kotlin conversion
This commit is contained in:
parent
8e6ab40d93
commit
b2c15ef186
316 changed files with 13055 additions and 22983 deletions
134
app/app.iml
134
app/app.iml
|
@ -35,10 +35,16 @@
|
|||
<option name="languageVersion" value="1.3" />
|
||||
<option name="apiVersion" value="1.3" />
|
||||
<option name="pluginOptions">
|
||||
<array />
|
||||
<array>
|
||||
<option value="plugin:org.jetbrains.kotlin.android:experimental=false" />
|
||||
<option value="plugin:org.jetbrains.kotlin.android:enabled=true" />
|
||||
<option value="plugin:org.jetbrains.kotlin.android:defaultCacheImplementation=hashMap" />
|
||||
</array>
|
||||
</option>
|
||||
<option name="pluginClasspaths">
|
||||
<array />
|
||||
<array>
|
||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.3.10/b714dd6deb5282a6545e4183d9270860a171f08e/kotlin-android-extensions-1.3.10.jar" />
|
||||
</array>
|
||||
</option>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
|
@ -50,7 +56,6 @@
|
|||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/normal/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/normalDebug/processNormalDebugResources/r" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/normal/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/normal/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/normal/debug" isTestSource="false" generated="true" />
|
||||
|
@ -64,7 +69,6 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/normalDebug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/normalDebug/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/normal/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/normalDebugAndroidTest/processNormalDebugAndroidTestResources/r" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/normal/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/normal/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/normal/debug" isTestSource="true" generated="true" />
|
||||
|
@ -148,10 +152,13 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/generated/source/r" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotation_processor_list" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-libraries" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkNormalDebugClasspath" />
|
||||
|
@ -166,7 +173,6 @@
|
|||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint_jar" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
|
||||
|
@ -189,87 +195,87 @@
|
|||
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:okhttp3-integration:1.5.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.slidingpanelayout:slidingpanelayout-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.material:material:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.3.10@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-2.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks-16.0.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.documentfile:documentfile:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-preference-v14:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.ksoichiro:android-observablescrollview:1.6.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.multidex:multidex:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.cardview:cardview:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.recyclerview:recyclerview:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:retrofit:2.4.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-flags-16.0.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.cardview:cardview-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.hannesa2:AndroidSlidingUpPanel-3.5.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.afollestad:material-cab-0.1.12" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-1.0.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.material:material-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement-16.0.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.h6ah4i.android.widget.advrecyclerview:advrecyclerview-0.11.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.fragment:fragment-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-cast:16.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: uk.co.chrisjenx:calligraphy:2.3.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.gridlayout:gridlayout:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.asynclayoutinflater:asynclayoutinflater:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.0.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife-annotations:9.0.0-rc1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel-2.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base-16.0.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.kabouzeid:RecyclerView-FastScroll-1.0.16-kmod" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.14.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.documentfile:documentfile-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.ksoichiro:android-observablescrollview-1.6.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.10@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-cast-16.1.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.recyclerview:recyclerview-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.slidingpanelayout:slidingpanelayout:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-flags:16.0.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.media:media:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.hannesa2:AndroidSlidingUpPanel:3.5.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:logging-interceptor:3.11.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.afollestad.material-dialogs:core-0.9.6.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-1.0.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.mediarouter:mediarouter:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:adapter-rxjava2:2.4.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.anjlab.android.iab.v3:library:1.0.44@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: uk.co.chrisjenx:calligraphy-2.3.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:converter-gson:2.4.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-v4-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife-runtime-9.0.0-rc1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.palette:palette-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.asynclayoutinflater:asynclayoutinflater-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.kabouzeid:RecyclerView-FastScroll:1.0.16-kmod@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-v13:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-v4:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.afollestad.material-dialogs:core:0.9.6.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife:9.0.0-rc1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-cast-framework:16.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: __local_aars__:/Users/hemanths/Desktop/KeepSafe/RetroMusicPlayer/app/libs/juniversalchardet-1.0.3.jar:unspecified@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: io.reactivex.rxjava2:rxjava:2.1.17@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.gridlayout:gridlayout-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.multidex:multidex-2.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime-2.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife-9.0.0-rc1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-ui:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: io.reactivex.rxjava2:rxandroid:2.0.2@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.11.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.media:media-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.r0adkll:slidableactivity-2.0.6" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core-2.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.core:core-1.0.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.0.2@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.r0adkll:slidableactivity:2.0.6@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.reactivestreams:reactive-streams:1.0.2@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: me.zhanghai.android.materialprogressbar:library-1.4.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.AdrienPoupa:jaudiotagger:2.2.3@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:glide:3.8.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.nanohttpd:nanohttpd:2.3.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.mediarouter:mediarouter-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.transition:transition-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.afollestad:material-cab:0.1.12@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.0.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.afollestad.material-dialogs:commons-0.9.6.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-preference-v14-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.print:print:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: me.zhanghai.android.materialprogressbar:library:1.4.2@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.10@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-v13-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.0.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-cast-framework-16.1.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: io.reactivex.rxjava2:rxandroid-2.0.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime-2.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.preference:preference-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.AdrienPoupa:jaudiotagger-2.2.3" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-ui-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base:16.0.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.transition:transition:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife-runtime:9.0.0-rc1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.0.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement:16.0.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.2@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.loader:loader-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.customview:customview-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.localbroadcastmanager:localbroadcastmanager-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.print:print-1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.palette:palette:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.preference:preference:1.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.core:core:1.0.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.0.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks:16.0.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.afollestad.material-dialogs:commons:0.9.6.0@aar" level="project" />
|
||||
<orderEntry type="module" module-name="appthemehelper" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,5 +1,6 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
@ -122,7 +123,7 @@ dependencies {
|
|||
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
|
||||
|
||||
implementation "com.jakewharton:butterknife:$butterKnife"
|
||||
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnife"
|
||||
kapt "com.jakewharton:butterknife-compiler:$butterKnife"
|
||||
|
||||
implementation "com.afollestad.material-dialogs:core:$materialDialog"
|
||||
implementation "com.afollestad.material-dialogs:commons:$materialDialog"
|
||||
|
|
|
@ -103,27 +103,19 @@
|
|||
<activity android:name=".ui.activities.tageditor.AlbumTagEditorActivity" />
|
||||
<activity android:name=".ui.activities.tageditor.SongTagEditorActivity" />
|
||||
<activity android:name=".ui.activities.SettingsActivity" />
|
||||
<activity android:name=".ui.activities.SearchActivity"
|
||||
android:windowSoftInputMode="stateVisible" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.activities.SearchActivity"
|
||||
android:windowSoftInputMode="stateVisible"></activity>
|
||||
<activity android:name=".ui.activities.LyricsActivity" />
|
||||
<activity android:name=".ui.activities.UserInfoActivity" />
|
||||
<activity
|
||||
android:name=".appshortcuts.AppShortcutLauncherActivity"
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
<activity
|
||||
android:name=".ui.activities.LockScreenActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="sensorPortrait"
|
||||
android:showOnLockScreen="true" />
|
||||
|
||||
<activity android:name=".ui.activities.SupportDevelopmentActivity" />
|
||||
<activity android:name=".ui.activities.GenreDetailsActivity" />
|
||||
<activity android:name=".ui.activities.LicenseActivity" />
|
||||
<activity android:name=".ui.activities.ProVersionActivity" />
|
||||
<activity android:name=".ui.activities.EqualizerActivity" />
|
||||
<activity android:name=".ui.activities.ErrorHandlerActivity" />
|
||||
<activity android:name=".ui.activities.WhatsNewActivity" />
|
||||
<activity
|
||||
android:name=".cast.ExpandedCastControlsActivity"
|
||||
android:label="@string/app_name"
|
||||
|
@ -163,66 +155,7 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
-->
|
||||
<receiver android:name=".appwidgets.BootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".appwidgets.AppWidgetBig"
|
||||
android:exported="false"
|
||||
android:label="@string/app_widget_big_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/app_widget_big_info" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".appwidgets.AppWidgetClassic"
|
||||
android:exported="false"
|
||||
android:label="@string/app_widget_classic_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/app_widget_classic_info" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".appwidgets.AppWidgetSmall"
|
||||
android:exported="false"
|
||||
android:label="@string/app_widget_small_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/app_widget_small_info" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".appwidgets.AppWidgetCard"
|
||||
android:exported="false"
|
||||
android:label="@string/app_widget_card_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/app_widget_card_info" />
|
||||
</receiver>
|
||||
<receiver android:name=".service.MediaButtonIntentReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- Widgets ends -->
|
||||
|
||||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
|
@ -256,9 +189,6 @@
|
|||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<activity android:name=".ui.activities.WhatsNewActivity"></activity>
|
||||
<activity android:name=".ui.activities.album.SmallAlbumDetailsActivity" />
|
||||
<activity android:name=".ui.activities.NowPayingActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1 +1 @@
|
|||
<html>
<head>
<style type="text/css">
* {
word-wrap: break-word;
}
{style-placeholder}
a {
color: #{link-color};
}
a:active {
color: #{link-color-active};
}
ul {
list-style-position: outside;
padding-left: 0;
padding-right: 0;
margin-left: 1em;
}
li {
padding-top: 8px;
}
</style>
</head>
<body>
<h1 style="text-align:center;">Are you subscribed to <a
href="https://www.youtube.com/user/PewDiePie">PewDiePie</a></h1>
<p style="line-height:150%">You can view the changelog dialog again at any time from the
<i>about</i> section.</p>
<h3>Version 2.2.100</h3>
<ul style="line-height:150%">
<li>Click new music mix to play songs</li>
<li>Gradient image option for gird list</li>
<li>Clear button for playing queue</li>
<li>Click toolbar (Library) to open options</li>
<li>Folder list back button</li>
<li>New theme Fit</li>
<li>On library click on toolbar for accessing main menu
</li>
<li>On home click on toolbar for accessing search
</li>
<li>BottomSheetDialogue is now adaptable to screens, background colour and text size
consistency.
</li>
<li>Removed coloured navigation bar option to making app adapt the primary colour</li>
<li>Swipe up gesture for now playing removed, replaced with "tap to open", To achieve
transparent navigation bar for desired themes.
</li>
<li>Improved tablet UI and home screen by adding suggestions toggle banner issues.</li>
<li>Improving lyrics page</li>
</ul>
<p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a>
</p>
<p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again. </p>
</body>
|
||||
<html>
<head>
<style type="text/css">
* {
word-wrap: break-word;
}
{style-placeholder}
a {
color: #{link-color};
}
a:active {
color: #{link-color-active};
}
ul {
list-style-position: outside;
padding-left: 0;
padding-right: 0;
margin-left: 1em;
}
li {
padding-top: 8px;
}
</style>
</head>
<body>
<h3>Version 2.2.100</h3>
<ul style="line-height:150%">
<li>Click new music mix to play songs</li>
<li>Gradient image option for gird list</li>
<li>Clear button for playing queue</li>
<li>Click toolbar (Library) to open options</li>
<li>Folder list back button</li>
<li>New theme Fit</li>
<li>On library click on toolbar for accessing main menu
</li>
<li>On home click on toolbar for accessing search
</li>
<li>BottomSheetDialogue is now adaptable to screens, background colour and text size
consistency.
</li>
<li>Removed coloured navigation bar option to making app adapt the primary colour</li>
<li>Swipe up gesture for now playing removed, replaced with "tap to open", To achieve
transparent navigation bar for desired themes.
</li>
<li>Improved tablet UI and home screen by adding suggestions toggle banner issues.</li>
<li>Improving lyrics page</li>
</ul>
<p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a>
</p>
<p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again. </p>
</body>
|
|
@ -1,42 +0,0 @@
|
|||
package code.name.monkey.retromusic;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String DISCORD_LINK = "https://discord.gg/qTecXXn";
|
||||
|
||||
public static final String RETRO_MUSIC_PACKAGE_NAME = "code.name.monkey.retromusic";
|
||||
public static final String MUSIC_PACKAGE_NAME = "com.android.music";
|
||||
public static final String ACTION_TOGGLE_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".togglepause";
|
||||
public static final String ACTION_PLAY = RETRO_MUSIC_PACKAGE_NAME + ".play";
|
||||
public static final String ACTION_PLAY_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + ".play.playlist";
|
||||
public static final String ACTION_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".pause";
|
||||
public static final String ACTION_STOP = RETRO_MUSIC_PACKAGE_NAME + ".stop";
|
||||
public static final String ACTION_SKIP = RETRO_MUSIC_PACKAGE_NAME + ".skip";
|
||||
public static final String ACTION_REWIND = RETRO_MUSIC_PACKAGE_NAME + ".rewind";
|
||||
public static final String ACTION_QUIT = RETRO_MUSIC_PACKAGE_NAME + ".quitservice";
|
||||
public static final String INTENT_EXTRA_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist";
|
||||
public static final String INTENT_EXTRA_SHUFFLE_MODE = RETRO_MUSIC_PACKAGE_NAME + ".intentextra.shufflemode";
|
||||
public static final String APP_WIDGET_UPDATE = RETRO_MUSIC_PACKAGE_NAME + ".appwidgetupdate";
|
||||
public static final String EXTRA_APP_WIDGET_NAME = RETRO_MUSIC_PACKAGE_NAME + "app_widget_name";
|
||||
// do not change these three strings as it will break support with other apps (e.g. last.fm scrobbling)
|
||||
public static final String META_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".metachanged";
|
||||
public static final String QUEUE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".queuechanged";
|
||||
public static final String PLAY_STATE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".playstatechanged";
|
||||
public static final String REPEAT_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".repeatmodechanged";
|
||||
public static final String SHUFFLE_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".shufflemodechanged";
|
||||
public static final String MEDIA_STORE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".mediastorechanged";
|
||||
public static final String RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic";
|
||||
public static final String PAYPAL_ME_URL = "https://www.paypal.me/h4h14";
|
||||
public static final String GOOGLE_PLUS_COMMUNITY = "https://plus.google.com/communities/110811566242871492162";
|
||||
public static final String TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534";
|
||||
public static final String GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicPlayer";
|
||||
public static final String BASE_API_URL_KUGOU = "http://lyrics.kugou.com/";
|
||||
public static final String TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog";
|
||||
public static final String USER_PROFILE = "profile.jpg";
|
||||
public static final String USER_BANNER = "banner.jpg";
|
||||
public static final String APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/";
|
||||
public static final String APP_TELEGRAM_LINK = "https://t.me/retromusicapp/";
|
||||
public static final String APP_TWITTER_LINK = "https://twitter.com/retromusicapp";
|
||||
public static final String FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md";
|
||||
public static final int CAST_SERVER_PORT = 8080;
|
||||
}
|
97
app/src/main/java/code/name/monkey/retromusic/Constants.kt
Normal file
97
app/src/main/java/code/name/monkey/retromusic/Constants.kt
Normal file
|
@ -0,0 +1,97 @@
|
|||
package code.name.monkey.retromusic
|
||||
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
|
||||
object Constants {
|
||||
|
||||
@JvmField
|
||||
val DISCORD_LINK = "https://discord.gg/qTecXXn"
|
||||
|
||||
@JvmField
|
||||
val RETRO_MUSIC_PACKAGE_NAME = "code.name.monkey.retromusic"
|
||||
@JvmField
|
||||
val MUSIC_PACKAGE_NAME = "com.android.music"
|
||||
@JvmField
|
||||
val ACTION_TOGGLE_PAUSE = "$RETRO_MUSIC_PACKAGE_NAME.togglepause"
|
||||
@JvmField
|
||||
val ACTION_PLAY = "$RETRO_MUSIC_PACKAGE_NAME.play"
|
||||
@JvmField
|
||||
val ACTION_PLAY_PLAYLIST = "$RETRO_MUSIC_PACKAGE_NAME.play.playlist"
|
||||
@JvmField
|
||||
val ACTION_PAUSE = "$RETRO_MUSIC_PACKAGE_NAME.pause"
|
||||
@JvmField
|
||||
val ACTION_STOP = "$RETRO_MUSIC_PACKAGE_NAME.stop"
|
||||
@JvmField
|
||||
val ACTION_SKIP = "$RETRO_MUSIC_PACKAGE_NAME.skip"
|
||||
@JvmField
|
||||
val ACTION_REWIND = "$RETRO_MUSIC_PACKAGE_NAME.rewind"
|
||||
@JvmField
|
||||
val ACTION_QUIT = "$RETRO_MUSIC_PACKAGE_NAME.quitservice"
|
||||
@JvmField
|
||||
val INTENT_EXTRA_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist"
|
||||
@JvmField
|
||||
val INTENT_EXTRA_SHUFFLE_MODE = "$RETRO_MUSIC_PACKAGE_NAME.intentextra.shufflemode"
|
||||
@JvmField
|
||||
val APP_WIDGET_UPDATE = "$RETRO_MUSIC_PACKAGE_NAME.appwidgetupdate"
|
||||
@JvmField
|
||||
val EXTRA_APP_WIDGET_NAME = RETRO_MUSIC_PACKAGE_NAME + "app_widget_name"
|
||||
|
||||
@JvmField
|
||||
val META_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.metachanged"
|
||||
@JvmField
|
||||
val QUEUE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.queuechanged"
|
||||
@JvmField
|
||||
val PLAY_STATE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.playstatechanged"
|
||||
@JvmField
|
||||
val REPEAT_MODE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.repeatmodechanged"
|
||||
@JvmField
|
||||
val SHUFFLE_MODE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.shufflemodechanged"
|
||||
@JvmField
|
||||
val MEDIA_STORE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.mediastorechanged"
|
||||
@JvmField
|
||||
val RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic"
|
||||
@JvmField
|
||||
val PAYPAL_ME_URL = "https://www.paypal.me/h4h14"
|
||||
@JvmField
|
||||
val GOOGLE_PLUS_COMMUNITY = "https://plus.google.com/communities/110811566242871492162"
|
||||
@JvmField
|
||||
val TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534"
|
||||
@JvmField
|
||||
val GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicPlayer"
|
||||
@JvmField
|
||||
val BASE_API_URL_KUGOU = "http://lyrics.kugou.com/"
|
||||
@JvmField
|
||||
val TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog"
|
||||
@JvmField
|
||||
val USER_PROFILE = "profile.jpg"
|
||||
@JvmField
|
||||
val USER_BANNER = "banner.jpg"
|
||||
@JvmField
|
||||
val APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/"
|
||||
@JvmField
|
||||
val APP_TELEGRAM_LINK = "https://t.me/retromusicapp/"
|
||||
@JvmField
|
||||
val APP_TWITTER_LINK = "https://twitter.com/retromusicapp"
|
||||
@JvmField
|
||||
val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
||||
@JvmField
|
||||
val CAST_SERVER_PORT = 8080
|
||||
|
||||
const val BASE_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
||||
@JvmField
|
||||
val BASE_PROJECTION = arrayOf(BaseColumns._ID, // 0
|
||||
MediaStore.Audio.AudioColumns.TITLE, // 1
|
||||
MediaStore.Audio.AudioColumns.TRACK, // 2
|
||||
MediaStore.Audio.AudioColumns.YEAR, // 3
|
||||
MediaStore.Audio.AudioColumns.DURATION, // 4
|
||||
MediaStore.Audio.AudioColumns.DATA, // 5
|
||||
MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
|
||||
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
|
||||
MediaStore.Audio.AudioColumns.ALBUM, // 8
|
||||
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
|
||||
MediaStore.Audio.AudioColumns.ARTIST)// 10
|
||||
const val NUMBER_OF_TOP_TRACKS = 99
|
||||
|
||||
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package code.name.monkey.retromusic;
|
||||
|
||||
import code.name.monkey.retromusic.providers.RepositoryImpl;
|
||||
import code.name.monkey.retromusic.providers.interfaces.Repository;
|
||||
import code.name.monkey.retromusic.rest.KogouClient;
|
||||
import code.name.monkey.retromusic.rest.service.KuGouApiService;
|
||||
import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider;
|
||||
import code.name.monkey.retromusic.util.schedulers.SchedulerProvider;
|
||||
|
||||
public class Injection {
|
||||
|
||||
public static Repository provideRepository() {
|
||||
return RepositoryImpl.getInstance();
|
||||
}
|
||||
|
||||
public static BaseSchedulerProvider provideSchedulerProvider() {
|
||||
return SchedulerProvider.getInstance();
|
||||
}
|
||||
|
||||
public static KuGouApiService provideKuGouApiService() {
|
||||
return new KogouClient().getApiService();
|
||||
}
|
||||
}
|
23
app/src/main/java/code/name/monkey/retromusic/Injection.kt
Normal file
23
app/src/main/java/code/name/monkey/retromusic/Injection.kt
Normal file
|
@ -0,0 +1,23 @@
|
|||
package code.name.monkey.retromusic
|
||||
|
||||
import code.name.monkey.retromusic.providers.RepositoryImpl
|
||||
import code.name.monkey.retromusic.providers.interfaces.Repository
|
||||
import code.name.monkey.retromusic.rest.KogouClient
|
||||
import code.name.monkey.retromusic.rest.service.KuGouApiService
|
||||
import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider
|
||||
import code.name.monkey.retromusic.util.schedulers.SchedulerProvider
|
||||
|
||||
object Injection {
|
||||
|
||||
fun provideRepository(): Repository {
|
||||
return RepositoryImpl.getInstance()
|
||||
}
|
||||
|
||||
fun provideSchedulerProvider(): BaseSchedulerProvider {
|
||||
return SchedulerProvider.getInstance()
|
||||
}
|
||||
|
||||
fun provideKuGouApiService(): KuGouApiService {
|
||||
return KogouClient().apiService
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
package code.name.monkey.retromusic;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.anjlab.android.iab.v3.BillingProcessor;
|
||||
import com.anjlab.android.iab.v3.TransactionDetails;
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
import code.name.monkey.appthemehelper.ThemeStore;
|
||||
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager;
|
||||
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
|
||||
|
||||
public class RetroApplication extends MultiDexApplication {
|
||||
|
||||
public static final String PRO_VERSION_PRODUCT_ID = "pro_version";
|
||||
|
||||
private static RetroApplication app;
|
||||
|
||||
private BillingProcessor billingProcessor;
|
||||
|
||||
public static RetroApplication getInstance() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return app.getApplicationContext();
|
||||
}
|
||||
|
||||
public static boolean isProVersion() {
|
||||
return BuildConfig.DEBUG || app.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID);
|
||||
}
|
||||
|
||||
public static void deleteAppData() {
|
||||
try {
|
||||
// clearing app data
|
||||
String packageName = app.getPackageName();
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
runtime.exec("pm clear " + packageName);
|
||||
|
||||
System.exit(0);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
app = this;
|
||||
|
||||
setupErrorHandler();
|
||||
|
||||
// default theme
|
||||
if (!ThemeStore.isConfigured(this, 3)) {
|
||||
ThemeStore.editTheme(this)
|
||||
.accentColorRes(R.color.md_green_A200)
|
||||
.coloredNavigationBar(true)
|
||||
.commit();
|
||||
}
|
||||
|
||||
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
|
||||
.setDefaultFontPath("fonts/circular_std_book.otf")
|
||||
.setFontAttrId(R.attr.fontPath)
|
||||
.build()
|
||||
);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
new DynamicShortcutManager(this).initDynamicShortcuts();
|
||||
}
|
||||
|
||||
// automatically restores purchases
|
||||
billingProcessor = new BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY,
|
||||
new BillingProcessor.IBillingHandler() {
|
||||
@Override
|
||||
public void onProductPurchased(@NonNull String productId, TransactionDetails details) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPurchaseHistoryRestored() {
|
||||
//Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingError(int errorCode, Throwable error) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingInitialized() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupErrorHandler() {
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable throwable) {
|
||||
handleUncaughtException(thread, throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleUncaughtException(Thread thread, Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
deleteAppData();
|
||||
//Intent intent = new Intent(this, ErrorHandlerActivity.class);
|
||||
//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
//startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
Glide.with(this).onLowMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
super.onTerminate();
|
||||
billingProcessor.release();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package code.name.monkey.retromusic
|
||||
|
||||
import android.content.Context
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import com.anjlab.android.iab.v3.BillingProcessor
|
||||
import com.anjlab.android.iab.v3.TransactionDetails
|
||||
import com.bumptech.glide.Glide
|
||||
import uk.co.chrisjenx.calligraphy.CalligraphyConfig
|
||||
|
||||
class RetroApplication : MultiDexApplication() {
|
||||
|
||||
lateinit var billingProcessor: BillingProcessor
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
|
||||
setupErrorHandler()
|
||||
|
||||
// default theme
|
||||
if (!ThemeStore.isConfigured(this, 3)) {
|
||||
ThemeStore.editTheme(this)
|
||||
.accentColorRes(R.color.md_green_A200)
|
||||
.coloredNavigationBar(true)
|
||||
.commit()
|
||||
}
|
||||
|
||||
// automatically restores purchases
|
||||
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY,
|
||||
object : BillingProcessor.IBillingHandler {
|
||||
override fun onProductPurchased(productId: String, details: TransactionDetails?) {}
|
||||
|
||||
override fun onPurchaseHistoryRestored() {
|
||||
//Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
override fun onBillingError(errorCode: Int, error: Throwable?) {}
|
||||
|
||||
override fun onBillingInitialized() {}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupErrorHandler() {
|
||||
Thread.setDefaultUncaughtExceptionHandler { _, throwable -> handleUncaughtException(throwable) }
|
||||
}
|
||||
|
||||
private fun handleUncaughtException(throwable: Throwable) {
|
||||
throwable.printStackTrace()
|
||||
deleteAppData()
|
||||
//Intent intent = new Intent(this, ErrorHandlerActivity.class);
|
||||
//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
//startActivity(intent);
|
||||
}
|
||||
|
||||
override fun onLowMemory() {
|
||||
super.onLowMemory()
|
||||
Glide.with(this).onLowMemory()
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
super.onTerminate()
|
||||
billingProcessor.release()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val PRO_VERSION_PRODUCT_ID = "pro_version"
|
||||
|
||||
lateinit var instance: RetroApplication
|
||||
private set
|
||||
|
||||
val context: Context
|
||||
get() = instance.applicationContext
|
||||
|
||||
val isProVersion: Boolean
|
||||
get() = BuildConfig.DEBUG || instance.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID)
|
||||
|
||||
fun deleteAppData() {
|
||||
try {
|
||||
// clearing app data
|
||||
val packageName = instance.packageName
|
||||
val runtime = Runtime.getRuntime()
|
||||
runtime.exec("pm clear $packageName")
|
||||
|
||||
System.exit(0)
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import code.name.monkey.appthemehelper.ThemeStore;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class AppShortcutIconGenerator {
|
||||
public static Icon generateThemedIcon(Context context, int iconId) {
|
||||
if (PreferenceUtil.getInstance().coloredAppShortcuts()){
|
||||
return generateUserThemedIcon(context, iconId);
|
||||
} else {
|
||||
return generateDefaultThemedIcon(context, iconId);
|
||||
}
|
||||
}
|
||||
|
||||
private static Icon generateDefaultThemedIcon(Context context, int iconId) {
|
||||
// Return an Icon of iconId with default colors
|
||||
return generateThemedIcon(context, iconId,
|
||||
context.getColor(R.color.app_shortcut_default_foreground),
|
||||
context.getColor(R.color.app_shortcut_default_background)
|
||||
);
|
||||
}
|
||||
|
||||
private static Icon generateUserThemedIcon(Context context, int iconId) {
|
||||
// Get background color from context's theme
|
||||
final TypedValue typedColorBackground = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true);
|
||||
|
||||
// Return an Icon of iconId with those colors
|
||||
return generateThemedIcon(context, iconId,
|
||||
ThemeStore.accentColor(context),
|
||||
typedColorBackground.data
|
||||
);
|
||||
}
|
||||
|
||||
private static Icon generateThemedIcon(Context context, int iconId, int foregroundColor, int backgroundColor) {
|
||||
// Get and tint foreground and background drawables
|
||||
Drawable vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor);
|
||||
Drawable backgroundDrawable = RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor);
|
||||
|
||||
// Squash the two drawables together
|
||||
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, vectorDrawable});
|
||||
|
||||
// Return as an Icon
|
||||
return Icon.createWithBitmap(drawableToBitmap(layerDrawable));
|
||||
}
|
||||
|
||||
private static Bitmap drawableToBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist;
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.*;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
|
||||
public class AppShortcutLauncherActivity extends Activity {
|
||||
public static final String KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType";
|
||||
|
||||
public static final int SHORTCUT_TYPE_SHUFFLE_ALL = 0;
|
||||
public static final int SHORTCUT_TYPE_TOP_TRACKS = 1;
|
||||
public static final int SHORTCUT_TYPE_LAST_ADDED = 2;
|
||||
public static final int SHORTCUT_TYPE_NONE = 3;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
int shortcutType = SHORTCUT_TYPE_NONE;
|
||||
|
||||
// Set shortcutType from the intent extras
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
//noinspection WrongConstant
|
||||
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE);
|
||||
}
|
||||
|
||||
switch (shortcutType) {
|
||||
case SHORTCUT_TYPE_SHUFFLE_ALL:
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_SHUFFLE,
|
||||
new ShuffleAllPlaylist(getApplicationContext()));
|
||||
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.getId());
|
||||
break;
|
||||
case SHORTCUT_TYPE_TOP_TRACKS:
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
||||
new MyTopTracksPlaylist(getApplicationContext()));
|
||||
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.getId());
|
||||
break;
|
||||
case SHORTCUT_TYPE_LAST_ADDED:
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
||||
new LastAddedPlaylist(getApplicationContext()));
|
||||
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.getId());
|
||||
break;
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
private void startServiceWithPlaylist(int shuffleMode, Playlist playlist) {
|
||||
Intent intent = new Intent(this, MusicService.class);
|
||||
intent.setAction(ACTION_PLAY_PLAYLIST);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist);
|
||||
bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode);
|
||||
|
||||
intent.putExtras(bundle);
|
||||
|
||||
startService(intent);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public class DynamicShortcutManager {
|
||||
|
||||
private Context context;
|
||||
private ShortcutManager shortcutManager;
|
||||
|
||||
public DynamicShortcutManager(Context context) {
|
||||
this.context = context;
|
||||
shortcutManager = this.context.getSystemService(ShortcutManager.class);
|
||||
}
|
||||
|
||||
public static ShortcutInfo createShortcut(Context context, String id, String shortLabel, String longLabel, Icon icon, Intent intent) {
|
||||
return new ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(shortLabel)
|
||||
.setLongLabel(longLabel)
|
||||
.setIcon(icon)
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void initDynamicShortcuts() {
|
||||
if (shortcutManager.getDynamicShortcuts().size() == 0) {
|
||||
shortcutManager.setDynamicShortcuts(getDefaultShortcuts());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDynamicShortcuts() {
|
||||
shortcutManager.updateShortcuts(getDefaultShortcuts());
|
||||
}
|
||||
|
||||
public List<ShortcutInfo> getDefaultShortcuts() {
|
||||
return (Arrays.asList(
|
||||
new ShuffleAllShortcutType(context).getShortcutInfo(),
|
||||
new TopTracksShortcutType(context).getShortcutInfo(),
|
||||
new LastAddedShortcutType(context).getShortcutInfo()
|
||||
));
|
||||
}
|
||||
|
||||
public static void reportShortcutUsed(Context context, String shortcutId){
|
||||
context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public abstract class BaseShortcutType {
|
||||
|
||||
static final String ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id.";
|
||||
|
||||
Context context;
|
||||
|
||||
public BaseShortcutType(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
static public String getId() {
|
||||
return ID_PREFIX + "invalid";
|
||||
}
|
||||
|
||||
abstract ShortcutInfo getShortcutInfo();
|
||||
|
||||
/**
|
||||
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
|
||||
*
|
||||
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
|
||||
* @return
|
||||
*/
|
||||
Intent getPlaySongsIntent(int shortcutType) {
|
||||
Intent intent = new Intent(context, AppShortcutLauncherActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
|
||||
Bundle b = new Bundle();
|
||||
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType);
|
||||
|
||||
intent.putExtras(b);
|
||||
|
||||
return intent;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class LastAddedShortcutType extends BaseShortcutType {
|
||||
public LastAddedShortcutType(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return ID_PREFIX + "last_added";
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return new ShortcutInfo.Builder(context, getId())
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_last_added_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_last_added_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class ShuffleAllShortcutType extends BaseShortcutType {
|
||||
public ShuffleAllShortcutType(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return ID_PREFIX + "shuffle_all";
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return new ShortcutInfo.Builder(context, getId())
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class TopTracksShortcutType extends BaseShortcutType {
|
||||
public TopTracksShortcutType(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return ID_PREFIX + "top_tracks";
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return new ShortcutInfo.Builder(context, getId())
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
package code.name.monkey.retromusic.appwidgets;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
|
||||
public class AppWidgetBig extends BaseAppWidget {
|
||||
|
||||
public static final String NAME = "app_widget_big";
|
||||
|
||||
private static AppWidgetBig mInstance;
|
||||
private Target<Bitmap> target; // for cancellation
|
||||
|
||||
public static synchronized AppWidgetBig getInstance() {
|
||||
if (mInstance == null) {
|
||||
mInstance = new AppWidgetBig();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
||||
* actions if service not running.
|
||||
*/
|
||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
||||
R.layout.app_widget_big);
|
||||
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
||||
MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
||||
MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
||||
MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
|
||||
|
||||
linkButtons(context, appWidgetView);
|
||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all active widget instances by pushing changes
|
||||
*/
|
||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
||||
R.layout.app_widget_big);
|
||||
|
||||
final boolean isPlaying = service.isPlaying();
|
||||
final Song song = service.getCurrentSong();
|
||||
|
||||
// Set the titles and artwork
|
||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
} else {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
||||
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song));
|
||||
}
|
||||
|
||||
// Set correct drawable for pause state
|
||||
int playPauseRes =
|
||||
isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, playPauseRes,
|
||||
MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
|
||||
|
||||
// Set prev/next button drawables
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
||||
MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
||||
MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
|
||||
|
||||
// Link actions buttons to intents
|
||||
linkButtons(service, appWidgetView);
|
||||
|
||||
// Load the album cover async and push the update on completion
|
||||
Point p = RetroUtil.getScreenSize(service);
|
||||
final int widgetImageSize = Math.min(p.x, p.y);
|
||||
final Context appContext = service.getApplicationContext();
|
||||
service.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (target != null) {
|
||||
Glide.clear(target);
|
||||
}
|
||||
target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
|
||||
.checkIgnoreMediaStore(appContext)
|
||||
.asBitmap().build()
|
||||
.into(new SimpleTarget<Bitmap>(widgetImageSize, widgetImageSize) {
|
||||
@Override
|
||||
public void onResourceReady(Bitmap resource,
|
||||
GlideAnimation<? super Bitmap> glideAnimation) {
|
||||
update(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
super.onLoadFailed(e, errorDrawable);
|
||||
update(null);
|
||||
}
|
||||
|
||||
private void update(@Nullable Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
||||
} else {
|
||||
appWidgetView.setImageViewBitmap(R.id.image, bitmap);
|
||||
}
|
||||
pushUpdate(appContext, appWidgetIds, appWidgetView);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Link up various button actions using {@link PendingIntent}.
|
||||
*/
|
||||
private void linkButtons(final Context context, final RemoteViews views) {
|
||||
Intent action;
|
||||
PendingIntent pendingIntent;
|
||||
|
||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
||||
|
||||
// Home
|
||||
action = new Intent(context, NowPayingActivity.class);
|
||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
||||
views.setOnClickPendingIntent(R.id.clickable_area, pendingIntent);
|
||||
|
||||
// Previous track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
||||
|
||||
// Play and pause
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
||||
|
||||
// Next track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
package code.name.monkey.retromusic.appwidgets;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.palette.graphics.Palette;
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
|
||||
public class AppWidgetCard extends BaseAppWidget {
|
||||
|
||||
public static final String NAME = "app_widget_card";
|
||||
|
||||
private static AppWidgetCard mInstance;
|
||||
private static int imageSize = 0;
|
||||
private static float cardRadius = 0f;
|
||||
private Target<BitmapPaletteWrapper> target; // for cancellation
|
||||
|
||||
public static synchronized AppWidgetCard getInstance() {
|
||||
if (mInstance == null) {
|
||||
mInstance = new AppWidgetCard();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
||||
* actions if service not running.
|
||||
*/
|
||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
||||
R.layout.app_widget_card);
|
||||
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
|
||||
linkButtons(context, appWidgetView);
|
||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all active widget instances by pushing changes
|
||||
*/
|
||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
||||
R.layout.app_widget_card);
|
||||
|
||||
final boolean isPlaying = service.isPlaying();
|
||||
final Song song = service.getCurrentSong();
|
||||
|
||||
// Set the titles and artwork
|
||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
} else {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
||||
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song));
|
||||
}
|
||||
|
||||
// Set correct drawable for pause state
|
||||
int playPauseRes =
|
||||
isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, playPauseRes,
|
||||
MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
|
||||
|
||||
// Set prev/next button drawables
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
|
||||
|
||||
// Link actions buttons to intents
|
||||
linkButtons(service, appWidgetView);
|
||||
|
||||
if (imageSize == 0) {
|
||||
imageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_card_image_size);
|
||||
}
|
||||
if (cardRadius == 0f) {
|
||||
cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius);
|
||||
}
|
||||
|
||||
// Load the album cover async and push the update on completion
|
||||
service.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (target != null) {
|
||||
Glide.clear(target);
|
||||
}
|
||||
target = SongGlideRequest.Builder.from(Glide.with(service), song)
|
||||
.checkIgnoreMediaStore(service)
|
||||
.generatePalette(service).build()
|
||||
.centerCrop()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
Palette palette = resource.getPalette();
|
||||
update(resource.getBitmap(), palette.getVibrantColor(palette
|
||||
.getMutedColor(MaterialValueHelper.getSecondaryTextColor(service, true))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
super.onLoadFailed(e, errorDrawable);
|
||||
update(null, MaterialValueHelper.getSecondaryTextColor(service, true));
|
||||
}
|
||||
|
||||
private void update(@Nullable Bitmap bitmap, int color) {
|
||||
// Set correct drawable for pause state
|
||||
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp
|
||||
: R.drawable.ic_play_arrow_white_24dp;
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause,
|
||||
createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f));
|
||||
|
||||
// Set prev/next button drawables
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
||||
color), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
||||
color), 1f));
|
||||
|
||||
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
|
||||
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize,
|
||||
cardRadius, 0, cardRadius, 0);
|
||||
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap);
|
||||
|
||||
pushUpdate(service, appWidgetIds, appWidgetView);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Link up various button actions using {@link PendingIntent}.
|
||||
*/
|
||||
private void linkButtons(final Context context, final RemoteViews views) {
|
||||
Intent action;
|
||||
PendingIntent pendingIntent;
|
||||
|
||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
||||
|
||||
// Home
|
||||
action = new Intent(context, NowPayingActivity.class);
|
||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
||||
views.setOnClickPendingIntent(R.id.image, pendingIntent);
|
||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent);
|
||||
|
||||
// Previous track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
||||
|
||||
// Play and pause
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
||||
|
||||
// Next track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
package code.name.monkey.retromusic.appwidgets;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.palette.graphics.Palette;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
public class AppWidgetClassic extends BaseAppWidget {
|
||||
|
||||
public static final String NAME = "app_widget_classic";
|
||||
|
||||
private static AppWidgetClassic mInstance;
|
||||
private static int imageSize = 0;
|
||||
private static float cardRadius = 0f;
|
||||
private Target<BitmapPaletteWrapper> target; // for cancellation
|
||||
|
||||
public static synchronized AppWidgetClassic getInstance() {
|
||||
if (mInstance == null) {
|
||||
mInstance = new AppWidgetClassic();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
||||
* actions if service not running.
|
||||
*/
|
||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
||||
R.layout.app_widget_classic);
|
||||
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
|
||||
linkButtons(context, appWidgetView);
|
||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all active widget instances by pushing changes
|
||||
*/
|
||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
||||
R.layout.app_widget_classic);
|
||||
|
||||
final boolean isPlaying = service.isPlaying();
|
||||
final Song song = service.getCurrentSong();
|
||||
|
||||
// Set the titles and artwork
|
||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
} else {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
||||
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song));
|
||||
}
|
||||
|
||||
// Link actions buttons to intents
|
||||
linkButtons(service, appWidgetView);
|
||||
|
||||
if (imageSize == 0) {
|
||||
imageSize = service.getResources()
|
||||
.getDimensionPixelSize(R.dimen.app_widget_classic_image_size);
|
||||
}
|
||||
if (cardRadius == 0f) {
|
||||
cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius);
|
||||
}
|
||||
|
||||
// Load the album cover async and push the update on completion
|
||||
final Context appContext = service.getApplicationContext();
|
||||
service.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (target != null) {
|
||||
Glide.clear(target);
|
||||
}
|
||||
target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
|
||||
.checkIgnoreMediaStore(appContext)
|
||||
.generatePalette(service).build()
|
||||
.centerCrop()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
Palette palette = resource.getPalette();
|
||||
update(resource.getBitmap(), palette.getVibrantColor(palette
|
||||
.getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
super.onLoadFailed(e, errorDrawable);
|
||||
update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true));
|
||||
}
|
||||
|
||||
private void update(@Nullable Bitmap bitmap, int color) {
|
||||
// Set correct drawable for pause state
|
||||
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp
|
||||
: R.drawable.ic_play_arrow_white_24dp;
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause,
|
||||
createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f));
|
||||
|
||||
// Set prev/next button drawables
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
||||
color), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
||||
color), 1f));
|
||||
|
||||
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
|
||||
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize,
|
||||
cardRadius, 0, cardRadius, 0);
|
||||
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap);
|
||||
|
||||
pushUpdate(appContext, appWidgetIds, appWidgetView);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Link up various button actions using {@link PendingIntent}.
|
||||
*/
|
||||
private void linkButtons(final Context context, final RemoteViews views) {
|
||||
Intent action;
|
||||
PendingIntent pendingIntent;
|
||||
|
||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
||||
|
||||
// Home
|
||||
action = new Intent(context, NowPayingActivity.class);
|
||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
||||
views.setOnClickPendingIntent(R.id.image, pendingIntent);
|
||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent);
|
||||
|
||||
// Previous track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
||||
|
||||
// Play and pause
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
||||
|
||||
// Next track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
||||
}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
package code.name.monkey.retromusic.appwidgets;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.palette.graphics.Palette;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
public class AppWidgetSmall extends BaseAppWidget {
|
||||
|
||||
public static final String NAME = "app_widget_small";
|
||||
|
||||
private static AppWidgetSmall mInstance;
|
||||
private static int imageSize = 0;
|
||||
private static float cardRadius = 0f;
|
||||
private Target<BitmapPaletteWrapper> target; // for cancellation
|
||||
|
||||
public static synchronized AppWidgetSmall getInstance() {
|
||||
if (mInstance == null) {
|
||||
mInstance = new AppWidgetSmall();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
||||
* actions if service not running.
|
||||
*/
|
||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
||||
R.layout.app_widget_small);
|
||||
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
||||
|
||||
linkButtons(context, appWidgetView);
|
||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all active widget instances by pushing changes
|
||||
*/
|
||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
||||
R.layout.app_widget_small);
|
||||
|
||||
final boolean isPlaying = service.isPlaying();
|
||||
final Song song = service.getCurrentSong();
|
||||
|
||||
// Set the titles and artwork
|
||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
||||
} else {
|
||||
if (TextUtils.isEmpty(song.title) || TextUtils.isEmpty(song.artistName)) {
|
||||
appWidgetView.setTextViewText(R.id.text_separator, "");
|
||||
} else {
|
||||
appWidgetView.setTextViewText(R.id.text_separator, "•");
|
||||
}
|
||||
|
||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
||||
appWidgetView.setTextViewText(R.id.text, song.artistName);
|
||||
}
|
||||
|
||||
// Link actions buttons to intents
|
||||
linkButtons(service, appWidgetView);
|
||||
|
||||
if (imageSize == 0) {
|
||||
imageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_small_image_size);
|
||||
}
|
||||
if (cardRadius == 0f) {
|
||||
cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius);
|
||||
}
|
||||
|
||||
// Load the album cover async and push the update on completion
|
||||
final Context appContext = service.getApplicationContext();
|
||||
service.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (target != null) {
|
||||
Glide.clear(target);
|
||||
}
|
||||
target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
|
||||
.checkIgnoreMediaStore(appContext)
|
||||
.generatePalette(service).build()
|
||||
.centerCrop()
|
||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
Palette palette = resource.getPalette();
|
||||
update(resource.getBitmap(), palette.getVibrantColor(palette
|
||||
.getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
super.onLoadFailed(e, errorDrawable);
|
||||
update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true));
|
||||
}
|
||||
|
||||
private void update(@Nullable Bitmap bitmap, int color) {
|
||||
// Set correct drawable for pause state
|
||||
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp
|
||||
: R.drawable.ic_play_arrow_white_24dp;
|
||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause,
|
||||
createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f));
|
||||
|
||||
// Set prev/next button drawables
|
||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
||||
color), 1f));
|
||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
||||
color), 1f));
|
||||
|
||||
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
|
||||
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize,
|
||||
cardRadius, 0, 0, 0);
|
||||
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap);
|
||||
|
||||
pushUpdate(appContext, appWidgetIds, appWidgetView);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Link up various button actions using {@link PendingIntent}.
|
||||
*/
|
||||
private void linkButtons(final Context context, final RemoteViews views) {
|
||||
Intent action;
|
||||
PendingIntent pendingIntent;
|
||||
|
||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
||||
|
||||
// Home
|
||||
action = new Intent(context, NowPayingActivity.class);
|
||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
||||
views.setOnClickPendingIntent(R.id.image, pendingIntent);
|
||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent);
|
||||
|
||||
// Previous track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
||||
|
||||
// Play and pause
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
||||
|
||||
// Next track
|
||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package code.name.monkey.retromusic.appwidgets;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
|
||||
|
||||
/**
|
||||
* @author Eugene Cheung (arkon)
|
||||
*/
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
|
||||
|
||||
// Start music service if there are any existing widgets
|
||||
if (widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetBig.class)).length > 0 ||
|
||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetClassic.class)).length > 0 ||
|
||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetSmall.class)).length > 0 ||
|
||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetCard.class)).length > 0) {
|
||||
final Intent serviceIntent = new Intent(context, MusicService.class);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // not allowed on Oreo
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
package code.name.monkey.retromusic.appwidgets.base;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
|
||||
public abstract class BaseAppWidget extends AppWidgetProvider {
|
||||
|
||||
public static final String NAME = "app_widget";
|
||||
|
||||
protected static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) {
|
||||
Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier),
|
||||
(int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||
drawable.draw(c);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
protected static Bitmap createRoundedBitmap(Drawable drawable, int width, int height, float tl,
|
||||
float tr, float bl, float br) {
|
||||
if (drawable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, width, height);
|
||||
drawable.draw(c);
|
||||
|
||||
Bitmap rounded = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
|
||||
Canvas canvas = new Canvas(rounded);
|
||||
Paint paint = new Paint();
|
||||
paint.setShader(
|
||||
new BitmapShader(bitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
|
||||
paint.setAntiAlias(true);
|
||||
canvas.drawPath(composeRoundedRectPath(new RectF(0, 0, width, height), tl, tr, bl, br), paint);
|
||||
|
||||
return rounded;
|
||||
}
|
||||
|
||||
protected static Path composeRoundedRectPath(RectF rect, float tl, float tr, float bl, float br) {
|
||||
Path path = new Path();
|
||||
tl = tl < 0 ? 0 : tl;
|
||||
tr = tr < 0 ? 0 : tr;
|
||||
bl = bl < 0 ? 0 : bl;
|
||||
br = br < 0 ? 0 : br;
|
||||
|
||||
path.moveTo(rect.left + tl, rect.top);
|
||||
path.lineTo(rect.right - tr, rect.top);
|
||||
path.quadTo(rect.right, rect.top, rect.right, rect.top + tr);
|
||||
path.lineTo(rect.right, rect.bottom - br);
|
||||
path.quadTo(rect.right, rect.bottom, rect.right - br, rect.bottom);
|
||||
path.lineTo(rect.left + bl, rect.bottom);
|
||||
path.quadTo(rect.left, rect.bottom, rect.left, rect.bottom - bl);
|
||||
path.lineTo(rect.left, rect.top + tl);
|
||||
path.quadTo(rect.left, rect.top, rect.left + tl, rect.top);
|
||||
path.close();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager,
|
||||
final int[] appWidgetIds) {
|
||||
defaultAppWidget(context, appWidgetIds);
|
||||
final Intent updateIntent = new Intent(Constants.APP_WIDGET_UPDATE);
|
||||
updateIntent.putExtra(Constants.EXTRA_APP_WIDGET_NAME, NAME);
|
||||
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
|
||||
updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
context.sendBroadcast(updateIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a change notification coming over from {@link MusicService}
|
||||
*/
|
||||
public void notifyChange(final MusicService service, final String what) {
|
||||
if (hasInstances(service)) {
|
||||
if (Constants.META_CHANGED.equals(what) || Constants.PLAY_STATE_CHANGED.equals(what)) {
|
||||
performUpdate(service, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void pushUpdate(final Context context, final int[] appWidgetIds,
|
||||
final RemoteViews views) {
|
||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
if (appWidgetIds != null) {
|
||||
appWidgetManager.updateAppWidget(appWidgetIds, views);
|
||||
} else {
|
||||
appWidgetManager.updateAppWidget(new ComponentName(context, getClass()), views);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check against {@link AppWidgetManager} if there are any instances of this widget.
|
||||
*/
|
||||
protected boolean hasInstances(final Context context) {
|
||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
final int[] mAppWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context,
|
||||
getClass()));
|
||||
return mAppWidgetIds.length > 0;
|
||||
}
|
||||
|
||||
protected PendingIntent buildPendingIntent(Context context, final String action,
|
||||
final ComponentName serviceName) {
|
||||
Intent intent = new Intent(action);
|
||||
intent.setComponent(serviceName);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
return PendingIntent.getForegroundService(context, 0, intent, 0);
|
||||
} else {
|
||||
return PendingIntent.getService(context, 0, intent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected void defaultAppWidget(final Context context, final int[] appWidgetIds);
|
||||
|
||||
abstract public void performUpdate(final MusicService service, final int[] appWidgetIds);
|
||||
|
||||
protected Drawable getAlbumArtDrawable(final Resources resources, final Bitmap bitmap) {
|
||||
Drawable image;
|
||||
if (bitmap == null) {
|
||||
image = resources.getDrawable(R.drawable.default_album_art);
|
||||
} else {
|
||||
image = new BitmapDrawable(resources, bitmap);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
protected String getSongArtistAndAlbum(final Song song) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(song.artistName);
|
||||
if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) {
|
||||
builder.append(" • ");
|
||||
}
|
||||
builder.append(song.albumName);
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
|
@ -16,6 +16,8 @@ import code.name.monkey.retromusic.Constants;
|
|||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.CAST_SERVER_PORT;
|
||||
|
||||
public class CastHelper {
|
||||
|
||||
public static void startCasting(CastSession castSession, Song song) {
|
||||
|
@ -23,22 +25,22 @@ public class CastHelper {
|
|||
String ipAddress = RetroUtil.getIPAddress(true);
|
||||
URL baseUrl;
|
||||
try {
|
||||
baseUrl = new URL("https", ipAddress, Constants.CAST_SERVER_PORT, "");
|
||||
baseUrl = new URL("https", ipAddress,CAST_SERVER_PORT, "");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
String songUrl = baseUrl.toString() + "/song?id=" + song.id;
|
||||
String albumArtUrl = baseUrl.toString() + "/albumart?id=" + song.albumId;
|
||||
String songUrl = baseUrl.toString() + "/song?id=" + song.getId();
|
||||
String albumArtUrl = baseUrl.toString() + "/albumart?id=" + song.getAlbumId();
|
||||
|
||||
|
||||
MediaMetadata musicMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
|
||||
|
||||
musicMetadata.putString(MediaMetadata.KEY_TITLE, song.title);
|
||||
musicMetadata.putString(MediaMetadata.KEY_ARTIST, song.artistName);
|
||||
musicMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, song.albumName);
|
||||
musicMetadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.trackNumber);
|
||||
musicMetadata.putString(MediaMetadata.KEY_TITLE, song.getTitle());
|
||||
musicMetadata.putString(MediaMetadata.KEY_ARTIST, song.getArtistName());
|
||||
musicMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, song.getAlbumName());
|
||||
musicMetadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.getTrackNumber());
|
||||
musicMetadata.addImage(new WebImage(Uri.parse(albumArtUrl)));
|
||||
|
||||
try {
|
||||
|
@ -46,7 +48,7 @@ public class CastHelper {
|
|||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setContentType("audio/mpeg")
|
||||
.setMetadata(musicMetadata)
|
||||
.setStreamDuration(song.duration)
|
||||
.setStreamDuration(song.getDuration())
|
||||
.build();
|
||||
RemoteMediaClient remoteMediaClient = castSession.getRemoteMediaClient();
|
||||
remoteMediaClient.load(mediaInfo, new MediaLoadOptions.Builder()
|
||||
|
|
|
@ -13,13 +13,15 @@ import code.name.monkey.retromusic.Constants;
|
|||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.CAST_SERVER_PORT;
|
||||
|
||||
public class WebServer extends NanoHTTPD {
|
||||
|
||||
private Context context;
|
||||
private Uri songUri, albumArtUri;
|
||||
|
||||
public WebServer(Context context) {
|
||||
super(Constants.CAST_SERVER_PORT);
|
||||
super(CAST_SERVER_PORT);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ public class AddToPlaylistDialog extends RoundedBottomSheetDialogFragment {
|
|||
super.onViewCreated(view, savedInstanceState);
|
||||
title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
||||
final ArrayList<Song> songs = getArguments().getParcelableArrayList("songs");
|
||||
final ArrayList<Playlist> playlists = PlaylistLoader.getAllPlaylists(getActivity()).blockingFirst();
|
||||
final ArrayList<Playlist> playlists = PlaylistLoader.INSTANCE.getAllPlaylists(getActivity()).blockingFirst();
|
||||
final AddToPlaylist playlistAdapter = new AddToPlaylist(getActivity(), playlists, R.layout.item_playlist, songs, getDialog());
|
||||
playlist.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
playlist.setItemAnimator(new DefaultItemAnimator());
|
||||
|
|
|
@ -82,7 +82,7 @@ public class DeleteSongsDialog extends RoundedBottomSheetDialogFragment {
|
|||
if (songs.size() > 1) {
|
||||
content = Html.fromHtml(getString(R.string.delete_x_songs, songs.size()));
|
||||
} else {
|
||||
content = Html.fromHtml(getString(R.string.delete_song_x, songs.get(0).title));
|
||||
content = Html.fromHtml(getString(R.string.delete_song_x, songs.get(0).getTitle()));
|
||||
}
|
||||
this.title.setText(content);
|
||||
}
|
||||
|
|
|
@ -81,8 +81,8 @@ public class MainOptionsBottomSheetDialogFragment extends RoundedBottomSheetDial
|
|||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View layout = inflater.inflate(R.layout.fragment_main_options, container, false);
|
||||
ButterKnife.bind(this, layout);
|
||||
layout.findViewById(R.id.action_buy_pro).setVisibility(RetroApplication.isProVersion() ? View.GONE : View.VISIBLE);
|
||||
ButterKnife.apply(materialButtons, textColor, ThemeStore.textColorPrimary(getContext()));
|
||||
layout.findViewById(R.id.action_buy_pro).setVisibility(RetroApplication.Companion.isProVersion() ? View.GONE : View.VISIBLE);
|
||||
//ButterKnife.apply(materialButtons, textColor, ThemeStore.textColorPrimary(getContext()));
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ public class MainOptionsBottomSheetDialogFragment extends RoundedBottomSheetDial
|
|||
.setQuality(75)
|
||||
.setCompressFormat(Bitmap.CompressFormat.WEBP)
|
||||
.compressToBitmapAsFlowable(
|
||||
new File(PreferenceUtil.getInstance().getProfileImage(), USER_PROFILE))
|
||||
new File(PreferenceUtil.getInstance().getProfileImage(),USER_PROFILE))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(userImageBottom::setImageBitmap,
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
package code.name.monkey.retromusic.dialogs;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import code.name.monkey.appthemehelper.ThemeStore;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.model.PlaylistSong;
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
||||
|
||||
|
||||
public class RemoveFromPlaylistDialog extends RoundedBottomSheetDialogFragment {
|
||||
@BindView(R.id.action_remove)
|
||||
TextView remove;
|
||||
|
||||
@BindView(R.id.title)
|
||||
TextView title;
|
||||
|
||||
@BindView(R.id.action_cancel)
|
||||
TextView cancel;
|
||||
|
||||
@NonNull
|
||||
public static RemoveFromPlaylistDialog create(PlaylistSong song) {
|
||||
ArrayList<PlaylistSong> list = new ArrayList<>();
|
||||
list.add(song);
|
||||
return create(list);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static RemoveFromPlaylistDialog create(ArrayList<PlaylistSong> songs) {
|
||||
RemoveFromPlaylistDialog dialog = new RemoveFromPlaylistDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelableArrayList("songs", songs);
|
||||
dialog.setArguments(args);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@OnClick({R.id.action_cancel, R.id.action_remove})
|
||||
void actions(View view) {
|
||||
final ArrayList<PlaylistSong> songs = getArguments().getParcelableArrayList("songs");
|
||||
switch (view.getId()) {
|
||||
case R.id.action_remove:
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
PlaylistsUtil.removeFromPlaylist(getActivity(), songs);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View layout = inflater.inflate(R.layout.dialog_remove_from_playlist, container, false);
|
||||
ButterKnife.bind(this, layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
//noinspection unchecked
|
||||
final ArrayList<PlaylistSong> songs = getArguments().getParcelableArrayList("songs");
|
||||
int title;
|
||||
CharSequence content;
|
||||
if (songs != null && songs.size() > 1) {
|
||||
title = R.string.remove_songs_from_playlist_title;
|
||||
content = Html.fromHtml(getString(R.string.remove_x_songs_from_playlist, songs.size()));
|
||||
} else {
|
||||
title = R.string.remove_song_from_playlist_title;
|
||||
content = Html.fromHtml(getString(R.string.remove_song_x_from_playlist, songs.get(0).title));
|
||||
}
|
||||
this.remove.setText(content);
|
||||
this.title.setText(title);
|
||||
|
||||
this.title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
||||
this.remove.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
||||
this.cancel.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package code.name.monkey.retromusic.dialogs
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.model.PlaylistSong
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment
|
||||
import java.util.*
|
||||
|
||||
|
||||
class RemoveFromPlaylistDialog : RoundedBottomSheetDialogFragment() {
|
||||
@BindView(R.id.action_remove)
|
||||
internal var remove: TextView? = null
|
||||
|
||||
@BindView(R.id.title)
|
||||
internal var title: TextView? = null
|
||||
|
||||
@BindView(R.id.action_cancel)
|
||||
internal var cancel: TextView? = null
|
||||
|
||||
@OnClick(R.id.action_cancel, R.id.action_remove)
|
||||
internal fun actions(view: View) {
|
||||
val songs = arguments!!.getParcelableArrayList<PlaylistSong>("songs")
|
||||
when (view.id) {
|
||||
R.id.action_remove -> {
|
||||
if (activity == null)
|
||||
return
|
||||
PlaylistsUtil.removeFromPlaylist(activity!!, songs!!)
|
||||
}
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val layout = inflater.inflate(R.layout.dialog_remove_from_playlist, container, false)
|
||||
ButterKnife.bind(this, layout)
|
||||
return layout
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val songs = arguments!!.getParcelableArrayList<PlaylistSong>("songs")
|
||||
val title: Int
|
||||
val content: CharSequence
|
||||
if (songs != null && songs.size > 1) {
|
||||
title = R.string.remove_songs_from_playlist_title
|
||||
content = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(getString(R.string.remove_x_songs_from_playlist, songs.size), Html.FROM_HTML_MODE_LEGACY)
|
||||
} else {
|
||||
Html.fromHtml(getString(R.string.remove_x_songs_from_playlist, songs.size))
|
||||
}
|
||||
} else {
|
||||
title = R.string.remove_song_from_playlist_title
|
||||
content = Html.fromHtml(getString(R.string.remove_song_x_from_playlist, songs!![0].title))
|
||||
}
|
||||
this.remove!!.text = content
|
||||
this.title!!.setText(title)
|
||||
|
||||
this.title!!.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||
this.remove!!.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||
this.cancel!!.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun create(song: PlaylistSong): RemoveFromPlaylistDialog {
|
||||
val list = ArrayList<PlaylistSong>()
|
||||
list.add(song)
|
||||
return create(list)
|
||||
}
|
||||
|
||||
fun create(songs: ArrayList<PlaylistSong>): RemoveFromPlaylistDialog {
|
||||
val dialog = RemoveFromPlaylistDialog()
|
||||
val args = Bundle()
|
||||
args.putParcelableArrayList("songs", songs)
|
||||
dialog.arguments = args
|
||||
return dialog
|
||||
}
|
||||
}
|
||||
}
|
|
@ -168,7 +168,7 @@ public class SleepTimerDialog extends RoundedBottomSheetDialogFragment {
|
|||
|
||||
private Intent makeTimerIntent() {
|
||||
return new Intent(getActivity(), MusicService.class)
|
||||
.setAction(ACTION_QUIT);
|
||||
.setAction( ACTION_QUIT);
|
||||
}
|
||||
|
||||
private class TimerUpdater extends CountDownTimer {
|
||||
|
|
|
@ -94,7 +94,7 @@ public class SongDetailDialog extends RoundedBottomSheetDialogFragment {
|
|||
|
||||
final Song song = getArguments().getParcelable("song");
|
||||
if (song != null) {
|
||||
final File songFile = new File(song.data);
|
||||
final File songFile = new File(song.getData());
|
||||
if (songFile.exists()) {
|
||||
textViews.get(1).setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName()));
|
||||
textViews.get(2).setText(makeTextWithTitle(context, R.string.label_file_path, songFile.getAbsolutePath()));
|
||||
|
@ -110,12 +110,12 @@ public class SongDetailDialog extends RoundedBottomSheetDialogFragment {
|
|||
} catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
Log.e(TAG, "error while reading the song file", e);
|
||||
// fallback
|
||||
textViews.get(5).setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration)));
|
||||
textViews.get(5).setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.getDuration())));
|
||||
}
|
||||
} else {
|
||||
// fallback
|
||||
textViews.get(1).setText(makeTextWithTitle(context, R.string.label_file_name, song.title));
|
||||
textViews.get(5).setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration)));
|
||||
textViews.get(1).setText(makeTextWithTitle(context, R.string.label_file_name, song.getTitle()));
|
||||
textViews.get(5).setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.getDuration())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class SongShareDialog extends RoundedBottomSheetDialogFragment {
|
|||
super.onViewCreated(view, savedInstanceState);
|
||||
final Song song = getArguments().getParcelable("song");
|
||||
|
||||
audioFile.setText(getString(R.string.currently_listening_to_x_by_x, song.title, song.artistName));
|
||||
audioFile.setText(getString(R.string.currently_listening_to_x_by_x, song.getTitle(), song.getArtistName()));
|
||||
audioFile.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
||||
audioText.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
||||
title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
||||
|
@ -60,7 +60,7 @@ public class SongShareDialog extends RoundedBottomSheetDialogFragment {
|
|||
@OnClick({R.id.option_2, R.id.option_1})
|
||||
void onClick(View view) {
|
||||
final Song song = getArguments().getParcelable("song");
|
||||
final String currentlyListening = getString(R.string.currently_listening_to_x_by_x, song.title, song.artistName);
|
||||
final String currentlyListening = getString(R.string.currently_listening_to_x_by_x, song.getTitle(), song.getArtistName());
|
||||
switch (view.getId()) {
|
||||
case R.id.option_1:
|
||||
startActivity(Intent.createChooser(
|
||||
|
|
|
@ -31,7 +31,7 @@ public class ArtistGlideRequest {
|
|||
|
||||
private static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist,
|
||||
boolean noCustomImage, boolean forceDownload) {
|
||||
boolean hasCustomImage = CustomArtistImageUtil.getInstance(RetroApplication.getInstance())
|
||||
boolean hasCustomImage = CustomArtistImageUtil.getInstance(RetroApplication.Companion.getInstance())
|
||||
.hasCustomArtistImage(artist);
|
||||
if (noCustomImage || !hasCustomImage) {
|
||||
return requestManager.load(new ArtistImage(artist.getName(), forceDownload));
|
||||
|
@ -41,7 +41,7 @@ public class ArtistGlideRequest {
|
|||
}
|
||||
|
||||
private static Key createSignature(Artist artist) {
|
||||
return ArtistSignatureUtil.getInstance(RetroApplication.getInstance())
|
||||
return ArtistSignatureUtil.getInstance(RetroApplication.Companion.getInstance())
|
||||
.getArtistSignature(artist.getName());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.RetroApplication;
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget;
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
|
||||
import static code.name.monkey.retromusic.util.RetroColorUtil.getColor;
|
||||
import static code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor;
|
||||
|
||||
|
||||
public abstract class RetroMusicColoredTarget extends BitmapPaletteTarget {
|
||||
|
||||
public RetroMusicColoredTarget(ImageView view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
super.onLoadFailed(e, errorDrawable);
|
||||
onColorReady(getDefaultFooterColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
||||
super.onResourceReady(resource, glideAnimation);
|
||||
int defaultColor = getDefaultFooterColor();
|
||||
|
||||
int primaryColor = getColor(resource.getPalette(), defaultColor);
|
||||
int dominantColor = getDominantColor(resource.getBitmap(), defaultColor);
|
||||
|
||||
onColorReady(PreferenceUtil.getInstance().isDominantColor() ?
|
||||
dominantColor : primaryColor);
|
||||
}
|
||||
|
||||
protected int getDefaultFooterColor() {
|
||||
return ATHUtil.resolveColor(getView().getContext(), R.attr.defaultFooterColor);
|
||||
}
|
||||
|
||||
protected int getAlbumArtistFooterColor() {
|
||||
return ATHUtil.resolveColor(getView().getContext(), R.attr.cardBackgroundColor);
|
||||
}
|
||||
|
||||
public abstract void onColorReady(int color);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package code.name.monkey.retromusic.glide
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.widget.ImageView
|
||||
|
||||
import com.bumptech.glide.request.animation.GlideAnimation
|
||||
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.RetroApplication
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget
|
||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor
|
||||
|
||||
|
||||
abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) {
|
||||
|
||||
protected val defaultFooterColor: Int
|
||||
get() = ATHUtil.resolveColor(getView().context, R.attr.defaultFooterColor)
|
||||
|
||||
protected val albumArtistFooterColor: Int
|
||||
get() = ATHUtil.resolveColor(getView().context, R.attr.cardBackgroundColor)
|
||||
|
||||
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(e, errorDrawable)
|
||||
onColorReady(defaultFooterColor)
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: BitmapPaletteWrapper,
|
||||
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) {
|
||||
super.onResourceReady(resource, glideAnimation)
|
||||
val defaultColor = defaultFooterColor
|
||||
|
||||
val primaryColor = getColor(resource.palette, defaultColor)
|
||||
val dominantColor = getDominantColor(resource.bitmap, defaultColor)
|
||||
|
||||
onColorReady(if (PreferenceUtil.getInstance().isDominantColor)
|
||||
dominantColor
|
||||
else
|
||||
primaryColor)
|
||||
}
|
||||
|
||||
abstract fun onColorReady(color: Int)
|
||||
}
|
|
@ -29,14 +29,14 @@ public class SongGlideRequest {
|
|||
static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Song song,
|
||||
boolean ignoreMediaStore) {
|
||||
if (ignoreMediaStore) {
|
||||
return requestManager.load(new AudioFileCover(song.data));
|
||||
return requestManager.load(new AudioFileCover(song.getData()));
|
||||
} else {
|
||||
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.albumId));
|
||||
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||
}
|
||||
}
|
||||
|
||||
static Key createSignature(Song song) {
|
||||
return new MediaStoreSignature("", song.dateModified, 0);
|
||||
return new MediaStoreSignature("", song.getDateModified(), 0);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.palette;
|
||||
|
||||
import android.widget.ImageView;
|
||||
import com.bumptech.glide.request.target.ImageViewTarget;
|
||||
|
||||
public class BitmapPaletteTarget extends ImageViewTarget<BitmapPaletteWrapper> {
|
||||
|
||||
public BitmapPaletteTarget(ImageView view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setResource(BitmapPaletteWrapper bitmapPaletteWrapper) {
|
||||
view.setImageBitmap(bitmapPaletteWrapper.getBitmap());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package code.name.monkey.retromusic.glide.palette
|
||||
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.request.target.ImageViewTarget
|
||||
|
||||
open class BitmapPaletteTarget(view: ImageView) : ImageViewTarget<BitmapPaletteWrapper>(view) {
|
||||
|
||||
override fun setResource(bitmapPaletteWrapper: BitmapPaletteWrapper) {
|
||||
view.setImageBitmap(bitmapPaletteWrapper.bitmap)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.media.audiofx.BassBoost;
|
||||
import android.media.audiofx.Equalizer;
|
||||
import android.media.audiofx.Virtualizer;
|
||||
import android.util.Log;
|
||||
|
||||
import code.name.monkey.retromusic.interfaces.EqualizerInterface;
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
public class EqualizerHelper implements EqualizerInterface {
|
||||
private static final String TAG = "EqualizerHelper";
|
||||
private static volatile EqualizerHelper ourInstance;
|
||||
private Equalizer mEqualizer;
|
||||
private BassBoost mBassBoost;
|
||||
private Virtualizer mVirtualizer;
|
||||
|
||||
private int mMaxLevel, mMinLevel;
|
||||
private boolean isRunning = false;
|
||||
|
||||
private EqualizerHelper() {
|
||||
|
||||
//Prevent form the reflection api.
|
||||
if (ourInstance != null) {
|
||||
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
|
||||
}
|
||||
|
||||
int i = MusicPlayerRemote.getAudioSessionId();
|
||||
|
||||
mEqualizer = new Equalizer(100, i);
|
||||
if (mEqualizer == null) {
|
||||
Log.i(TAG, "onCreate: Equalizer is null");
|
||||
return;
|
||||
}
|
||||
mEqualizer.setEnabled(true);
|
||||
|
||||
|
||||
mBassBoost = new BassBoost(100, i);
|
||||
if (mBassBoost == null) {
|
||||
Log.i(TAG, "onCreate: BassBoost is null");
|
||||
return;
|
||||
}
|
||||
|
||||
mVirtualizer = new Virtualizer(100, i);
|
||||
if (mVirtualizer == null) {
|
||||
Log.i(TAG, "onCreate: Virtualizer is null");
|
||||
return;
|
||||
}
|
||||
|
||||
mMaxLevel = (int) mEqualizer.getBandLevelRange()[1];
|
||||
mMinLevel = (int) mEqualizer.getBandLevelRange()[0];
|
||||
|
||||
Log.i(TAG, "onCreate: " + mMaxLevel + " " + mMinLevel);
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
public static EqualizerHelper getInstance() {
|
||||
//Double check locking pattern
|
||||
if (ourInstance == null) {//Check for the first time
|
||||
|
||||
synchronized (EqualizerHelper.class) {//Check for the second time.
|
||||
|
||||
//if there is no instance available... create new one
|
||||
if (ourInstance == null) {
|
||||
ourInstance = new EqualizerHelper();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
//Make singleton from serialize and deserialize operation.
|
||||
protected EqualizerHelper readResolve() {
|
||||
return getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Equalizer getEqualizer() {
|
||||
return mEqualizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BassBoost getBassBoost() {
|
||||
return mBassBoost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Virtualizer getVirtualizer() {
|
||||
return mVirtualizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBandLevelLow() {
|
||||
return mMinLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBandLevelHigh() {
|
||||
return mMaxLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfBands() {
|
||||
return (int) mEqualizer.getNumberOfBands();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCenterFreq(int band) {
|
||||
return (int) mEqualizer.getCenterFreq((short) band);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getBandLevel(int band) {
|
||||
return (int) mEqualizer.getBandLevel((short) band);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBandLevel(int band, int level) {
|
||||
mEqualizer.setBandLevel((short) band, (short) level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBassBoostEnabled() {
|
||||
return mBassBoost.getEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBassBoostEnabled(boolean isEnabled) {
|
||||
mBassBoost.setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBassBoostStrength() {
|
||||
return (int) mBassBoost.getRoundedStrength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBassBoostStrength(int strength) {
|
||||
mBassBoost.setStrength((short) strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVirtualizerEnabled() {
|
||||
return mVirtualizer.getEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVirtualizerEnabled(boolean isEnabled) {
|
||||
mVirtualizer.setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVirtualizerStrength() {
|
||||
return mVirtualizer.getRoundedStrength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVirtualizerStrength(int strength) {
|
||||
mVirtualizer.setStrength((short) strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.media.audiofx.BassBoost
|
||||
import android.media.audiofx.Equalizer
|
||||
import android.media.audiofx.Virtualizer
|
||||
import android.util.Log
|
||||
|
||||
import code.name.monkey.retromusic.interfaces.EqualizerInterface
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
class EqualizerHelper private constructor() : EqualizerInterface {
|
||||
override val equalizer: Equalizer
|
||||
override val bassBoost: BassBoost
|
||||
override val virtualizer: Virtualizer
|
||||
|
||||
override val bandLevelHigh: Int
|
||||
override val bandLevelLow: Int
|
||||
override var isRunning = false
|
||||
|
||||
override val numberOfBands: Int
|
||||
get() = equalizer.numberOfBands.toInt()
|
||||
|
||||
override var isBassBoostEnabled: Boolean
|
||||
get() = bassBoost.enabled
|
||||
set(isEnabled) {
|
||||
bassBoost.enabled = isEnabled
|
||||
}
|
||||
|
||||
override var bassBoostStrength: Int
|
||||
get() = bassBoost.roundedStrength.toInt()
|
||||
set(strength) = bassBoost.setStrength(strength.toShort())
|
||||
|
||||
override var isVirtualizerEnabled: Boolean
|
||||
get() = virtualizer.enabled
|
||||
set(isEnabled) {
|
||||
virtualizer.enabled = isEnabled
|
||||
}
|
||||
|
||||
override var virtualizerStrength: Int
|
||||
get() = virtualizer.roundedStrength.toInt()
|
||||
set(strength) = virtualizer.setStrength(strength.toShort())
|
||||
|
||||
init {
|
||||
|
||||
//Prevent form the reflection api.
|
||||
if (ourInstance != null) {
|
||||
throw RuntimeException("Use getInstance() method to get the single instance of this class.")
|
||||
}
|
||||
|
||||
val i = MusicPlayerRemote.audioSessionId
|
||||
|
||||
equalizer = Equalizer(100, i)
|
||||
|
||||
equalizer.enabled = true
|
||||
bassBoost = BassBoost(100, i)
|
||||
virtualizer = Virtualizer(100, i)
|
||||
|
||||
bandLevelHigh = equalizer.bandLevelRange[1].toInt()
|
||||
bandLevelLow = equalizer.bandLevelRange[0].toInt()
|
||||
|
||||
Log.i(TAG, "onCreate: $bandLevelHigh $bandLevelLow")
|
||||
isRunning = true
|
||||
}
|
||||
|
||||
//Make singleton from serialize and deserialize operation.
|
||||
protected fun readResolve(): EqualizerHelper? {
|
||||
return instance
|
||||
}
|
||||
|
||||
override fun getCenterFreq(band: Int): Int {
|
||||
return equalizer.getCenterFreq(band.toShort())
|
||||
}
|
||||
|
||||
|
||||
override fun getBandLevel(band: Int): Int {
|
||||
return equalizer.getBandLevel(band.toShort()).toInt()
|
||||
}
|
||||
|
||||
override fun setBandLevel(band: Int, level: Int) {
|
||||
equalizer.setBandLevel(band.toShort(), level.toShort())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "EqualizerHelper"
|
||||
@Volatile
|
||||
private var ourInstance: EqualizerHelper? = null
|
||||
|
||||
//Double check locking pattern
|
||||
//Check for the first time
|
||||
//Check for the second time.
|
||||
//if there is no instance available... create new one
|
||||
val instance: EqualizerHelper?
|
||||
get() {
|
||||
if (ourInstance == null) {
|
||||
|
||||
synchronized(EqualizerHelper::class.java) {
|
||||
if (ourInstance == null) {
|
||||
ourInstance = EqualizerHelper()
|
||||
}
|
||||
}
|
||||
}
|
||||
return ourInstance
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
|
||||
public class HorizontalAdapterHelper {
|
||||
|
||||
public static final int LAYOUT_RES = R.layout.item_image;
|
||||
|
||||
public static final int TYPE_FIRST = 1;
|
||||
public static final int TYPE_MIDDLE = 2;
|
||||
public static final int TYPE_LAST = 3;
|
||||
|
||||
public static void applyMarginToLayoutParams(Context context,
|
||||
ViewGroup.MarginLayoutParams layoutParams, int viewType) {
|
||||
int listMargin = context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.now_playing_top_margin);
|
||||
if (viewType == TYPE_FIRST) {
|
||||
layoutParams.leftMargin = listMargin;
|
||||
} else if (viewType == TYPE_LAST) {
|
||||
layoutParams.rightMargin = listMargin;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getItemViewtype(int position, int itemCount) {
|
||||
if (position == 0) {
|
||||
return TYPE_FIRST;
|
||||
} else if (position == itemCount - 1) {
|
||||
return TYPE_LAST;
|
||||
} else {
|
||||
return TYPE_MIDDLE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import code.name.monkey.retromusic.R
|
||||
|
||||
|
||||
object HorizontalAdapterHelper {
|
||||
|
||||
val LAYOUT_RES = R.layout.item_image
|
||||
|
||||
val TYPE_FIRST = 1
|
||||
val TYPE_MIDDLE = 2
|
||||
val TYPE_LAST = 3
|
||||
|
||||
fun applyMarginToLayoutParams(context: Context,
|
||||
layoutParams: ViewGroup.MarginLayoutParams, viewType: Int) {
|
||||
val listMargin = context.resources
|
||||
.getDimensionPixelSize(R.dimen.now_playing_top_margin)
|
||||
if (viewType == TYPE_FIRST) {
|
||||
layoutParams.leftMargin = listMargin
|
||||
} else if (viewType == TYPE_LAST) {
|
||||
layoutParams.rightMargin = listMargin
|
||||
}
|
||||
}
|
||||
|
||||
fun getItemViewtype(position: Int, itemCount: Int): Int {
|
||||
return if (position == 0) {
|
||||
TYPE_FIRST
|
||||
} else if (position == itemCount - 1) {
|
||||
TYPE_LAST
|
||||
} else {
|
||||
TYPE_MIDDLE
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
public interface M3UConstants {
|
||||
String EXTENSION = "m3u";
|
||||
String HEADER = "#EXTM3U";
|
||||
String ENTRY = "#EXTINF:";
|
||||
String DURATION_SEPARATOR = ",";
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
interface M3UConstants {
|
||||
companion object {
|
||||
val EXTENSION = "m3u"
|
||||
val HEADER = "#EXTM3U"
|
||||
val ENTRY = "#EXTINF:"
|
||||
val DURATION_SEPARATOR = ","
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist;
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableEmitter;
|
||||
|
||||
public class M3UWriter implements M3UConstants {
|
||||
public static final String TAG = M3UWriter.class.getSimpleName();
|
||||
|
||||
public static Observable<File> write(@NonNull Context context,
|
||||
@NonNull File dir, @NonNull Playlist playlist) {
|
||||
if (!dir.exists()) //noinspection ResultOfMethodCallIgnored
|
||||
dir.mkdirs();
|
||||
File file = new File(dir, playlist.name.concat("." + EXTENSION));
|
||||
|
||||
if (playlist instanceof AbsCustomPlaylist) {
|
||||
return Observable.create(e -> {
|
||||
((AbsCustomPlaylist) playlist).getSongs(context).subscribe(songs -> {
|
||||
saveSongsToFile(file, e, songs);
|
||||
});
|
||||
});
|
||||
} else
|
||||
return Observable.create(e ->
|
||||
PlaylistSongsLoader.getPlaylistSongList(context, playlist.id)
|
||||
.subscribe(songs -> {
|
||||
saveSongsToFile(file, e, songs);
|
||||
}));
|
||||
}
|
||||
|
||||
private static void saveSongsToFile(File file, ObservableEmitter<File> e, ArrayList<Song> songs) throws IOException {
|
||||
if (songs.size() > 0) {
|
||||
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
|
||||
bw.write(HEADER);
|
||||
for (Song song : songs) {
|
||||
bw.newLine();
|
||||
bw.write(ENTRY + song.duration + DURATION_SEPARATOR + song.artistName + " - " + song.title);
|
||||
bw.newLine();
|
||||
bw.write(song.data);
|
||||
}
|
||||
|
||||
bw.close();
|
||||
}
|
||||
e.onNext(file);
|
||||
e.onComplete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.content.Context
|
||||
|
||||
import java.io.BufferedWriter
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
import java.util.ArrayList
|
||||
|
||||
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableEmitter
|
||||
|
||||
class M3UWriter : M3UConstants {
|
||||
companion object {
|
||||
val TAG: String = M3UWriter::class.java.simpleName
|
||||
|
||||
fun write(context: Context,
|
||||
dir: File, playlist: Playlist): Observable<File> {
|
||||
if (!dir.exists())
|
||||
|
||||
dir.mkdirs()
|
||||
val file = File(dir, playlist.name + ("." + M3UConstants.EXTENSION))
|
||||
|
||||
return if (playlist is AbsCustomPlaylist) {
|
||||
Observable.create { e -> playlist.getSongs(context).subscribe { songs -> saveSongsToFile(file, e, songs) } }
|
||||
} else
|
||||
Observable.create { e -> PlaylistSongsLoader.getPlaylistSongList(context, playlist.id).subscribe { songs -> saveSongsToFile(file, e, songs) } }
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun saveSongsToFile(file: File, e: ObservableEmitter<File>, songs: ArrayList<Song>) {
|
||||
if (songs.size > 0) {
|
||||
val bw = BufferedWriter(FileWriter(file))
|
||||
bw.write(M3UConstants.HEADER)
|
||||
for (song in songs) {
|
||||
bw.newLine()
|
||||
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
|
||||
bw.newLine()
|
||||
bw.write(song.data)
|
||||
}
|
||||
|
||||
bw.close()
|
||||
}
|
||||
e.onNext(file)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,496 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastContext;
|
||||
import com.google.android.gms.cast.framework.CastSession;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.RetroApplication;
|
||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
|
||||
public class MusicPlayerRemote {
|
||||
public static final String TAG = MusicPlayerRemote.class.getSimpleName();
|
||||
private static final WeakHashMap<Context, ServiceBinder> mConnectionMap = new WeakHashMap<>();
|
||||
@Nullable
|
||||
public static MusicService musicService;
|
||||
private static int playbackLocation = PlaybackLocation.LOCAL;
|
||||
|
||||
|
||||
private static CastSession getCastSession() {
|
||||
CastSession castSession = CastContext.getSharedInstance(RetroApplication.getInstance()).getSessionManager().getCurrentCastSession();
|
||||
if (castSession != null) {
|
||||
playbackLocation = PlaybackLocation.REMOTE;
|
||||
} else {
|
||||
playbackLocation = PlaybackLocation.LOCAL;
|
||||
}
|
||||
return castSession;
|
||||
}
|
||||
|
||||
public static ServiceToken bindToService(@NonNull final Context context,
|
||||
final ServiceConnection callback) {
|
||||
|
||||
Activity realActivity = ((Activity) context).getParent();
|
||||
if (realActivity == null) {
|
||||
realActivity = (Activity) context;
|
||||
}
|
||||
|
||||
final ContextWrapper contextWrapper = new ContextWrapper(realActivity);
|
||||
contextWrapper.startService(new Intent(contextWrapper, MusicService.class));
|
||||
|
||||
final ServiceBinder binder = new ServiceBinder(callback);
|
||||
|
||||
if (contextWrapper.bindService(new Intent().setClass(contextWrapper, MusicService.class), binder, Context.BIND_AUTO_CREATE)) {
|
||||
mConnectionMap.put(contextWrapper, binder);
|
||||
return new ServiceToken(contextWrapper);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void unbindFromService(@Nullable final ServiceToken token) {
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
final ContextWrapper mContextWrapper = token.mWrappedContext;
|
||||
final ServiceBinder mBinder = mConnectionMap.remove(mContextWrapper);
|
||||
if (mBinder == null) {
|
||||
return;
|
||||
}
|
||||
mContextWrapper.unbindService(mBinder);
|
||||
if (mConnectionMap.isEmpty()) {
|
||||
musicService = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getFilePathFromUri(Context context, Uri uri) {
|
||||
|
||||
final String column = "_data";
|
||||
final String[] projection = {
|
||||
column
|
||||
};
|
||||
try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null,
|
||||
null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int column_index = cursor.getColumnIndexOrThrow(column);
|
||||
return cursor.getString(column_index);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void playSongAt(final int position) {
|
||||
if (musicService != null) {
|
||||
musicService.playSongAt(position);
|
||||
}
|
||||
}
|
||||
|
||||
public static void pauseSong() {
|
||||
if (musicService != null) {
|
||||
musicService.pause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void playNextSong() {
|
||||
if (musicService != null) {
|
||||
musicService.playNextSong(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void playPreviousSong() {
|
||||
if (musicService != null) {
|
||||
musicService.playPreviousSong(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void back() {
|
||||
if (musicService != null) {
|
||||
musicService.back(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPlaying() {
|
||||
return musicService != null && musicService.isPlaying();
|
||||
}
|
||||
|
||||
public static void resumePlaying() {
|
||||
if (musicService != null) {
|
||||
musicService.play();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void openQueue(final ArrayList<Song> queue, final int startPosition, final boolean startPlaying) {
|
||||
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
||||
musicService.openQueue(queue, startPosition, startPlaying);
|
||||
if (PreferenceUtil.getInstance().isShuffleModeOn())
|
||||
setShuffleMode(MusicService.SHUFFLE_MODE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void openAndShuffleQueue(final ArrayList<Song> queue, boolean startPlaying) {
|
||||
int startPosition = 0;
|
||||
if (!queue.isEmpty()) {
|
||||
startPosition = new Random().nextInt(queue.size());
|
||||
}
|
||||
|
||||
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
||||
openQueue(queue, startPosition, startPlaying);
|
||||
setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean tryToHandleOpenPlayingQueue(final ArrayList<Song> queue, final int startPosition, final boolean startPlaying) {
|
||||
if (getPlayingQueue() == queue) {
|
||||
if (startPlaying) {
|
||||
playSongAt(startPosition);
|
||||
} else {
|
||||
setPosition(startPosition);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Song getCurrentSong() {
|
||||
if (musicService != null) {
|
||||
return musicService.getCurrentSong();
|
||||
}
|
||||
return Song.EMPTY_SONG;
|
||||
}
|
||||
|
||||
public static int getPosition() {
|
||||
if (musicService != null) {
|
||||
return musicService.getPosition();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
public static void setPosition(final int position) {
|
||||
if (musicService != null) {
|
||||
musicService.setPosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
public static ArrayList<Song> getPlayingQueue() {
|
||||
if (musicService != null) {
|
||||
return musicService.getPlayingQueue();
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public static int getSongProgressMillis() {
|
||||
if (musicService != null) {
|
||||
return musicService.getSongProgressMillis();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int getSongDurationMillis() {
|
||||
if (musicService != null) {
|
||||
return musicService.getSongDurationMillis();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static long getQueueDurationMillis(int position) {
|
||||
if (musicService != null) {
|
||||
return musicService.getQueueDurationMillis(position);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int seekTo(int millis) {
|
||||
if (musicService != null) {
|
||||
return musicService.seek(millis);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int getRepeatMode() {
|
||||
if (musicService != null) {
|
||||
return musicService.getRepeatMode();
|
||||
}
|
||||
return MusicService.REPEAT_MODE_NONE;
|
||||
}
|
||||
|
||||
public static int getShuffleMode() {
|
||||
if (musicService != null) {
|
||||
return musicService.getShuffleMode();
|
||||
}
|
||||
return MusicService.SHUFFLE_MODE_NONE;
|
||||
}
|
||||
|
||||
public static boolean cycleRepeatMode() {
|
||||
if (musicService != null) {
|
||||
musicService.cycleRepeatMode();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean toggleShuffleMode() {
|
||||
if (musicService != null) {
|
||||
musicService.toggleShuffle();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean setShuffleMode(final int shuffleMode) {
|
||||
if (musicService != null) {
|
||||
musicService.setShuffleMode(shuffleMode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean playNext(Song song) {
|
||||
if (musicService != null) {
|
||||
if (getPlayingQueue().size() > 0) {
|
||||
musicService.addSong(getPosition() + 1, song);
|
||||
} else {
|
||||
ArrayList<Song> queue = new ArrayList<>();
|
||||
queue.add(song);
|
||||
openQueue(queue, 0, false);
|
||||
}
|
||||
Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean playNext(@NonNull ArrayList<Song> songs) {
|
||||
if (musicService != null) {
|
||||
if (getPlayingQueue().size() > 0) {
|
||||
musicService.addSongs(getPosition() + 1, songs);
|
||||
} else {
|
||||
openQueue(songs, 0, false);
|
||||
}
|
||||
final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size());
|
||||
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean enqueue(Song song) {
|
||||
if (musicService != null) {
|
||||
if (getPlayingQueue().size() > 0) {
|
||||
musicService.addSong(song);
|
||||
} else {
|
||||
ArrayList<Song> queue = new ArrayList<>();
|
||||
queue.add(song);
|
||||
openQueue(queue, 0, false);
|
||||
}
|
||||
Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean enqueue(@NonNull ArrayList<Song> songs) {
|
||||
if (musicService != null) {
|
||||
if (getPlayingQueue().size() > 0) {
|
||||
musicService.addSongs(songs);
|
||||
} else {
|
||||
openQueue(songs, 0, false);
|
||||
}
|
||||
final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size());
|
||||
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean removeFromQueue(@NonNull Song song) {
|
||||
if (musicService != null) {
|
||||
musicService.removeSong(song);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean removeFromQueue(int position) {
|
||||
if (musicService != null && position >= 0 && position < getPlayingQueue().size()) {
|
||||
musicService.removeSong(position);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean moveSong(int from, int to) {
|
||||
if (musicService != null && from >= 0 && to >= 0 && from < getPlayingQueue().size() && to < getPlayingQueue().size()) {
|
||||
musicService.moveSong(from, to);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean clearQueue() {
|
||||
if (musicService != null) {
|
||||
musicService.clearQueue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getAudioSessionId() {
|
||||
if (musicService != null) {
|
||||
return musicService.getAudioSessionId();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void playFromUri(Uri uri) {
|
||||
if (musicService != null) {
|
||||
ArrayList<Song> songs = null;
|
||||
if (uri.getScheme() != null && uri.getAuthority() != null) {
|
||||
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
|
||||
String songId = null;
|
||||
if (uri.getAuthority().equals("com.android.providers.media.documents")) {
|
||||
songId = getSongIdFromMediaProvider(uri);
|
||||
} else if (uri.getAuthority().equals("media")) {
|
||||
songId = uri.getLastPathSegment();
|
||||
}
|
||||
if (songId != null) {
|
||||
/* songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
musicService,
|
||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
new String[]{songId}
|
||||
));*/
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
musicService,
|
||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
new String[]{songId}))
|
||||
.subscribeOn(Schedulers.io()).blockingFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (songs == null) {
|
||||
File songFile = null;
|
||||
if (uri.getAuthority() != null && uri.getAuthority().equals("com.android.externalstorage.documents")) {
|
||||
songFile = new File(Environment.getExternalStorageDirectory(), uri.getPath().split(":", 2)[1]);
|
||||
}
|
||||
if (songFile == null) {
|
||||
String path = getFilePathFromUri(musicService, uri);
|
||||
if (path != null)
|
||||
songFile = new File(path);
|
||||
}
|
||||
if (songFile == null && uri.getPath() != null) {
|
||||
songFile = new File(uri.getPath());
|
||||
}
|
||||
if (songFile != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
musicService,
|
||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
||||
new String[]{songFile.getAbsolutePath()}
|
||||
)).blockingFirst();
|
||||
}
|
||||
}
|
||||
if (songs != null && !songs.isEmpty()) {
|
||||
openQueue(songs, 0, true);
|
||||
} else {
|
||||
//TODO the file is not listed in the media store
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private static String getSongIdFromMediaProvider(Uri uri) {
|
||||
return DocumentsContract.getDocumentId(uri).split(":")[1];
|
||||
}
|
||||
|
||||
public static boolean isServiceConnected() {
|
||||
return musicService != null;
|
||||
}
|
||||
|
||||
@interface PlaybackLocation {
|
||||
int REMOTE = 0;
|
||||
int LOCAL = 1;
|
||||
}
|
||||
|
||||
public static final class ServiceBinder implements ServiceConnection {
|
||||
private final ServiceConnection mCallback;
|
||||
|
||||
ServiceBinder(final ServiceConnection callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(final ComponentName className, final IBinder service) {
|
||||
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
|
||||
musicService = binder.getService();
|
||||
if (mCallback != null) {
|
||||
mCallback.onServiceConnected(className, service);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(final ComponentName className) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onServiceDisconnected(className);
|
||||
}
|
||||
musicService = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServiceToken {
|
||||
ContextWrapper mWrappedContext;
|
||||
|
||||
ServiceToken(final ContextWrapper context) {
|
||||
mWrappedContext = context;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,440 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.IBinder
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.RetroApplication
|
||||
import code.name.monkey.retromusic.loaders.SongLoader
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
|
||||
object MusicPlayerRemote {
|
||||
val TAG = MusicPlayerRemote::class.java.simpleName
|
||||
private val mConnectionMap = WeakHashMap<Context, ServiceBinder>()
|
||||
var musicService: MusicService? = null
|
||||
private var playbackLocation = PlaybackLocation.LOCAL
|
||||
|
||||
|
||||
private val castSession: CastSession?
|
||||
get() {
|
||||
val castSession = CastContext.getSharedInstance(RetroApplication.instance).sessionManager.currentCastSession
|
||||
if (castSession != null) {
|
||||
playbackLocation = PlaybackLocation.REMOTE
|
||||
} else {
|
||||
playbackLocation = PlaybackLocation.LOCAL
|
||||
}
|
||||
return castSession
|
||||
}
|
||||
|
||||
val isPlaying: Boolean
|
||||
get() = musicService != null && musicService!!.isPlaying
|
||||
|
||||
val currentSong: Song
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.currentSong
|
||||
} else Song.EMPTY_SONG
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
var position: Int
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.position
|
||||
} else -1
|
||||
set(position) {
|
||||
if (musicService != null) {
|
||||
musicService!!.position = position
|
||||
}
|
||||
}
|
||||
|
||||
val playingQueue: ArrayList<Song>
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.playingQueue
|
||||
} else ArrayList()
|
||||
|
||||
val songProgressMillis: Int
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.songProgressMillis
|
||||
} else -1
|
||||
|
||||
val songDurationMillis: Int
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.songDurationMillis
|
||||
} else -1
|
||||
|
||||
val repeatMode: Int
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.repeatMode
|
||||
} else MusicService.REPEAT_MODE_NONE
|
||||
|
||||
val shuffleMode: Int
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.shuffleMode
|
||||
} else MusicService.SHUFFLE_MODE_NONE
|
||||
|
||||
val audioSessionId: Int
|
||||
get() = if (musicService != null) {
|
||||
musicService!!.audioSessionId
|
||||
} else -1
|
||||
|
||||
val isServiceConnected: Boolean
|
||||
get() = musicService != null
|
||||
|
||||
fun bindToService(context: Context,
|
||||
callback: ServiceConnection): ServiceToken? {
|
||||
|
||||
var realActivity: Activity? = (context as Activity).parent
|
||||
if (realActivity == null) {
|
||||
realActivity = context
|
||||
}
|
||||
|
||||
val contextWrapper = ContextWrapper(realActivity)
|
||||
contextWrapper.startService(Intent(contextWrapper, MusicService::class.java))
|
||||
|
||||
val binder = ServiceBinder(callback)
|
||||
|
||||
if (contextWrapper.bindService(Intent().setClass(contextWrapper, MusicService::class.java), binder, Context.BIND_AUTO_CREATE)) {
|
||||
mConnectionMap[contextWrapper] = binder
|
||||
return ServiceToken(contextWrapper)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun unbindFromService(token: ServiceToken?) {
|
||||
if (token == null) {
|
||||
return
|
||||
}
|
||||
val mContextWrapper = token.mWrappedContext
|
||||
val mBinder = mConnectionMap.remove(mContextWrapper) ?: return
|
||||
mContextWrapper.unbindService(mBinder)
|
||||
if (mConnectionMap.isEmpty()) {
|
||||
musicService = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFilePathFromUri(context: Context, uri: Uri): String? {
|
||||
|
||||
val column = "_data"
|
||||
val projection = arrayOf(column)
|
||||
try {
|
||||
context.contentResolver.query(uri, projection, null, null, null)!!.use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
val column_index = cursor.getColumnIndexOrThrow(column)
|
||||
return cursor.getString(column_index)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.message)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun playSongAt(position: Int) {
|
||||
if (musicService != null) {
|
||||
musicService!!.playSongAt(position)
|
||||
}
|
||||
}
|
||||
|
||||
fun pauseSong() {
|
||||
if (musicService != null) {
|
||||
musicService!!.pause()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun playNextSong() {
|
||||
if (musicService != null) {
|
||||
musicService!!.playNextSong(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun playPreviousSong() {
|
||||
if (musicService != null) {
|
||||
musicService!!.playPreviousSong(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun back() {
|
||||
if (musicService != null) {
|
||||
musicService!!.back(true)
|
||||
}
|
||||
}
|
||||
|
||||
fun resumePlaying() {
|
||||
if (musicService != null) {
|
||||
musicService!!.play()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun openQueue(queue: ArrayList<Song>, startPosition: Int, startPlaying: Boolean) {
|
||||
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
||||
musicService!!.openQueue(queue, startPosition, startPlaying)
|
||||
if (PreferenceUtil.getInstance().isShuffleModeOn)
|
||||
setShuffleMode(MusicService.SHUFFLE_MODE_NONE)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun openAndShuffleQueue(queue: ArrayList<Song>, startPlaying: Boolean) {
|
||||
var startPosition = 0
|
||||
if (!queue.isEmpty()) {
|
||||
startPosition = Random().nextInt(queue.size)
|
||||
}
|
||||
|
||||
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
||||
openQueue(queue, startPosition, startPlaying)
|
||||
setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryToHandleOpenPlayingQueue(queue: ArrayList<Song>, startPosition: Int, startPlaying: Boolean): Boolean {
|
||||
if (playingQueue === queue) {
|
||||
if (startPlaying) {
|
||||
playSongAt(startPosition)
|
||||
} else {
|
||||
position = startPosition
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun getQueueDurationMillis(position: Int): Long {
|
||||
return if (musicService != null) {
|
||||
musicService!!.getQueueDurationMillis(position)
|
||||
} else -1
|
||||
}
|
||||
|
||||
fun seekTo(millis: Int): Int {
|
||||
return if (musicService != null) {
|
||||
musicService!!.seek(millis)
|
||||
} else -1
|
||||
}
|
||||
|
||||
fun cycleRepeatMode(): Boolean {
|
||||
if (musicService != null) {
|
||||
musicService!!.cycleRepeatMode()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun toggleShuffleMode(): Boolean {
|
||||
if (musicService != null) {
|
||||
musicService!!.toggleShuffle()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun setShuffleMode(shuffleMode: Int): Boolean {
|
||||
if (musicService != null) {
|
||||
musicService!!.shuffleMode = shuffleMode
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun playNext(song: Song): Boolean {
|
||||
if (musicService != null) {
|
||||
if (playingQueue.size > 0) {
|
||||
musicService!!.addSong(position + 1, song)
|
||||
} else {
|
||||
val queue = ArrayList<Song>()
|
||||
queue.add(song)
|
||||
openQueue(queue, 0, false)
|
||||
}
|
||||
Toast.makeText(musicService, musicService!!.resources.getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun playNext(songs: ArrayList<Song>): Boolean {
|
||||
if (musicService != null) {
|
||||
if (playingQueue.size > 0) {
|
||||
musicService!!.addSongs(position + 1, songs)
|
||||
} else {
|
||||
openQueue(songs, 0, false)
|
||||
}
|
||||
val toast = if (songs.size == 1) musicService!!.resources.getString(R.string.added_title_to_playing_queue) else musicService!!.resources.getString(R.string.added_x_titles_to_playing_queue, songs.size)
|
||||
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun enqueue(song: Song): Boolean {
|
||||
if (musicService != null) {
|
||||
if (playingQueue.size > 0) {
|
||||
musicService!!.addSong(song)
|
||||
} else {
|
||||
val queue = ArrayList<Song>()
|
||||
queue.add(song)
|
||||
openQueue(queue, 0, false)
|
||||
}
|
||||
Toast.makeText(musicService, musicService!!.resources.getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun enqueue(songs: ArrayList<Song>): Boolean {
|
||||
if (musicService != null) {
|
||||
if (playingQueue.size > 0) {
|
||||
musicService!!.addSongs(songs)
|
||||
} else {
|
||||
openQueue(songs, 0, false)
|
||||
}
|
||||
val toast = if (songs.size == 1) musicService!!.resources.getString(R.string.added_title_to_playing_queue) else musicService!!.resources.getString(R.string.added_x_titles_to_playing_queue, songs.size)
|
||||
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeFromQueue(song: Song): Boolean {
|
||||
if (musicService != null) {
|
||||
musicService!!.removeSong(song)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeFromQueue(position: Int): Boolean {
|
||||
if (musicService != null && position >= 0 && position < playingQueue.size) {
|
||||
musicService!!.removeSong(position)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun moveSong(from: Int, to: Int): Boolean {
|
||||
if (musicService != null && from >= 0 && to >= 0 && from < playingQueue.size && to < playingQueue.size) {
|
||||
musicService!!.moveSong(from, to)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun clearQueue(): Boolean {
|
||||
if (musicService != null) {
|
||||
musicService!!.clearQueue()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun playFromUri(uri: Uri) {
|
||||
if (musicService != null) {
|
||||
var songs: ArrayList<Song>? = null
|
||||
if (uri.scheme != null && uri.authority != null) {
|
||||
if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
|
||||
var songId: String? = null
|
||||
if (uri.authority == "com.android.providers.media.documents") {
|
||||
songId = getSongIdFromMediaProvider(uri)
|
||||
} else if (uri.authority == "media") {
|
||||
songId = uri.lastPathSegment
|
||||
}
|
||||
if (songId != null) {
|
||||
/* songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
musicService,
|
||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
new String[]{songId}
|
||||
));*/
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
musicService!!,
|
||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
arrayOf(songId)))
|
||||
.subscribeOn(Schedulers.io()).blockingFirst()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (songs == null) {
|
||||
var songFile: File? = null
|
||||
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
|
||||
songFile = File(Environment.getExternalStorageDirectory(), uri.path!!.split(":".toRegex(), 2).toTypedArray()[1])
|
||||
}
|
||||
if (songFile == null) {
|
||||
val path = getFilePathFromUri(musicService!!, uri)
|
||||
if (path != null)
|
||||
songFile = File(path)
|
||||
}
|
||||
if (songFile == null && uri.path != null) {
|
||||
songFile = File(uri.path)
|
||||
}
|
||||
if (songFile != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(musicService!!, MediaStore.Audio.AudioColumns.DATA + "=?", arrayOf(songFile.absolutePath)
|
||||
)).blockingFirst()
|
||||
}
|
||||
}
|
||||
if (songs != null && !songs.isEmpty()) {
|
||||
openQueue(songs, 0, true)
|
||||
} else {
|
||||
//TODO the file is not listed in the media store
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun getSongIdFromMediaProvider(uri: Uri): String {
|
||||
return DocumentsContract.getDocumentId(uri).split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
|
||||
}
|
||||
|
||||
internal annotation class PlaybackLocation {
|
||||
companion object {
|
||||
val REMOTE = 0
|
||||
val LOCAL = 1
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceBinder internal constructor(private val mCallback: ServiceConnection?) : ServiceConnection {
|
||||
|
||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||
val binder = service as MusicService.MusicBinder
|
||||
musicService = binder.service
|
||||
mCallback?.onServiceConnected(className, service)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(className: ComponentName) {
|
||||
mCallback?.onServiceDisconnected(className)
|
||||
musicService = null
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceToken internal constructor(internal var mWrappedContext: ContextWrapper)
|
||||
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
||||
public class MusicProgressViewUpdateHelper extends Handler {
|
||||
private static final int CMD_REFRESH_PROGRESS_VIEWS = 1;
|
||||
|
||||
private static final int MIN_INTERVAL = 20;
|
||||
private static final int UPDATE_INTERVAL_PLAYING = 1000;
|
||||
private static final int UPDATE_INTERVAL_PAUSED = 500;
|
||||
|
||||
private Callback callback;
|
||||
private int intervalPlaying;
|
||||
private int intervalPaused;
|
||||
|
||||
public void start() {
|
||||
queueNextRefresh(1);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
removeMessages(CMD_REFRESH_PROGRESS_VIEWS);
|
||||
}
|
||||
|
||||
public MusicProgressViewUpdateHelper(Callback callback) {
|
||||
this.callback = callback;
|
||||
this.intervalPlaying = UPDATE_INTERVAL_PLAYING;
|
||||
this.intervalPaused = UPDATE_INTERVAL_PAUSED;
|
||||
}
|
||||
|
||||
public MusicProgressViewUpdateHelper(Callback callback, int intervalPlaying, int intervalPaused) {
|
||||
this.callback = callback;
|
||||
this.intervalPlaying = intervalPlaying;
|
||||
this.intervalPaused = intervalPaused;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(@NonNull Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if (msg.what == CMD_REFRESH_PROGRESS_VIEWS) {
|
||||
queueNextRefresh(refreshProgressViews());
|
||||
}
|
||||
}
|
||||
|
||||
private int refreshProgressViews() {
|
||||
final int progressMillis = MusicPlayerRemote.getSongProgressMillis();
|
||||
final int totalMillis = MusicPlayerRemote.getSongDurationMillis();
|
||||
|
||||
callback.onUpdateProgressViews(progressMillis, totalMillis);
|
||||
|
||||
if (!MusicPlayerRemote.isPlaying()) {
|
||||
return intervalPaused;
|
||||
}
|
||||
|
||||
final int remainingMillis = intervalPlaying - progressMillis % intervalPlaying;
|
||||
|
||||
return Math.max(MIN_INTERVAL, remainingMillis);
|
||||
}
|
||||
|
||||
private void queueNextRefresh(final long delay) {
|
||||
final Message message = obtainMessage(CMD_REFRESH_PROGRESS_VIEWS);
|
||||
removeMessages(CMD_REFRESH_PROGRESS_VIEWS);
|
||||
sendMessageDelayed(message, delay);
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onUpdateProgressViews(int progress, int total);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
|
||||
|
||||
class MusicProgressViewUpdateHelper : Handler {
|
||||
|
||||
private var callback: Callback? = null
|
||||
private var intervalPlaying: Int = 0
|
||||
private var intervalPaused: Int = 0
|
||||
|
||||
fun start() {
|
||||
queueNextRefresh(1)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
|
||||
}
|
||||
|
||||
constructor(callback: Callback) {
|
||||
this.callback = callback
|
||||
this.intervalPlaying = UPDATE_INTERVAL_PLAYING
|
||||
this.intervalPaused = UPDATE_INTERVAL_PAUSED
|
||||
}
|
||||
|
||||
constructor(callback: Callback, intervalPlaying: Int, intervalPaused: Int) {
|
||||
this.callback = callback
|
||||
this.intervalPlaying = intervalPlaying
|
||||
this.intervalPaused = intervalPaused
|
||||
}
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
if (msg.what == CMD_REFRESH_PROGRESS_VIEWS) {
|
||||
queueNextRefresh(refreshProgressViews().toLong())
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshProgressViews(): Int {
|
||||
val progressMillis = MusicPlayerRemote.songProgressMillis
|
||||
val totalMillis = MusicPlayerRemote.songDurationMillis
|
||||
|
||||
callback!!.onUpdateProgressViews(progressMillis, totalMillis)
|
||||
|
||||
if (!MusicPlayerRemote.isPlaying) {
|
||||
return intervalPaused
|
||||
}
|
||||
|
||||
val remainingMillis = intervalPlaying - progressMillis % intervalPlaying
|
||||
|
||||
return Math.max(MIN_INTERVAL, remainingMillis)
|
||||
}
|
||||
|
||||
private fun queueNextRefresh(delay: Long) {
|
||||
val message = obtainMessage(CMD_REFRESH_PROGRESS_VIEWS)
|
||||
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
|
||||
sendMessageDelayed(message, delay)
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onUpdateProgressViews(progress: Int, total: Int)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val CMD_REFRESH_PROGRESS_VIEWS = 1
|
||||
|
||||
private val MIN_INTERVAL = 20
|
||||
private val UPDATE_INTERVAL_PLAYING = 1000
|
||||
private val UPDATE_INTERVAL_PAUSED = 500
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
|
||||
public class PlayPauseButtonOnClickHandler implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (MusicPlayerRemote.isPlaying()) {
|
||||
MusicPlayerRemote.pauseSong();
|
||||
} else {
|
||||
MusicPlayerRemote.resumePlaying();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.view.View
|
||||
|
||||
|
||||
class PlayPauseButtonOnClickHandler : View.OnClickListener {
|
||||
override fun onClick(v: View) {
|
||||
if (MusicPlayerRemote.isPlaying) {
|
||||
MusicPlayerRemote.pauseSong()
|
||||
} else {
|
||||
MusicPlayerRemote.resumePlaying()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
|
||||
|
||||
public class SearchQueryHelper {
|
||||
private static final String TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?";
|
||||
private static final String ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?";
|
||||
private static final String ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?";
|
||||
private static final String AND = " AND ";
|
||||
private static ArrayList<Song> songs = new ArrayList<>();
|
||||
|
||||
public static ArrayList<Song> getSongs() {
|
||||
return songs;
|
||||
}
|
||||
|
||||
public static void setSongs(ArrayList<Song> songs) {
|
||||
SearchQueryHelper.songs = songs;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static ArrayList<Song> getSongs(@NonNull final Context context, @NonNull final Bundle extras) {
|
||||
final String query = extras.getString(SearchManager.QUERY, null);
|
||||
final String artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null);
|
||||
final String albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null);
|
||||
final String titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null);
|
||||
|
||||
ArrayList<Song> songs = new ArrayList<>();
|
||||
if (artistName != null && albumName != null && titleName != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (artistName != null && titleName != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (albumName != null && titleName != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (artistName != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (albumName != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (titleName != null) {
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
return new ArrayList<Song>();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.app.SearchManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import code.name.monkey.retromusic.loaders.SongLoader
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import java.util.*
|
||||
|
||||
|
||||
object SearchQueryHelper {
|
||||
private val TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"
|
||||
private val ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"
|
||||
private val ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"
|
||||
private val AND = " AND "
|
||||
var songs = ArrayList<Song>()
|
||||
|
||||
fun getSongs(context: Context, extras: Bundle): ArrayList<Song> {
|
||||
val query = extras.getString(SearchManager.QUERY, null)
|
||||
val artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null)
|
||||
val albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null)
|
||||
val titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null)
|
||||
|
||||
var songs = ArrayList<Song>()
|
||||
if (artistName != null && albumName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, arrayOf(artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()))).blockingFirst()
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
if (artistName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, arrayOf(artistName.toLowerCase(), titleName.toLowerCase()))).blockingFirst()
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
if (albumName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, arrayOf(albumName.toLowerCase(), titleName.toLowerCase()))).blockingFirst()
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
if (artistName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, arrayOf(artistName.toLowerCase()))).blockingFirst()
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
if (albumName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, arrayOf(albumName.toLowerCase()))).blockingFirst()
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
if (titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, arrayOf(titleName.toLowerCase()))).blockingFirst()
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, arrayOf(query.toLowerCase()))).blockingFirst()
|
||||
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, arrayOf(query.toLowerCase()))).blockingFirst()
|
||||
if (!songs.isEmpty()) {
|
||||
return songs
|
||||
}
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, arrayOf(query.toLowerCase()))).blockingFirst()
|
||||
return if (!songs.isEmpty()) {
|
||||
songs
|
||||
} else ArrayList()
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class ShuffleHelper {
|
||||
|
||||
public static void makeShuffleList(@NonNull List<Song> listToShuffle, final int current) {
|
||||
if (listToShuffle.isEmpty()) return;
|
||||
if (current >= 0) {
|
||||
Song song = listToShuffle.remove(current);
|
||||
Collections.shuffle(listToShuffle);
|
||||
listToShuffle.add(0, song);
|
||||
} else {
|
||||
Collections.shuffle(listToShuffle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
||||
import java.util.Collections
|
||||
|
||||
|
||||
object ShuffleHelper {
|
||||
|
||||
fun makeShuffleList(listToShuffle: MutableList<Song>, current: Int) {
|
||||
if (listToShuffle.isEmpty()) return
|
||||
if (current >= 0) {
|
||||
val song = listToShuffle.removeAt(current)
|
||||
listToShuffle.shuffle()
|
||||
listToShuffle.add(0, song)
|
||||
} else {
|
||||
listToShuffle.shuffle()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Andrew Neal Licensed under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
|
||||
* or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*/
|
||||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
import android.provider.MediaStore;
|
||||
|
||||
/**
|
||||
* Holds all of the sort orders for each list type.
|
||||
*
|
||||
* @author Andrew Neal (andrewdneal@gmail.com)
|
||||
*/
|
||||
public final class SortOrder {
|
||||
|
||||
/**
|
||||
* This class is never instantiated
|
||||
*/
|
||||
public SortOrder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Artist sort order entries.
|
||||
*/
|
||||
public interface ArtistSortOrder {
|
||||
|
||||
/* Artist sort order A-Z */
|
||||
String ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Artist sort order Z-A */
|
||||
String ARTIST_Z_A = ARTIST_A_Z + " DESC";
|
||||
|
||||
/* Artist sort order number of songs */
|
||||
String ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS
|
||||
+ " DESC";
|
||||
|
||||
/* Artist sort order number of albums */
|
||||
String ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS
|
||||
+ " DESC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Album sort order entries.
|
||||
*/
|
||||
public interface AlbumSortOrder {
|
||||
|
||||
/* Album sort order A-Z */
|
||||
String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Album sort order Z-A */
|
||||
String ALBUM_Z_A = ALBUM_A_Z + " DESC";
|
||||
|
||||
/* Album sort order songs */
|
||||
String ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS
|
||||
+ " DESC";
|
||||
|
||||
/* Album sort order artist */
|
||||
String ALBUM_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||
+ ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Album sort order year */
|
||||
String ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Song sort order entries.
|
||||
*/
|
||||
public interface SongSortOrder {
|
||||
|
||||
/* Song sort order A-Z */
|
||||
String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Song sort order Z-A */
|
||||
String SONG_Z_A = SONG_A_Z + " DESC";
|
||||
|
||||
/* Song sort order artist */
|
||||
String SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Song sort order album */
|
||||
String SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Song sort order year */
|
||||
String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
|
||||
|
||||
/* Song sort order duration */
|
||||
String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC";
|
||||
|
||||
/* Song sort order date */
|
||||
String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Album song sort order entries.
|
||||
*/
|
||||
public interface AlbumSongSortOrder {
|
||||
|
||||
/* Album song sort order A-Z */
|
||||
String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Album song sort order Z-A */
|
||||
String SONG_Z_A = SONG_A_Z + " DESC";
|
||||
|
||||
/* Album song sort order track list */
|
||||
String SONG_TRACK_LIST = MediaStore.Audio.Media.TRACK + ", "
|
||||
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Album song sort order duration */
|
||||
String SONG_DURATION = SongSortOrder.SONG_DURATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Artist song sort order entries.
|
||||
*/
|
||||
public interface ArtistSongSortOrder {
|
||||
|
||||
/* Artist song sort order A-Z */
|
||||
String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Artist song sort order Z-A */
|
||||
String SONG_Z_A = SONG_A_Z + " DESC";
|
||||
|
||||
/* Artist song sort order album */
|
||||
String SONG_ALBUM = MediaStore.Audio.Media.ALBUM;
|
||||
|
||||
/* Artist song sort order year */
|
||||
String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
|
||||
|
||||
/* Artist song sort order duration */
|
||||
String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC";
|
||||
|
||||
/* Artist song sort order date */
|
||||
String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Artist album sort order entries.
|
||||
*/
|
||||
public interface ArtistAlbumSortOrder {
|
||||
|
||||
/* Artist album sort order A-Z */
|
||||
String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Artist album sort order Z-A */
|
||||
String ALBUM_Z_A = ALBUM_A_Z + " DESC";
|
||||
|
||||
/* Artist album sort order year */
|
||||
String ALBUM_YEAR = MediaStore.Audio.Media.YEAR
|
||||
+ " DESC";
|
||||
|
||||
/* Artist album sort order year */
|
||||
String ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR
|
||||
+ " ASC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Genre sort order entries.
|
||||
*/
|
||||
public interface GenreSortOrder {
|
||||
|
||||
/* Genre sort order A-Z */
|
||||
String GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER;
|
||||
|
||||
/* Genre sort order Z-A */
|
||||
String ALBUM_Z_A = GENRE_A_Z + " DESC";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Andrew Neal Licensed under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
|
||||
* or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*/
|
||||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.provider.MediaStore
|
||||
|
||||
/**
|
||||
* Holds all of the sort orders for each list type.
|
||||
*
|
||||
* @author Andrew Neal (andrewdneal@gmail.com)
|
||||
*/
|
||||
/**
|
||||
* This class is never instantiated
|
||||
*/
|
||||
class SortOrder {
|
||||
|
||||
/**
|
||||
* Artist sort order entries.
|
||||
*/
|
||||
interface ArtistSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Artist sort order A-Z */
|
||||
val ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Artist sort order Z-A */
|
||||
val ARTIST_Z_A = "$ARTIST_A_Z DESC"
|
||||
|
||||
/* Artist sort order number of songs */
|
||||
val ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + " DESC"
|
||||
|
||||
/* Artist sort order number of albums */
|
||||
val ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + " DESC"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Album sort order entries.
|
||||
*/
|
||||
interface AlbumSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Album sort order A-Z */
|
||||
val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Album sort order Z-A */
|
||||
val ALBUM_Z_A = "$ALBUM_A_Z DESC"
|
||||
|
||||
/* Album sort order songs */
|
||||
val ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + " DESC"
|
||||
|
||||
/* Album sort order artist */
|
||||
val ALBUM_ARTIST = (MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||
+ ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER)
|
||||
|
||||
/* Album sort order year */
|
||||
val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Song sort order entries.
|
||||
*/
|
||||
interface SongSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Song sort order A-Z */
|
||||
val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Song sort order Z-A */
|
||||
val SONG_Z_A = "$SONG_A_Z DESC"
|
||||
|
||||
/* Song sort order artist */
|
||||
val SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Song sort order album */
|
||||
val SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Song sort order year */
|
||||
val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||
|
||||
/* Song sort order duration */
|
||||
val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"
|
||||
|
||||
/* Song sort order date */
|
||||
val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Album song sort order entries.
|
||||
*/
|
||||
interface AlbumSongSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Album song sort order A-Z */
|
||||
val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Album song sort order Z-A */
|
||||
val SONG_Z_A = "$SONG_A_Z DESC"
|
||||
|
||||
/* Album song sort order track list */
|
||||
val SONG_TRACK_LIST = (MediaStore.Audio.Media.TRACK + ", "
|
||||
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
|
||||
|
||||
/* Album song sort order duration */
|
||||
val SONG_DURATION = SongSortOrder.SONG_DURATION
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Artist song sort order entries.
|
||||
*/
|
||||
interface ArtistSongSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Artist song sort order A-Z */
|
||||
val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Artist song sort order Z-A */
|
||||
val SONG_Z_A = "$SONG_A_Z DESC"
|
||||
|
||||
/* Artist song sort order album */
|
||||
val SONG_ALBUM = MediaStore.Audio.Media.ALBUM
|
||||
|
||||
/* Artist song sort order year */
|
||||
val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||
|
||||
/* Artist song sort order duration */
|
||||
val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"
|
||||
|
||||
/* Artist song sort order date */
|
||||
val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Artist album sort order entries.
|
||||
*/
|
||||
interface ArtistAlbumSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Artist album sort order A-Z */
|
||||
val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Artist album sort order Z-A */
|
||||
val ALBUM_Z_A = "$ALBUM_A_Z DESC"
|
||||
|
||||
/* Artist album sort order year */
|
||||
val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||
|
||||
/* Artist album sort order year */
|
||||
val ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR + " ASC"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Genre sort order entries.
|
||||
*/
|
||||
interface GenreSortOrder {
|
||||
companion object {
|
||||
|
||||
/* Genre sort order A-Z */
|
||||
val GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER
|
||||
|
||||
/* Genre sort order Z-A */
|
||||
val ALBUM_Z_A = "$GENRE_A_Z DESC"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper;
|
||||
|
||||
/**
|
||||
* Simple thread safe stop watch.
|
||||
*
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class StopWatch {
|
||||
|
||||
/**
|
||||
* The time the stop watch was last started.
|
||||
*/
|
||||
private long startTime;
|
||||
|
||||
/**
|
||||
* The time elapsed before the current {@link #startTime}.
|
||||
*/
|
||||
private long previousElapsedTime;
|
||||
|
||||
/**
|
||||
* Whether the stop watch is currently running or not.
|
||||
*/
|
||||
private boolean isRunning;
|
||||
|
||||
/**
|
||||
* Starts or continues the stop watch.
|
||||
*
|
||||
* @see #pause()
|
||||
* @see #reset()
|
||||
*/
|
||||
public void start() {
|
||||
synchronized (this) {
|
||||
startTime = System.currentTimeMillis();
|
||||
isRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the stop watch. It can be continued later from {@link #start()}.
|
||||
*
|
||||
* @see #start()
|
||||
* @see #reset()
|
||||
*/
|
||||
public void pause() {
|
||||
synchronized (this) {
|
||||
previousElapsedTime += System.currentTimeMillis() - startTime;
|
||||
isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and resets the stop watch to zero milliseconds.
|
||||
*
|
||||
* @see #start()
|
||||
* @see #pause()
|
||||
*/
|
||||
public void reset() {
|
||||
synchronized (this) {
|
||||
startTime = 0;
|
||||
previousElapsedTime = 0;
|
||||
isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total elapsed time in milliseconds
|
||||
*/
|
||||
public final long getElapsedTime() {
|
||||
synchronized (this) {
|
||||
long currentElapsedTime = 0;
|
||||
if (isRunning) {
|
||||
currentElapsedTime = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
return previousElapsedTime + currentElapsedTime;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%d millis", getElapsedTime());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
/**
|
||||
* Simple thread safe stop watch.
|
||||
*
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
class StopWatch {
|
||||
|
||||
/**
|
||||
* The time the stop watch was last started.
|
||||
*/
|
||||
private var startTime: Long = 0
|
||||
|
||||
/**
|
||||
* The time elapsed before the current [.startTime].
|
||||
*/
|
||||
private var previousElapsedTime: Long = 0
|
||||
|
||||
/**
|
||||
* Whether the stop watch is currently running or not.
|
||||
*/
|
||||
private var isRunning: Boolean = false
|
||||
|
||||
/**
|
||||
* @return the total elapsed time in milliseconds
|
||||
*/
|
||||
val elapsedTime: Long
|
||||
get() = synchronized(this) {
|
||||
var currentElapsedTime: Long = 0
|
||||
if (isRunning) {
|
||||
currentElapsedTime = System.currentTimeMillis() - startTime
|
||||
}
|
||||
return previousElapsedTime + currentElapsedTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or continues the stop watch.
|
||||
*
|
||||
* @see .pause
|
||||
* @see .reset
|
||||
*/
|
||||
fun start() {
|
||||
synchronized(this) {
|
||||
startTime = System.currentTimeMillis()
|
||||
isRunning = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the stop watch. It can be continued later from [.start].
|
||||
*
|
||||
* @see .start
|
||||
* @see .reset
|
||||
*/
|
||||
fun pause() {
|
||||
synchronized(this) {
|
||||
previousElapsedTime += System.currentTimeMillis() - startTime
|
||||
isRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and resets the stop watch to zero milliseconds.
|
||||
*
|
||||
* @see .start
|
||||
* @see .pause
|
||||
*/
|
||||
fun reset() {
|
||||
synchronized(this) {
|
||||
startTime = 0
|
||||
previousElapsedTime = 0
|
||||
isRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return String.format("%d millis", elapsedTime)
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper.menu;
|
||||
|
||||
import android.app.Activity;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.loaders.GenreLoader;
|
||||
import code.name.monkey.retromusic.model.Genre;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
public class GenreMenuHelper {
|
||||
public static boolean handleMenuClick(@NonNull AppCompatActivity activity,
|
||||
@NonNull Genre genre,
|
||||
@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_play:
|
||||
MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true);
|
||||
return true;
|
||||
case R.id.action_play_next:
|
||||
MusicPlayerRemote.playNext(getGenreSongs(activity, genre));
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(getGenreSongs(activity, genre))
|
||||
.show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_add_to_current_playing:
|
||||
MusicPlayerRemote.enqueue(getGenreSongs(activity, genre));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ArrayList<Song> getGenreSongs(@NonNull Activity activity,
|
||||
@NonNull Genre genre) {
|
||||
ArrayList<Song> songs;
|
||||
songs = GenreLoader.getSongs(activity, genre.id).blockingFirst();
|
||||
return songs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package code.name.monkey.retromusic.helper.menu
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.view.MenuItem
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import code.name.monkey.retromusic.loaders.GenreLoader
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
object GenreMenuHelper {
|
||||
fun handleMenuClick(activity: AppCompatActivity,
|
||||
genre: Genre,
|
||||
item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> {
|
||||
MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true)
|
||||
return true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(getGenreSongs(activity, genre))
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(getGenreSongs(activity, genre))
|
||||
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_current_playing -> {
|
||||
MusicPlayerRemote.enqueue(getGenreSongs(activity, genre))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getGenreSongs(activity: Activity,
|
||||
genre: Genre): ArrayList<Song> {
|
||||
val songs: ArrayList<Song>
|
||||
songs = GenreLoader.getSongs(activity, genre.id).blockingFirst()
|
||||
return songs
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper.menu;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.RetroApplication;
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
||||
import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog;
|
||||
import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog;
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
|
||||
import code.name.monkey.retromusic.misc.WeakContextAsyncTask;
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist;
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
||||
|
||||
|
||||
public class PlaylistMenuHelper {
|
||||
|
||||
public static boolean handleMenuClick(@NonNull AppCompatActivity activity,
|
||||
@NonNull final Playlist playlist, @NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_play:
|
||||
MusicPlayerRemote.openQueue(getPlaylistSongs(activity, playlist), 9, true);
|
||||
return true;
|
||||
case R.id.action_play_next:
|
||||
MusicPlayerRemote.playNext(getPlaylistSongs(activity, playlist));
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(getPlaylistSongs(activity, playlist))
|
||||
.show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_add_to_current_playing:
|
||||
MusicPlayerRemote.enqueue(getPlaylistSongs(activity, playlist));
|
||||
return true;
|
||||
case R.id.action_rename_playlist:
|
||||
RenamePlaylistDialog.create(playlist.id)
|
||||
.show(activity.getSupportFragmentManager(), "RENAME_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_delete_playlist:
|
||||
DeletePlaylistDialog.create(playlist)
|
||||
.show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_save_playlist:
|
||||
new SavePlaylistAsyncTask(activity).execute(playlist);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ArrayList<Song> getPlaylistSongs(@NonNull Activity activity,
|
||||
@NonNull Playlist playlist) {
|
||||
ArrayList<Song> songs;
|
||||
if (playlist instanceof AbsCustomPlaylist) {
|
||||
songs = ((AbsCustomPlaylist) playlist).getSongs(activity).blockingFirst();
|
||||
} else {
|
||||
songs = PlaylistSongsLoader.getPlaylistSongList(activity, playlist).blockingFirst();
|
||||
}
|
||||
return songs;
|
||||
}
|
||||
|
||||
private static class SavePlaylistAsyncTask extends WeakContextAsyncTask<Playlist, String, String> {
|
||||
SavePlaylistAsyncTask(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Playlist... params) {
|
||||
return String.format(RetroApplication.getInstance().getApplicationContext().getString(R.string
|
||||
.saved_playlist_to), PlaylistsUtil.savePlaylist(RetroApplication.getInstance().getApplicationContext(), params[0]).blockingFirst());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String string) {
|
||||
super.onPostExecute(string);
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
Toast.makeText(context, string, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package code.name.monkey.retromusic.helper.menu
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.RetroApplication
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||
import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog
|
||||
import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
|
||||
import code.name.monkey.retromusic.misc.WeakContextAsyncTask
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||
|
||||
|
||||
object PlaylistMenuHelper {
|
||||
|
||||
fun handleMenuClick(activity: AppCompatActivity,
|
||||
playlist: Playlist, item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> {
|
||||
MusicPlayerRemote.openQueue(getPlaylistSongs(activity, playlist), 9, true)
|
||||
return true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(getPlaylistSongs(activity, playlist))
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(getPlaylistSongs(activity, playlist))
|
||||
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_current_playing -> {
|
||||
MusicPlayerRemote.enqueue(getPlaylistSongs(activity, playlist))
|
||||
return true
|
||||
}
|
||||
R.id.action_rename_playlist -> {
|
||||
RenamePlaylistDialog.create(playlist.id.toLong())
|
||||
.show(activity.supportFragmentManager, "RENAME_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_delete_playlist -> {
|
||||
DeletePlaylistDialog.create(playlist)
|
||||
.show(activity.supportFragmentManager, "DELETE_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_save_playlist -> {
|
||||
SavePlaylistAsyncTask(activity).execute(playlist)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getPlaylistSongs(activity: Activity,
|
||||
playlist: Playlist): ArrayList<Song> {
|
||||
val songs: ArrayList<Song>
|
||||
if (playlist is AbsCustomPlaylist) {
|
||||
songs = playlist.getSongs(activity).blockingFirst()
|
||||
} else {
|
||||
songs = PlaylistSongsLoader.getPlaylistSongList(activity, playlist).blockingFirst()
|
||||
}
|
||||
return songs
|
||||
}
|
||||
|
||||
private class SavePlaylistAsyncTask internal constructor(context: Context) : WeakContextAsyncTask<Playlist, String, String>(context) {
|
||||
|
||||
override fun doInBackground(vararg params: Playlist): String {
|
||||
return String.format(RetroApplication.instance.applicationContext.getString(R.string
|
||||
.saved_playlist_to), PlaylistsUtil.savePlaylist(RetroApplication.instance.applicationContext, params[0]).blockingFirst())
|
||||
}
|
||||
|
||||
override fun onPostExecute(string: String) {
|
||||
super.onPostExecute(string)
|
||||
val context = context
|
||||
if (context != null) {
|
||||
Toast.makeText(context, string, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper.menu;
|
||||
|
||||
import android.content.Intent;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog;
|
||||
import code.name.monkey.retromusic.dialogs.SongDetailDialog;
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||
import code.name.monkey.retromusic.interfaces.PaletteColorHolder;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity;
|
||||
import code.name.monkey.retromusic.ui.activities.tageditor.SongTagEditorActivity;
|
||||
import code.name.monkey.retromusic.util.MusicUtil;
|
||||
import code.name.monkey.retromusic.util.NavigationUtil;
|
||||
|
||||
|
||||
public class SongMenuHelper {
|
||||
public static final int MENU_RES = R.menu.menu_item_song;
|
||||
|
||||
public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull Song song, int menuItemId) {
|
||||
switch (menuItemId) {
|
||||
case R.id.action_set_as_ringtone:
|
||||
MusicUtil.setRingtone(activity, song.id);
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
activity.startActivity(Intent.createChooser(MusicUtil.createShareSongFileIntent(song, activity), null));
|
||||
return true;
|
||||
case R.id.action_delete_from_device:
|
||||
DeleteSongsDialog.create(song).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(song).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_play_next:
|
||||
MusicPlayerRemote.playNext(song);
|
||||
return true;
|
||||
case R.id.action_add_to_current_playing:
|
||||
MusicPlayerRemote.enqueue(song);
|
||||
return true;
|
||||
case R.id.action_tag_editor:
|
||||
Intent tagEditorIntent = new Intent(activity, SongTagEditorActivity.class);
|
||||
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id);
|
||||
if (activity instanceof PaletteColorHolder)
|
||||
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_PALETTE, ((PaletteColorHolder) activity).getPaletteColor());
|
||||
activity.startActivity(tagEditorIntent);
|
||||
return true;
|
||||
case R.id.action_details:
|
||||
SongDetailDialog.create(song).show(activity.getSupportFragmentManager(), "SONG_DETAILS");
|
||||
return true;
|
||||
case R.id.action_go_to_album:
|
||||
NavigationUtil.goToAlbum(activity, song.albumId);
|
||||
return true;
|
||||
case R.id.action_go_to_artist:
|
||||
NavigationUtil.goToArtist(activity, song.artistId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static abstract class OnClickSongMenu implements View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
||||
private AppCompatActivity activity;
|
||||
|
||||
protected OnClickSongMenu(@NonNull AppCompatActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public int getMenuRes() {
|
||||
return MENU_RES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
PopupMenu popupMenu = new PopupMenu(activity, v);
|
||||
popupMenu.inflate(getMenuRes());
|
||||
popupMenu.setOnMenuItemClickListener(this);
|
||||
popupMenu.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
return handleMenuClick(activity, getSong(), item.getItemId());
|
||||
}
|
||||
|
||||
public abstract Song getSong();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package code.name.monkey.retromusic.helper.menu
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
||||
import code.name.monkey.retromusic.dialogs.SongDetailDialog
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity
|
||||
import code.name.monkey.retromusic.ui.activities.tageditor.SongTagEditorActivity
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.NavigationUtil
|
||||
|
||||
|
||||
object SongMenuHelper {
|
||||
val MENU_RES = R.menu.menu_item_song
|
||||
|
||||
fun handleMenuClick(activity: FragmentActivity, song: Song, menuItemId: Int): Boolean {
|
||||
when (menuItemId) {
|
||||
R.id.action_set_as_ringtone -> {
|
||||
MusicUtil.setRingtone(activity, song.id)
|
||||
return true
|
||||
}
|
||||
R.id.action_share -> {
|
||||
activity.startActivity(Intent.createChooser(MusicUtil.createShareSongFileIntent(song, activity), null))
|
||||
return true
|
||||
}
|
||||
R.id.action_delete_from_device -> {
|
||||
DeleteSongsDialog.create(song).show(activity.supportFragmentManager, "DELETE_SONGS")
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(song).show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(song)
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_current_playing -> {
|
||||
MusicPlayerRemote.enqueue(song)
|
||||
return true
|
||||
}
|
||||
R.id.action_tag_editor -> {
|
||||
val tagEditorIntent = Intent(activity, SongTagEditorActivity::class.java)
|
||||
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id)
|
||||
if (activity is PaletteColorHolder)
|
||||
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_PALETTE, (activity as PaletteColorHolder).paletteColor)
|
||||
activity.startActivity(tagEditorIntent)
|
||||
return true
|
||||
}
|
||||
R.id.action_details -> {
|
||||
SongDetailDialog.create(song).show(activity.supportFragmentManager, "SONG_DETAILS")
|
||||
return true
|
||||
}
|
||||
R.id.action_go_to_album -> {
|
||||
NavigationUtil.goToAlbum(activity, song.albumId)
|
||||
return true
|
||||
}
|
||||
R.id.action_go_to_artist -> {
|
||||
NavigationUtil.goToArtist(activity, song.artistId)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
abstract class OnClickSongMenu protected constructor(private val activity: AppCompatActivity) : View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
||||
|
||||
open val menuRes: Int
|
||||
get() = MENU_RES
|
||||
|
||||
abstract val song: Song
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val popupMenu = PopupMenu(activity, v)
|
||||
popupMenu.inflate(menuRes)
|
||||
popupMenu.setOnMenuItemClickListener(this)
|
||||
popupMenu.show()
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
return handleMenuClick(activity, song, item.itemId)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package code.name.monkey.retromusic.helper.menu;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog;
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||
|
||||
|
||||
|
||||
public class SongsMenuHelper {
|
||||
public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull ArrayList<Song> songs, int menuItemId) {
|
||||
switch (menuItemId) {
|
||||
case R.id.action_play_next:
|
||||
MusicPlayerRemote.playNext(songs);
|
||||
return true;
|
||||
case R.id.action_add_to_current_playing:
|
||||
MusicPlayerRemote.enqueue(songs);
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(songs).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_delete_from_device:
|
||||
DeleteSongsDialog.create(songs).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package code.name.monkey.retromusic.helper.menu
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import java.util.*
|
||||
|
||||
|
||||
object SongsMenuHelper {
|
||||
fun handleMenuClick(activity: FragmentActivity, songs: ArrayList<Song>, menuItemId: Int): Boolean {
|
||||
when (menuItemId) {
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(songs)
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_current_playing -> {
|
||||
MusicPlayerRemote.enqueue(songs)
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(songs).show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_delete_from_device -> {
|
||||
DeleteSongsDialog.create(songs).show(activity.supportFragmentManager, "DELETE_SONGS")
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package code.name.monkey.retromusic.interfaces;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
|
||||
|
||||
public interface CabHolder {
|
||||
|
||||
@NonNull
|
||||
MaterialCab openCab(final int menuRes, final MaterialCab.Callback callback);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package code.name.monkey.retromusic.interfaces
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab
|
||||
|
||||
|
||||
interface CabHolder {
|
||||
|
||||
fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package code.name.monkey.retromusic.interfaces;
|
||||
|
||||
import android.media.audiofx.BassBoost;
|
||||
import android.media.audiofx.Equalizer;
|
||||
import android.media.audiofx.Virtualizer;
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
public interface EqualizerInterface {
|
||||
int getBandLevelLow();
|
||||
|
||||
int getBandLevelHigh();
|
||||
|
||||
int getNumberOfBands();
|
||||
|
||||
int getCenterFreq(int band);
|
||||
|
||||
int getBandLevel(int band);
|
||||
|
||||
void setBandLevel(int band, int level);
|
||||
|
||||
boolean isBassBoostEnabled();
|
||||
|
||||
void setBassBoostEnabled(boolean isEnabled);
|
||||
|
||||
int getBassBoostStrength();
|
||||
|
||||
void setBassBoostStrength(int strength);
|
||||
|
||||
boolean isVirtualizerEnabled();
|
||||
|
||||
void setVirtualizerEnabled(boolean isEnabled);
|
||||
|
||||
int getVirtualizerStrength();
|
||||
|
||||
void setVirtualizerStrength(int strength);
|
||||
|
||||
boolean isRunning();
|
||||
|
||||
Equalizer getEqualizer();
|
||||
|
||||
BassBoost getBassBoost();
|
||||
|
||||
Virtualizer getVirtualizer();
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package code.name.monkey.retromusic.interfaces
|
||||
|
||||
import android.media.audiofx.BassBoost
|
||||
import android.media.audiofx.Equalizer
|
||||
import android.media.audiofx.Virtualizer
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
interface EqualizerInterface {
|
||||
val bandLevelLow: Int
|
||||
|
||||
val bandLevelHigh: Int
|
||||
|
||||
val numberOfBands: Int
|
||||
|
||||
var isBassBoostEnabled: Boolean
|
||||
|
||||
var bassBoostStrength: Int
|
||||
|
||||
var isVirtualizerEnabled: Boolean
|
||||
|
||||
var virtualizerStrength: Int
|
||||
|
||||
val isRunning: Boolean
|
||||
|
||||
val equalizer: Equalizer
|
||||
|
||||
val bassBoost: BassBoost
|
||||
|
||||
val virtualizer: Virtualizer
|
||||
|
||||
fun getCenterFreq(band: Int): Int
|
||||
|
||||
fun getBandLevel(band: Int): Int
|
||||
|
||||
fun setBandLevel(band: Int, level: Int)
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package code.name.monkey.retromusic.interfaces;
|
||||
|
||||
|
||||
public interface LoaderIds {
|
||||
int FOLDERS_FRAGMENT = 5;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package code.name.monkey.retromusic.interfaces
|
||||
|
||||
|
||||
interface LoaderIds {
|
||||
companion object {
|
||||
val FOLDERS_FRAGMENT = 5
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package code.name.monkey.retromusic.interfaces;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 14/08/17.
|
||||
*/
|
||||
|
||||
public interface MainActivityFragmentCallbacks {
|
||||
boolean handleBackPress();
|
||||
|
||||
//void selectedFragment(Fragment fragment);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package code.name.monkey.retromusic.interfaces
|
||||
|
||||
/**
|
||||
* Created by hemanths on 14/08/17.
|
||||
*/
|
||||
|
||||
interface MainActivityFragmentCallbacks {
|
||||
fun handleBackPress(): Boolean
|
||||
|
||||
//void selectedFragment(Fragment fragment);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package code.name.monkey.retromusic.interfaces;
|
||||
|
||||
|
||||
public interface MusicServiceEventListener {
|
||||
void onServiceConnected();
|
||||
|
||||
void onServiceDisconnected();
|
||||
|
||||
void onQueueChanged();
|
||||
|
||||
void onPlayingMetaChanged();
|
||||
|
||||
void onPlayStateChanged();
|
||||
|
||||
void onRepeatModeChanged();
|
||||
|
||||
void onShuffleModeChanged();
|
||||
|
||||
void onMediaStoreChanged();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package code.name.monkey.retromusic.interfaces
|
||||
|
||||
|
||||
interface MusicServiceEventListener {
|
||||
fun onServiceConnected()
|
||||
|
||||
fun onServiceDisconnected()
|
||||
|
||||
fun onQueueChanged()
|
||||
|
||||
fun onPlayingMetaChanged()
|
||||
|
||||
fun onPlayStateChanged()
|
||||
|
||||
fun onRepeatModeChanged()
|
||||
|
||||
fun onShuffleModeChanged()
|
||||
|
||||
fun onMediaStoreChanged()
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package code.name.monkey.retromusic.interfaces;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
/**
|
||||
* @author Aidan Follestad (afollestad)
|
||||
*/
|
||||
public interface PaletteColorHolder {
|
||||
|
||||
@ColorInt
|
||||
int getPaletteColor();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package code.name.monkey.retromusic.interfaces
|
||||
|
||||
import androidx.annotation.ColorInt
|
||||
|
||||
/**
|
||||
* @author Aidan Follestad (afollestad)
|
||||
*/
|
||||
interface PaletteColorHolder {
|
||||
|
||||
@get:ColorInt
|
||||
val paletteColor: Int
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.MediaStore.Audio.AudioColumns;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.model.Album;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.Observable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 11/08/17.
|
||||
*/
|
||||
|
||||
public class AlbumLoader {
|
||||
|
||||
public static Observable<ArrayList<Album>> getAllAlbums(@NonNull Context context) {
|
||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
null,
|
||||
null,
|
||||
getSongLoaderSortOrder(context))
|
||||
);
|
||||
|
||||
return splitIntoAlbums(songs);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Album>> getAlbums(@NonNull final Context context,
|
||||
String query) {
|
||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ALBUM + " LIKE ?",
|
||||
new String[]{"%" + query + "%"},
|
||||
getSongLoaderSortOrder(context))
|
||||
);
|
||||
return splitIntoAlbums(songs);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Album> getAlbum(@NonNull final Context context, int albumId) {
|
||||
return Observable.create(e -> {
|
||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion
|
||||
.makeSongCursor(context, AudioColumns.ALBUM_ID + "=?",
|
||||
new String[]{String.valueOf(albumId)}, getSongLoaderSortOrder(context)));
|
||||
songs.subscribe(songs1 -> {
|
||||
e.onNext(new Album(songs1));
|
||||
e.onComplete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Album>> splitIntoAlbums(
|
||||
@Nullable final Observable<ArrayList<Song>> songs) {
|
||||
return Observable.create(e -> {
|
||||
ArrayList<Album> albums = new ArrayList<>();
|
||||
if (songs != null) {
|
||||
songs.subscribe(songs1 -> {
|
||||
for (Song song : songs1) {
|
||||
getOrCreateAlbum(albums, song.albumId).subscribe(album -> album.songs.add(song));
|
||||
}
|
||||
});
|
||||
}
|
||||
e.onNext(albums);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static ArrayList<Album> splitIntoAlbums(@Nullable final ArrayList<Song> songs) {
|
||||
ArrayList<Album> albums = new ArrayList<>();
|
||||
if (songs != null) {
|
||||
for (Song song : songs) {
|
||||
getOrCreateAlbum(albums, song.albumId).subscribe(album -> album.songs.add(song));
|
||||
}
|
||||
}
|
||||
return albums;
|
||||
}
|
||||
|
||||
private static Observable<Album> getOrCreateAlbum(ArrayList<Album> albums, int albumId) {
|
||||
return Observable.create(e -> {
|
||||
for (Album album : albums) {
|
||||
if (!album.songs.isEmpty() && album.songs.get(0).albumId == albumId) {
|
||||
e.onNext(album);
|
||||
e.onComplete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Album album = new Album();
|
||||
albums.add(album);
|
||||
e.onNext(album);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
public static String getSongLoaderSortOrder(Context context) {
|
||||
return PreferenceUtil.getInstance().getAlbumSortOrder() + ", " +
|
||||
//PreferenceUtil.getInstance().getAlbumSongSortOrder() + "," +
|
||||
PreferenceUtil.getInstance().getAlbumDetailSongSortOrder();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import io.reactivex.Observable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by hemanths on 11/08/17.
|
||||
*/
|
||||
|
||||
open class AlbumLoader {
|
||||
companion object {
|
||||
fun getAllAlbums(context: Context): Observable<ArrayList<Album>> {
|
||||
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
context, null, null,
|
||||
getSongLoaderSortOrder())
|
||||
)
|
||||
|
||||
return splitIntoAlbums(songs)
|
||||
}
|
||||
|
||||
fun getAlbums(context: Context,
|
||||
query: String): Observable<ArrayList<Album>> {
|
||||
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ALBUM + " LIKE ?",
|
||||
arrayOf("%$query%"),
|
||||
getSongLoaderSortOrder())
|
||||
)
|
||||
return splitIntoAlbums(songs)
|
||||
}
|
||||
|
||||
fun getAlbum(context: Context, albumId: Int): Observable<Album> {
|
||||
return Observable.create { e ->
|
||||
val songs = SongLoader.getSongs(SongLoader
|
||||
.makeSongCursor(context, AudioColumns.ALBUM_ID + "=?",
|
||||
arrayOf(albumId.toString()), getSongLoaderSortOrder()))
|
||||
songs.subscribe { songs1 ->
|
||||
e.onNext(Album(songs1))
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun splitIntoAlbums(
|
||||
songs: Observable<ArrayList<Song>>?): Observable<ArrayList<Album>> {
|
||||
return Observable.create { e ->
|
||||
val albums = ArrayList<Album>()
|
||||
songs?.subscribe { songs1 ->
|
||||
for (song in songs1) {
|
||||
getOrCreateAlbum(albums, song.albumId).subscribe { album -> album.songs!!.add(song) }
|
||||
}
|
||||
}
|
||||
e.onNext(albums)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun splitIntoAlbums(songs: ArrayList<Song>?): ArrayList<Album> {
|
||||
val albums = ArrayList<Album>()
|
||||
if (songs != null) {
|
||||
for (song in songs) {
|
||||
getOrCreateAlbum(albums, song.albumId).subscribe { album -> album.songs!!.add(song) }
|
||||
}
|
||||
}
|
||||
return albums
|
||||
}
|
||||
|
||||
private fun getOrCreateAlbum(albums: ArrayList<Album>, albumId: Int): Observable<Album> {
|
||||
return Observable.create { e ->
|
||||
for (album in albums) {
|
||||
if (!album.songs!!.isEmpty() && album.songs[0].albumId == albumId) {
|
||||
e.onNext(album)
|
||||
e.onComplete()
|
||||
return@create
|
||||
}
|
||||
}
|
||||
val album = Album()
|
||||
albums.add(album)
|
||||
e.onNext(album)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSongLoaderSortOrder(): String {
|
||||
return PreferenceUtil.getInstance().albumSortOrder + ", " +
|
||||
//PreferenceUtil.getInstance().getAlbumSongSortOrder() + "," +
|
||||
PreferenceUtil.getInstance().albumDetailSongSortOrder
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.MediaStore.Audio.AudioColumns;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.model.Album;
|
||||
import code.name.monkey.retromusic.model.Artist;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
public class ArtistLoader {
|
||||
private static String getSongLoaderSortOrder(Context context) {
|
||||
return PreferenceUtil.getInstance().getArtistSortOrder() + ", " +
|
||||
PreferenceUtil.getInstance().getArtistAlbumSortOrder() + ", " +
|
||||
PreferenceUtil.getInstance().getAlbumDetailSongSortOrder() + ", " +
|
||||
PreferenceUtil.getInstance().getArtistDetailSongSortOrder();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Artist> getArtist(@NonNull final Context context, int artistId) {
|
||||
return Observable.create(e -> SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST_ID + "=?",
|
||||
new String[]{String.valueOf(artistId)},
|
||||
getSongLoaderSortOrder(context)))
|
||||
.subscribe(songs -> {
|
||||
Artist artist = new Artist(AlbumLoader.splitIntoAlbums(songs));
|
||||
e.onNext(artist);
|
||||
e.onComplete();
|
||||
}));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Artist>> getAllArtists(@NonNull final Context context) {
|
||||
return Observable.create(e -> SongLoader.Companion
|
||||
.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
null,
|
||||
null,
|
||||
getSongLoaderSortOrder(context))
|
||||
).subscribe(songs -> {
|
||||
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)));
|
||||
e.onComplete();
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Artist>> getArtists(@NonNull final Context context, String query) {
|
||||
return Observable.create(e -> SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST + " LIKE ?",
|
||||
new String[]{"%" + query + "%"},
|
||||
getSongLoaderSortOrder(context))
|
||||
).subscribe(songs -> {
|
||||
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)));
|
||||
e.onComplete();
|
||||
}));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static ArrayList<Artist> splitIntoArtists(@Nullable final ArrayList<Album> albums) {
|
||||
ArrayList<Artist> artists = new ArrayList<>();
|
||||
if (albums != null) {
|
||||
for (Album album : albums) {
|
||||
getOrCreateArtist(artists, album.getArtistId()).albums.add(album);
|
||||
}
|
||||
}
|
||||
return artists;
|
||||
}
|
||||
|
||||
private static Artist getOrCreateArtist(ArrayList<Artist> artists, int artistId) {
|
||||
for (Artist artist : artists) {
|
||||
if (!artist.albums.isEmpty() && !artist.albums.get(0).songs.isEmpty() && artist.albums.get(0).songs.get(0).artistId == artistId) {
|
||||
return artist;
|
||||
}
|
||||
}
|
||||
Artist album = new Artist();
|
||||
artists.add(album);
|
||||
return album;
|
||||
}
|
||||
|
||||
public static Observable<ArrayList<Artist>> splitIntoArtists(Observable<ArrayList<Album>> albums) {
|
||||
return Observable.create(e -> {
|
||||
ArrayList<Artist> artists = new ArrayList<>();
|
||||
albums.subscribe(localAlbums -> {
|
||||
if (localAlbums != null) {
|
||||
for (Album album : localAlbums) {
|
||||
getOrCreateArtist(artists, album.getArtistId()).albums.add(album);
|
||||
}
|
||||
}
|
||||
e.onNext(artists);
|
||||
e.onComplete();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import io.reactivex.Observable
|
||||
|
||||
object ArtistLoader {
|
||||
private fun getSongLoaderSortOrder(): String {
|
||||
return PreferenceUtil.getInstance().artistSortOrder + ", " +
|
||||
PreferenceUtil.getInstance().artistAlbumSortOrder + ", " +
|
||||
PreferenceUtil.getInstance().albumDetailSongSortOrder + ", " +
|
||||
PreferenceUtil.getInstance().artistDetailSongSortOrder
|
||||
}
|
||||
|
||||
fun getArtist(context: Context, artistId: Int): Observable<Artist> {
|
||||
return Observable.create { e ->
|
||||
SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST_ID + "=?",
|
||||
arrayOf(artistId.toString()),
|
||||
getSongLoaderSortOrder()))
|
||||
.subscribe { songs ->
|
||||
val artist = Artist(AlbumLoader.splitIntoAlbums(songs))
|
||||
e.onNext(artist)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllArtists(context: Context): Observable<ArrayList<Artist>> {
|
||||
return Observable.create { e ->
|
||||
SongLoader
|
||||
.getSongs(SongLoader.makeSongCursor(
|
||||
context, null, null,
|
||||
getSongLoaderSortOrder())
|
||||
).subscribe { songs ->
|
||||
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)))
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getArtists(context: Context, query: String): Observable<ArrayList<Artist>> {
|
||||
return Observable.create { e ->
|
||||
SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST + " LIKE ?",
|
||||
arrayOf("%$query%"),
|
||||
getSongLoaderSortOrder())
|
||||
).subscribe { songs ->
|
||||
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)))
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun splitIntoArtists(albums: ArrayList<Album>?): ArrayList<Artist> {
|
||||
val artists = ArrayList<Artist>()
|
||||
if (albums != null) {
|
||||
for (album in albums) {
|
||||
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
||||
}
|
||||
}
|
||||
return artists
|
||||
}
|
||||
|
||||
private fun getOrCreateArtist(artists: ArrayList<Artist>, artistId: Int): Artist {
|
||||
for (artist in artists) {
|
||||
if (!artist.albums!!.isEmpty() && !artist.albums[0].songs!!.isEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
|
||||
return artist
|
||||
}
|
||||
}
|
||||
val album = Artist()
|
||||
artists.add(album)
|
||||
return album
|
||||
}
|
||||
|
||||
fun splitIntoArtists(albums: Observable<ArrayList<Album>>): Observable<ArrayList<Artist>> {
|
||||
return Observable.create { e ->
|
||||
val artists = ArrayList<Artist>()
|
||||
albums.subscribe { localAlbums ->
|
||||
if (localAlbums != null) {
|
||||
for (album in localAlbums) {
|
||||
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
||||
}
|
||||
}
|
||||
e.onNext(artists)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.MediaStore;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
|
||||
public class ArtistSongLoader extends SongLoader {
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getArtistSongList(@NonNull final Context context, final int artistId) {
|
||||
return Companion.getSongs(makeArtistSongCursor(context, artistId));
|
||||
}
|
||||
|
||||
public static Cursor makeArtistSongCursor(@NonNull final Context context, final int artistId) {
|
||||
try {
|
||||
return Companion.makeSongCursor(
|
||||
context,
|
||||
MediaStore.Audio.AudioColumns.ARTIST_ID + "=?",
|
||||
new String[]{
|
||||
String.valueOf(artistId)
|
||||
},
|
||||
PreferenceUtil.getInstance().getArtistSongSortOrder()
|
||||
);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.MediaStore.Audio.Genres;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.model.Genre;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
public class GenreLoader {
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Genre>> getAllGenres(@NonNull final Context context) {
|
||||
return getGenresFromCursor(context, makeGenreCursor(context));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getSongs(@NonNull final Context context, final int genreId) {
|
||||
// The genres table only stores songs that have a genre specified,
|
||||
// so we need to get songs without a genre a different way.
|
||||
if (genreId == -1) {
|
||||
return getSongsWithNoGenre(context);
|
||||
}
|
||||
|
||||
return SongLoader.Companion.getSongs(makeGenreSongCursor(context, genreId));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Genre getGenreFromCursor(@NonNull Context context, @NonNull final Cursor cursor) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String name = cursor.getString(1);
|
||||
final int songCount = getSongs(context, id).blockingFirst().size();
|
||||
return new Genre(id, name, songCount);
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Observable<ArrayList<Song>> getSongsWithNoGenre(@NonNull final Context context) {
|
||||
String selection = BaseColumns._ID + " NOT IN " +
|
||||
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)";
|
||||
return SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, selection, null));
|
||||
}
|
||||
|
||||
private static boolean hasSongsWithNoGenre(@NonNull final Context context) {
|
||||
final Cursor allSongsCursor = SongLoader.Companion.makeSongCursor(context, null, null);
|
||||
final Cursor allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context);
|
||||
|
||||
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean hasSongsWithNoGenre = allSongsCursor.getCount() > allSongsWithGenreCursor.getCount();
|
||||
allSongsCursor.close();
|
||||
allSongsWithGenreCursor.close();
|
||||
return hasSongsWithNoGenre;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Cursor makeAllSongsWithGenreCursor(@NonNull final Context context) {
|
||||
try {
|
||||
return context.getContentResolver().query(
|
||||
Uri.parse("content://media/external/audio/genres/all/members"),
|
||||
new String[]{Genres.Members.AUDIO_ID}, null, null, null);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Cursor makeGenreSongCursor(@NonNull final Context context, int genreId) {
|
||||
try {
|
||||
return context.getContentResolver().query(
|
||||
Genres.Members.getContentUri("external", genreId),
|
||||
SongLoader.Companion.getBASE_PROJECTION(), SongLoader.BASE_SELECTION, null, PreferenceUtil.getInstance().getSongSortOrder());
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Observable<ArrayList<Genre>> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) {
|
||||
return Observable.create(e -> {
|
||||
final ArrayList<Genre> genres = new ArrayList<>();
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
Genre genre = getGenreFromCursor(context, cursor);
|
||||
if (genre.songCount > 0) {
|
||||
genres.add(genre);
|
||||
} else {
|
||||
// try to remove the empty genre from the media store
|
||||
try {
|
||||
context.getContentResolver().delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + " == " + genre.id, null);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
// nothing we can do then
|
||||
}
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
e.onNext(genres);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static Cursor makeGenreCursor(@NonNull final Context context) {
|
||||
final String[] projection = new String[]{
|
||||
Genres._ID,
|
||||
Genres.NAME
|
||||
};
|
||||
|
||||
try {
|
||||
return context.getContentResolver().query(
|
||||
Genres.EXTERNAL_CONTENT_URI,
|
||||
projection, null, null, PreferenceUtil.getInstance().getGenreSortOrder());
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore.Audio.Genres
|
||||
import code.name.monkey.retromusic.Constants.BASE_PROJECTION
|
||||
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import io.reactivex.Observable
|
||||
import java.util.*
|
||||
|
||||
object GenreLoader {
|
||||
|
||||
fun getAllGenres(context: Context): Observable<ArrayList<Genre>> {
|
||||
return getGenresFromCursor(context, makeGenreCursor(context))
|
||||
}
|
||||
|
||||
fun getSongs(context: Context, genreId: Int): Observable<ArrayList<Song>> {
|
||||
// The genres table only stores songs that have a genre specified,
|
||||
// so we need to get songs without a genre a different way.
|
||||
return if (genreId == -1) {
|
||||
getSongsWithNoGenre(context)
|
||||
} else SongLoader.getSongs(makeGenreSongCursor(context, genreId))
|
||||
|
||||
}
|
||||
|
||||
private fun getGenreFromCursor(context: Context, cursor: Cursor): Genre {
|
||||
val id = cursor.getInt(0)
|
||||
val name = cursor.getString(1)
|
||||
val songCount = getSongs(context, id).blockingFirst().size
|
||||
return Genre(id, name, songCount)
|
||||
|
||||
}
|
||||
|
||||
private fun getSongsWithNoGenre(context: Context): Observable<ArrayList<Song>> {
|
||||
val selection = BaseColumns._ID + " NOT IN " +
|
||||
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)"
|
||||
return SongLoader.getSongs(SongLoader.makeSongCursor(context, selection, null))
|
||||
}
|
||||
|
||||
private fun hasSongsWithNoGenre(context: Context): Boolean {
|
||||
val allSongsCursor = SongLoader.makeSongCursor(context, null, null)
|
||||
val allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context)
|
||||
|
||||
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val hasSongsWithNoGenre = allSongsCursor.count > allSongsWithGenreCursor.count
|
||||
allSongsCursor.close()
|
||||
allSongsWithGenreCursor.close()
|
||||
return hasSongsWithNoGenre
|
||||
}
|
||||
|
||||
private fun makeAllSongsWithGenreCursor(context: Context): Cursor? {
|
||||
try {
|
||||
return context.contentResolver.query(
|
||||
Uri.parse("content://media/external/audio/genres/all/members"),
|
||||
arrayOf(Genres.Members.AUDIO_ID), null, null, null)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun makeGenreSongCursor(context: Context, genreId: Int): Cursor? {
|
||||
try {
|
||||
return context.contentResolver.query(
|
||||
Genres.Members.getContentUri("external", genreId.toLong()),
|
||||
BASE_PROJECTION, BASE_SELECTION, null, PreferenceUtil.getInstance().songSortOrder)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getGenresFromCursor(context: Context, cursor: Cursor?): Observable<ArrayList<Genre>> {
|
||||
return Observable.create { e ->
|
||||
val genres = ArrayList<Genre>()
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
val genre = getGenreFromCursor(context, cursor)
|
||||
if (genre.songCount > 0) {
|
||||
genres.add(genre)
|
||||
} else {
|
||||
// try to remove the empty genre from the media store
|
||||
try {
|
||||
context.contentResolver.delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + " == " + genre.id, null)
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
// nothing we can do then
|
||||
}
|
||||
|
||||
}
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
cursor.close()
|
||||
}
|
||||
e.onNext(genres)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun makeGenreCursor(context: Context): Cursor? {
|
||||
val projection = arrayOf(Genres._ID, Genres.NAME)
|
||||
|
||||
try {
|
||||
return context.contentResolver.query(
|
||||
Genres.EXTERNAL_CONTENT_URI,
|
||||
projection, null, null, PreferenceUtil.getInstance().genreSortOrder)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.Audio.AudioColumns;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
|
||||
public class GenreSongsLoader {
|
||||
|
||||
public static Observable<ArrayList<Song>> getGenreSongsList(@NonNull Context context, int genreId) {
|
||||
return Observable.create(e -> {
|
||||
ArrayList<Song> list = new ArrayList<>();
|
||||
Cursor cursor = makeGenreSongCursor(context, genreId);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
list.add(getGenreSongFromCursorImpl(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
e.onNext((ArrayList<Song>) (List) list);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Song getGenreSongFromCursorImpl(@NonNull Cursor cursor) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String title = cursor.getString(1);
|
||||
final int trackNumber = cursor.getInt(2);
|
||||
final int year = cursor.getInt(3);
|
||||
final long duration = cursor.getLong(4);
|
||||
final String data = cursor.getString(5);
|
||||
final int dateModified = cursor.getInt(6);
|
||||
final int albumId = cursor.getInt(7);
|
||||
final String albumName = cursor.getString(8);
|
||||
final int artistId = cursor.getInt(9);
|
||||
final String artistName = cursor.getString(10);
|
||||
return new Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName);
|
||||
}
|
||||
|
||||
private static Cursor makeGenreSongCursor(Context context, long genreId) {
|
||||
try {
|
||||
return context.getContentResolver().query(
|
||||
MediaStore.Audio.Genres.Members.getContentUri("external", genreId),
|
||||
new String[]{
|
||||
MediaStore.Audio.Playlists.Members.AUDIO_ID,// 0
|
||||
AudioColumns.TITLE,// 1
|
||||
AudioColumns.TRACK,// 2
|
||||
AudioColumns.YEAR,// 3
|
||||
AudioColumns.DURATION,// 4
|
||||
AudioColumns.DATA,// 5
|
||||
AudioColumns.DATE_MODIFIED,// 6
|
||||
AudioColumns.ALBUM_ID,// 7
|
||||
AudioColumns.ALBUM,// 8
|
||||
AudioColumns.ARTIST_ID,// 9
|
||||
AudioColumns.ARTIST,// 10
|
||||
}, SongLoader.BASE_SELECTION, null,
|
||||
MediaStore.Audio.Genres.Members.DEFAULT_SORT_ORDER);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
public class HomeLoader {
|
||||
|
||||
public static Observable<ArrayList<AbsSmartPlaylist>> getRecentAndTopThings(
|
||||
@NonNull Context context) {
|
||||
ArrayList<AbsSmartPlaylist> objects = new ArrayList<>();
|
||||
return Observable.create(e -> {
|
||||
|
||||
new HistoryPlaylist(context).getSongs(context).subscribe(songs -> {
|
||||
if (!songs.isEmpty()) {
|
||||
objects.add(new HistoryPlaylist(context));
|
||||
}
|
||||
});
|
||||
new LastAddedPlaylist(context).getSongs(context).subscribe(songs -> {
|
||||
if (!songs.isEmpty()) {
|
||||
objects.add(new LastAddedPlaylist(context));
|
||||
}
|
||||
});
|
||||
new MyTopTracksPlaylist(context).getSongs(context).subscribe(songs -> {
|
||||
if (!songs.isEmpty()) {
|
||||
objects.add(new MyTopTracksPlaylist(context));
|
||||
}
|
||||
});
|
||||
|
||||
e.onNext(objects);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
public static Observable<ArrayList<Playlist>> getHomeLoader(@NonNull Context context) {
|
||||
ArrayList<Playlist> playlists = new ArrayList<>();
|
||||
PlaylistLoader.getAllPlaylists(context)
|
||||
.subscribe(playlists1 -> {
|
||||
if (playlists1.size() > 0) {
|
||||
for (Playlist playlist : playlists1) {
|
||||
PlaylistSongsLoader.getPlaylistSongList(context, playlist)
|
||||
.subscribe(songs -> {
|
||||
if (songs.size() > 0) {
|
||||
playlists.add(playlist);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return Observable.just(playlists);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
|
||||
import android.content.Context
|
||||
|
||||
import java.util.ArrayList
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist
|
||||
import io.reactivex.Observable
|
||||
|
||||
object HomeLoader {
|
||||
|
||||
fun getRecentAndTopThings(
|
||||
context: Context): Observable<ArrayList<AbsSmartPlaylist>> {
|
||||
val objects = ArrayList<AbsSmartPlaylist>()
|
||||
return Observable.create { e ->
|
||||
|
||||
HistoryPlaylist(context).getSongs(context).subscribe { songs ->
|
||||
if (!songs.isEmpty()) {
|
||||
objects.add(HistoryPlaylist(context))
|
||||
}
|
||||
}
|
||||
LastAddedPlaylist(context).getSongs(context).subscribe { songs ->
|
||||
if (!songs.isEmpty()) {
|
||||
objects.add(LastAddedPlaylist(context))
|
||||
}
|
||||
}
|
||||
MyTopTracksPlaylist(context).getSongs(context).subscribe { songs ->
|
||||
if (!songs.isEmpty()) {
|
||||
objects.add(MyTopTracksPlaylist(context))
|
||||
}
|
||||
}
|
||||
|
||||
e.onNext(objects)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getHomeLoader(context: Context): Observable<ArrayList<Playlist>> {
|
||||
val playlists = ArrayList<Playlist>()
|
||||
PlaylistLoader.getAllPlaylists(context)
|
||||
.subscribe { playlists1 ->
|
||||
if (playlists1.size > 0) {
|
||||
for (playlist in playlists1) {
|
||||
PlaylistSongsLoader.getPlaylistSongList(context, playlist)
|
||||
.subscribe { songs ->
|
||||
if (songs.size > 0) {
|
||||
playlists.add(playlist)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Observable.just(playlists)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.model.Album;
|
||||
import code.name.monkey.retromusic.model.Artist;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.annotations.NonNull;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
public class LastAddedSongsLoader {
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getLastAddedSongs(@NonNull Context context) {
|
||||
return SongLoader.Companion.getSongs(makeLastAddedCursor(context));
|
||||
}
|
||||
|
||||
public static Cursor makeLastAddedCursor(@NonNull final Context context) {
|
||||
long cutoff = PreferenceUtil.getInstance().getLastAddedCutoff();
|
||||
|
||||
return SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
MediaStore.Audio.Media.DATE_ADDED + ">?",
|
||||
new String[]{String.valueOf(cutoff)},
|
||||
MediaStore.Audio.Media.DATE_ADDED + " DESC");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Album>> getLastAddedAlbums(@NonNull Context context) {
|
||||
return AlbumLoader.splitIntoAlbums(getLastAddedSongs(context));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Artist>> getLastAddedArtists(@NonNull Context context) {
|
||||
return ArtistLoader.splitIntoArtists(getLastAddedAlbums(context));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.provider.MediaStore
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.annotations.NonNull
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
object LastAddedSongsLoader {
|
||||
|
||||
@NonNull
|
||||
fun getLastAddedSongs(@NonNull context: Context): Observable<ArrayList<Song>> {
|
||||
return SongLoader.getSongs(makeLastAddedCursor(context))
|
||||
}
|
||||
|
||||
fun makeLastAddedCursor(@NonNull context: Context): Cursor? {
|
||||
val cutoff = PreferenceUtil.getInstance().lastAddedCutoff
|
||||
|
||||
return SongLoader.makeSongCursor(
|
||||
context,
|
||||
MediaStore.Audio.Media.DATE_ADDED + ">?",
|
||||
arrayOf(cutoff.toString()),
|
||||
MediaStore.Audio.Media.DATE_ADDED + " DESC")
|
||||
}
|
||||
|
||||
@NonNull
|
||||
fun getLastAddedAlbums(@NonNull context: Context): Observable<ArrayList<Album>> {
|
||||
return AlbumLoader.splitIntoAlbums(getLastAddedSongs(context))
|
||||
}
|
||||
|
||||
@NonNull
|
||||
fun getLastAddedArtists(@NonNull context: Context): Observable<ArrayList<Artist>> {
|
||||
return ArtistLoader.splitIntoArtists(getLastAddedAlbums(context))
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.Audio.PlaylistsColumns;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
public class PlaylistLoader {
|
||||
@Nullable
|
||||
public static Cursor makePlaylistCursor(@NonNull final Context context, final String selection, final String[] values) {
|
||||
try {
|
||||
return context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
||||
new String[]{
|
||||
/* 0 */
|
||||
BaseColumns._ID,
|
||||
/* 1 */
|
||||
PlaylistsColumns.NAME
|
||||
}, selection, values, MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Playlist> getPlaylist(@Nullable final Cursor cursor) {
|
||||
return Observable.create(e -> {
|
||||
Playlist playlist = new Playlist();
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
playlist = getPlaylistFromCursorImpl(cursor);
|
||||
}
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
|
||||
e.onNext(playlist);
|
||||
e.onComplete();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Playlist> getPlaylist(@NonNull final Context context, final String playlistName) {
|
||||
return getPlaylist(makePlaylistCursor(
|
||||
context,
|
||||
PlaylistsColumns.NAME + "=?",
|
||||
new String[]{
|
||||
playlistName
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Playlist> getPlaylist(@NonNull final Context context, final int playlistId) {
|
||||
return getPlaylist(makePlaylistCursor(
|
||||
context,
|
||||
BaseColumns._ID + "=?",
|
||||
new String[]{
|
||||
String.valueOf(playlistId)
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Playlist getPlaylistFromCursorImpl(@NonNull final Cursor cursor) {
|
||||
|
||||
final int id = cursor.getInt(0);
|
||||
final String name = cursor.getString(1);
|
||||
return new Playlist(id, name);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Playlist>> getAllPlaylists(@Nullable final Cursor cursor) {
|
||||
return Observable.create(e -> {
|
||||
ArrayList<Playlist> playlists = new ArrayList<>();
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
playlists.add(getPlaylistFromCursorImpl(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
|
||||
e.onNext(playlists);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Playlist>> getAllPlaylists(@NonNull final Context context) {
|
||||
return getAllPlaylists(makePlaylistCursor(context, null, null));
|
||||
}
|
||||
|
||||
public static void deletePlaylists(Context context, long playlistId) {
|
||||
Uri localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
||||
StringBuilder localStringBuilder = new StringBuilder();
|
||||
localStringBuilder.append("_id IN (");
|
||||
localStringBuilder.append((playlistId));
|
||||
localStringBuilder.append(")");
|
||||
context.getContentResolver().delete(localUri, localStringBuilder.toString(), null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.PlaylistsColumns
|
||||
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import io.reactivex.Observable
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
object PlaylistLoader {
|
||||
fun makePlaylistCursor(context: Context, selection: String?, values: Array<String>?): Cursor? {
|
||||
try {
|
||||
return context.contentResolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
/* 0 */
|
||||
BaseColumns._ID,
|
||||
/* 1 */
|
||||
PlaylistsColumns.NAME), selection, values, MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getPlaylist(cursor: Cursor?): Observable<Playlist> {
|
||||
return Observable.create { e ->
|
||||
var playlist = Playlist()
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
playlist = getPlaylistFromCursorImpl(cursor)
|
||||
}
|
||||
cursor?.close()
|
||||
|
||||
e.onNext(playlist)
|
||||
e.onComplete()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun getPlaylist(context: Context, playlistName: String): Observable<Playlist> {
|
||||
return getPlaylist(makePlaylistCursor(
|
||||
context,
|
||||
PlaylistsColumns.NAME + "=?",
|
||||
arrayOf(playlistName)
|
||||
))
|
||||
}
|
||||
|
||||
fun getPlaylist(context: Context, playlistId: Int): Observable<Playlist> {
|
||||
return getPlaylist(makePlaylistCursor(
|
||||
context,
|
||||
BaseColumns._ID + "=?",
|
||||
arrayOf(playlistId.toString())
|
||||
))
|
||||
}
|
||||
|
||||
private fun getPlaylistFromCursorImpl(cursor: Cursor): Playlist {
|
||||
|
||||
val id = cursor.getInt(0)
|
||||
val name = cursor.getString(1)
|
||||
return Playlist(id, name)
|
||||
}
|
||||
|
||||
|
||||
fun getAllPlaylists(cursor: Cursor?): Observable<ArrayList<Playlist>> {
|
||||
return Observable.create { e ->
|
||||
val playlists = ArrayList<Playlist>()
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
playlists.add(getPlaylistFromCursorImpl(cursor))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
cursor?.close()
|
||||
|
||||
e.onNext(playlists)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllPlaylists(context: Context): Observable<ArrayList<Playlist>> {
|
||||
return getAllPlaylists(makePlaylistCursor(context, null, null))
|
||||
}
|
||||
|
||||
fun deletePlaylists(context: Context, playlistId: Long) {
|
||||
val localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI
|
||||
val localStringBuilder = StringBuilder()
|
||||
localStringBuilder.append("_id IN (")
|
||||
localStringBuilder.append(playlistId)
|
||||
localStringBuilder.append(")")
|
||||
context.contentResolver.delete(localUri, localStringBuilder.toString(), null)
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.Audio.AudioColumns;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist;
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.PlaylistSong;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.annotations.NonNull;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
public class PlaylistSongsLoader {
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getPlaylistSongList(@NonNull Context context, Playlist playlist) {
|
||||
if (playlist instanceof AbsCustomPlaylist) {
|
||||
return ((AbsCustomPlaylist) playlist).getSongs(context);
|
||||
} else {
|
||||
//noinspection unchecked
|
||||
return getPlaylistSongList(context, playlist.id);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getPlaylistSongList(@NonNull Context context, final int playlistId) {
|
||||
return Observable.create(e -> {
|
||||
ArrayList<PlaylistSong> songs = new ArrayList<>();
|
||||
Cursor cursor = makePlaylistSongCursor(context, playlistId);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
songs.add(getPlaylistSongFromCursorImpl(cursor, playlistId));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
e.onNext((ArrayList<Song>) (List) songs);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static PlaylistSong getPlaylistSongFromCursorImpl(@NonNull Cursor cursor, int playlistId) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String title = cursor.getString(1);
|
||||
final int trackNumber = cursor.getInt(2);
|
||||
final int year = cursor.getInt(3);
|
||||
final long duration = cursor.getLong(4);
|
||||
final String data = cursor.getString(5);
|
||||
final int dateModified = cursor.getInt(6);
|
||||
final int albumId = cursor.getInt(7);
|
||||
final String albumName = cursor.getString(8);
|
||||
final int artistId = cursor.getInt(9);
|
||||
final String artistName = cursor.getString(10);
|
||||
final int idInPlaylist = cursor.getInt(11);
|
||||
|
||||
return new PlaylistSong(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName, playlistId, idInPlaylist);
|
||||
}
|
||||
|
||||
private static Cursor makePlaylistSongCursor(@NonNull final Context context, final int playlistId) {
|
||||
try {
|
||||
return context.getContentResolver().query(
|
||||
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
|
||||
new String[]{
|
||||
MediaStore.Audio.Playlists.Members.AUDIO_ID,// 0
|
||||
AudioColumns.TITLE,// 1
|
||||
AudioColumns.TRACK,// 2
|
||||
AudioColumns.YEAR,// 3
|
||||
AudioColumns.DURATION,// 4
|
||||
AudioColumns.DATA,// 5
|
||||
AudioColumns.DATE_MODIFIED,// 6
|
||||
AudioColumns.ALBUM_ID,// 7
|
||||
AudioColumns.ALBUM,// 8
|
||||
AudioColumns.ARTIST_ID,// 9
|
||||
AudioColumns.ARTIST,// 10
|
||||
MediaStore.Audio.Playlists.Members._ID, // 11
|
||||
}, SongLoader.BASE_SELECTION, null,
|
||||
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.PlaylistSong
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.annotations.NonNull
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
object PlaylistSongsLoader {
|
||||
|
||||
@NonNull
|
||||
fun getPlaylistSongList(@NonNull context: Context, playlist: Playlist): Observable<ArrayList<Song>> {
|
||||
return (playlist as? AbsCustomPlaylist)?.getSongs(context)
|
||||
?: getPlaylistSongList(context, playlist.id)
|
||||
}
|
||||
|
||||
@NonNull
|
||||
fun getPlaylistSongList(@NonNull context: Context, playlistId: Int): Observable<ArrayList<Song>> {
|
||||
return Observable.create { e ->
|
||||
val songs = ArrayList<Song>()
|
||||
val cursor = makePlaylistSongCursor(context, playlistId)
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
songs.add(getPlaylistSongFromCursorImpl(cursor, playlistId))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
cursor?.close()
|
||||
e.onNext(songs)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private fun getPlaylistSongFromCursorImpl(@NonNull cursor: Cursor, playlistId: Int): PlaylistSong {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getInt(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
val idInPlaylist = cursor.getInt(11)
|
||||
|
||||
return PlaylistSong(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName, playlistId, idInPlaylist)
|
||||
}
|
||||
|
||||
private fun makePlaylistSongCursor(@NonNull context: Context, playlistId: Int): Cursor? {
|
||||
try {
|
||||
return context.contentResolver.query(
|
||||
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId.toLong()),
|
||||
arrayOf(MediaStore.Audio.Playlists.Members.AUDIO_ID, // 0
|
||||
AudioColumns.TITLE, // 1
|
||||
AudioColumns.TRACK, // 2
|
||||
AudioColumns.YEAR, // 3
|
||||
AudioColumns.DURATION, // 4
|
||||
AudioColumns.DATA, // 5
|
||||
AudioColumns.DATE_MODIFIED, // 6
|
||||
AudioColumns.ALBUM_ID, // 7
|
||||
AudioColumns.ALBUM, // 8
|
||||
AudioColumns.ARTIST_ID, // 9
|
||||
AudioColumns.ARTIST, // 10
|
||||
MediaStore.Audio.Playlists.Members._ID)// 11
|
||||
, BASE_SELECTION, null,
|
||||
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
public class SearchLoader {
|
||||
|
||||
public static Observable<ArrayList<Object>> searchAll(@NonNull Context context, @NonNull String query) {
|
||||
ArrayList<Object> results = new ArrayList<>();
|
||||
return Observable.create(e -> {
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
SongLoader.Companion.getSongs(context, query)
|
||||
.subscribe(songs -> {
|
||||
if (!songs.isEmpty()) {
|
||||
results.add(context.getResources().getString(R.string.songs));
|
||||
results.addAll(songs);
|
||||
}
|
||||
});
|
||||
|
||||
ArtistLoader.getArtists(context, query)
|
||||
.subscribe(artists -> {
|
||||
if (!artists.isEmpty()) {
|
||||
results.add(context.getResources().getString(R.string.artists));
|
||||
results.addAll(artists);
|
||||
}
|
||||
});
|
||||
AlbumLoader.getAlbums(context, query)
|
||||
.subscribe(albums -> {
|
||||
if (!albums.isEmpty()) {
|
||||
results.add(context.getResources().getString(R.string.albums));
|
||||
results.addAll(albums);
|
||||
}
|
||||
});
|
||||
}
|
||||
e.onNext(results);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import java.util.ArrayList
|
||||
|
||||
import code.name.monkey.retromusic.R
|
||||
import io.reactivex.Observable
|
||||
|
||||
object SearchLoader {
|
||||
|
||||
fun searchAll(context: Context, query: String): Observable<ArrayList<Any>> {
|
||||
val results = ArrayList<Any>()
|
||||
return Observable.create { e ->
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
SongLoader.getSongs(context, query)
|
||||
.subscribe { songs ->
|
||||
if (!songs.isEmpty()) {
|
||||
results.add(context.resources.getString(R.string.songs))
|
||||
results.addAll(songs)
|
||||
}
|
||||
}
|
||||
|
||||
ArtistLoader.getArtists(context, query)
|
||||
.subscribe { artists ->
|
||||
if (!artists.isEmpty()) {
|
||||
results.add(context.resources.getString(R.string.artists))
|
||||
results.addAll(artists)
|
||||
}
|
||||
}
|
||||
AlbumLoader.getAlbums(context, query)
|
||||
.subscribe { albums ->
|
||||
if (!albums.isEmpty()) {
|
||||
results.add(context.resources.getString(R.string.albums))
|
||||
results.addAll(albums)
|
||||
}
|
||||
}
|
||||
}
|
||||
e.onNext(results)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,9 +2,10 @@ package code.name.monkey.retromusic.loaders
|
|||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import code.name.monkey.retromusic.Constants.BASE_PROJECTION
|
||||
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
||||
import code.name.monkey.retromusic.helper.ShuffleHelper
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.providers.BlacklistStore
|
||||
|
@ -16,167 +17,152 @@ import java.util.*
|
|||
* Created by hemanths on 10/08/17.
|
||||
*/
|
||||
|
||||
open class SongLoader {
|
||||
companion object {
|
||||
|
||||
const val BASE_SELECTION = AudioColumns.IS_MUSIC + "=1" + " AND " + AudioColumns.TITLE + " != ''"
|
||||
val BASE_PROJECTION = arrayOf(BaseColumns._ID, // 0
|
||||
AudioColumns.TITLE, // 1
|
||||
AudioColumns.TRACK, // 2
|
||||
AudioColumns.YEAR, // 3
|
||||
AudioColumns.DURATION, // 4
|
||||
AudioColumns.DATA, // 5
|
||||
AudioColumns.DATE_MODIFIED, // 6
|
||||
AudioColumns.ALBUM_ID, // 7
|
||||
AudioColumns.ALBUM, // 8
|
||||
AudioColumns.ARTIST_ID, // 9
|
||||
AudioColumns.ARTIST)// 10
|
||||
object SongLoader {
|
||||
|
||||
fun getAllSongs(context: Context): Observable<ArrayList<Song>> {
|
||||
val cursor = makeSongCursor(context, null, null)
|
||||
return getSongs(cursor)
|
||||
}
|
||||
fun getAllSongs(context: Context): Observable<ArrayList<Song>> {
|
||||
val cursor = makeSongCursor(context, null, null)
|
||||
return getSongs(cursor)
|
||||
}
|
||||
|
||||
fun getSongs(context: Context, query: String): Observable<ArrayList<Song>> {
|
||||
val cursor = makeSongCursor(context, AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%"))
|
||||
return getSongs(cursor)
|
||||
}
|
||||
fun getSongs(context: Context, query: String): Observable<ArrayList<Song>> {
|
||||
val cursor = makeSongCursor(context, AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%"))
|
||||
return getSongs(cursor)
|
||||
}
|
||||
|
||||
fun getSongs(cursor: Cursor?): Observable<ArrayList<Song>> {
|
||||
return Observable.create { e ->
|
||||
val songs = ArrayList<Song>()
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
songs.add(getSongFromCursorImpl(cursor))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
|
||||
cursor?.close()
|
||||
e.onNext(songs)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSongFromCursorImpl(cursor: Cursor): Song {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getLong(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
|
||||
return Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName,
|
||||
artistId, artistName)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun makeSongCursor(context: Context, selection: String?, selectionValues: Array<String>?, sortOrder: String = PreferenceUtil.getInstance().songSortOrder): Cursor? {
|
||||
var selectionFinal = selection
|
||||
var selectionValuesFinal = selectionValues
|
||||
selectionFinal = if (selection != null && selection.trim { it <= ' ' } != "") {
|
||||
"$BASE_SELECTION AND $selectionFinal"
|
||||
} else {
|
||||
BASE_SELECTION
|
||||
fun getSongs(cursor: Cursor?): Observable<ArrayList<Song>> {
|
||||
return Observable.create { e ->
|
||||
val songs = ArrayList<Song>()
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
songs.add(getSongFromCursorImpl(cursor))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
|
||||
// Blacklist
|
||||
val paths = BlacklistStore.getInstance(context).paths
|
||||
if (!paths.isEmpty()) {
|
||||
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size)
|
||||
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
||||
}
|
||||
|
||||
try {
|
||||
return context.contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||
BASE_PROJECTION, selectionFinal, selectionValuesFinal, sortOrder)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun generateBlacklistSelection(selection: String?, pathCount: Int): String {
|
||||
val newSelection = StringBuilder(
|
||||
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
|
||||
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
|
||||
for (i in 0 until pathCount - 1) {
|
||||
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
|
||||
}
|
||||
return newSelection.toString()
|
||||
}
|
||||
|
||||
private fun addBlacklistSelectionValues(selectionValues: Array<String>?,
|
||||
paths: ArrayList<String>): Array<String>? {
|
||||
var selectionValuesFinal = selectionValues
|
||||
if (selectionValuesFinal == null) {
|
||||
selectionValuesFinal = emptyArray()
|
||||
}
|
||||
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
|
||||
"n = $it"
|
||||
}
|
||||
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
|
||||
for (i in selectionValuesFinal.size until newSelectionValues.size) {
|
||||
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
|
||||
}
|
||||
return newSelectionValues
|
||||
}
|
||||
|
||||
fun getSong(cursor: Cursor?): Observable<Song> {
|
||||
return Observable.create { e ->
|
||||
val song: Song
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
song = getSongFromCursorImpl(cursor)
|
||||
} else {
|
||||
song = Song.EMPTY_SONG
|
||||
}
|
||||
cursor?.close()
|
||||
e.onNext(song)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSong(context: Context, queryId: Int): Observable<Song> {
|
||||
val cursor = makeSongCursor(context, AudioColumns._ID + "=?",
|
||||
arrayOf(queryId.toString()))
|
||||
return getSong(cursor)
|
||||
}
|
||||
|
||||
fun suggestSongs(context: Context): Observable<ArrayList<Song>> {
|
||||
return SongLoader.getAllSongs(context)
|
||||
.flatMap {
|
||||
val list = ArrayList<Song>()
|
||||
ShuffleHelper.makeShuffleList(it, -1)
|
||||
if (it.size > 9) {
|
||||
list.addAll(it.subList(0, 9))
|
||||
}
|
||||
return@flatMap Observable.just(list)
|
||||
}
|
||||
/*.flatMap({ songs ->
|
||||
val list = ArrayList<Song>()
|
||||
ShuffleHelper.makeShuffleList(songs, -1)
|
||||
if (songs.size > 9) {
|
||||
list.addAll(songs.subList(0, 9))
|
||||
}
|
||||
Observable.just(list)
|
||||
} as Function<ArrayList<Song>, ObservableSource<ArrayList<Song>>>)*/
|
||||
/*.subscribe(songs -> {
|
||||
ArrayList<Song> list = new ArrayList<>();
|
||||
if (songs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ShuffleHelper.makeShuffleList(songs, -1);
|
||||
if (songs.size() > 10) {
|
||||
list.addAll(songs.subList(0, 10));
|
||||
} else {
|
||||
list.addAll(songs);
|
||||
}
|
||||
return;
|
||||
});*/
|
||||
cursor?.close()
|
||||
e.onNext(songs)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSongFromCursorImpl(cursor: Cursor): Song {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getLong(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
|
||||
return Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName,
|
||||
artistId, artistName)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun makeSongCursor(context: Context, selection: String?, selectionValues: Array<String>?, sortOrder: String = PreferenceUtil.getInstance().songSortOrder): Cursor? {
|
||||
var selectionFinal = selection
|
||||
var selectionValuesFinal = selectionValues
|
||||
selectionFinal = if (selection != null && selection.trim { it <= ' ' } != "") {
|
||||
"$BASE_SELECTION AND $selectionFinal"
|
||||
} else {
|
||||
BASE_SELECTION
|
||||
}
|
||||
|
||||
// Blacklist
|
||||
val paths = BlacklistStore.getInstance(context).paths
|
||||
if (!paths.isEmpty()) {
|
||||
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size)
|
||||
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
||||
}
|
||||
|
||||
try {
|
||||
return context.contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||
BASE_PROJECTION, selectionFinal, selectionValuesFinal, sortOrder)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun generateBlacklistSelection(selection: String?, pathCount: Int): String {
|
||||
val newSelection = StringBuilder(
|
||||
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
|
||||
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
|
||||
for (i in 0 until pathCount - 1) {
|
||||
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
|
||||
}
|
||||
return newSelection.toString()
|
||||
}
|
||||
|
||||
private fun addBlacklistSelectionValues(selectionValues: Array<String>?,
|
||||
paths: ArrayList<String>): Array<String>? {
|
||||
var selectionValuesFinal = selectionValues
|
||||
if (selectionValuesFinal == null) {
|
||||
selectionValuesFinal = emptyArray()
|
||||
}
|
||||
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
|
||||
"n = $it"
|
||||
}
|
||||
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
|
||||
for (i in selectionValuesFinal.size until newSelectionValues.size) {
|
||||
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
|
||||
}
|
||||
return newSelectionValues
|
||||
}
|
||||
|
||||
fun getSong(cursor: Cursor?): Observable<Song> {
|
||||
return Observable.create { e ->
|
||||
val song: Song = if (cursor != null && cursor.moveToFirst()) {
|
||||
getSongFromCursorImpl(cursor)
|
||||
} else {
|
||||
Song.EMPTY_SONG
|
||||
}
|
||||
cursor?.close()
|
||||
e.onNext(song)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSong(context: Context, queryId: Int): Observable<Song> {
|
||||
val cursor = makeSongCursor(context, AudioColumns._ID + "=?",
|
||||
arrayOf(queryId.toString()))
|
||||
return getSong(cursor)
|
||||
}
|
||||
|
||||
fun suggestSongs(context: Context): Observable<ArrayList<Song>> {
|
||||
return SongLoader.getAllSongs(context)
|
||||
.flatMap {
|
||||
val list = ArrayList<Song>()
|
||||
ShuffleHelper.makeShuffleList(it, -1)
|
||||
if (it.size > 9) {
|
||||
list.addAll(it.subList(0, 9))
|
||||
}
|
||||
return@flatMap Observable.just(list)
|
||||
}
|
||||
/*.flatMap({ songs ->
|
||||
val list = ArrayList<Song>()
|
||||
ShuffleHelper.makeShuffleList(songs, -1)
|
||||
if (songs.size > 9) {
|
||||
list.addAll(songs.subList(0, 9))
|
||||
}
|
||||
Observable.just(list)
|
||||
} as Function<ArrayList<Song>, ObservableSource<ArrayList<Song>>>)*/
|
||||
/*.subscribe(songs -> {
|
||||
ArrayList<Song> list = new ArrayList<>();
|
||||
if (songs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ShuffleHelper.makeShuffleList(songs, -1);
|
||||
if (songs.size() > 10) {
|
||||
list.addAll(songs.subList(0, 10));
|
||||
} else {
|
||||
list.addAll(songs);
|
||||
}
|
||||
return;
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue