kotlin conversion

main
h4h13 2018-11-30 06:36:16 +05:30
parent 8e6ab40d93
commit b2c15ef186
316 changed files with 13055 additions and 22983 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View 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
}

View File

@ -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();
}
}

View 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
}
}

View File

@ -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();
}
}

View File

@ -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()
}
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}

View File

@ -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()

View File

@ -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;
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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,

View File

@ -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()));
}
}

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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())));
}
}

View File

@ -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(

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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());
}
}

View File

@ -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)
}
}

View File

@ -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;
}
}

View File

@ -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
}
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}
}

View File

@ -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 = ",";
}

View File

@ -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 = ","
}
}

View File

@ -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();
}
}

View File

@ -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()
}
}
}

View File

@ -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;
}
}
}

View File

@ -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)
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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();
}
}
}

View File

@ -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()
}
}
}

View File

@ -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>();
}
}

View File

@ -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()
}
}

View File

@ -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);
}
}
}

View File

@ -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()
}
}
}

View File

@ -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";
}
}

View File

@ -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"
}
}
}

View File

@ -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());
}
}

View File

@ -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)
}
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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();
}
}
}
}

View File

@ -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()
}
}
}
}

View File

@ -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();
}
}

View File

@ -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)
}
}
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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();
}

View File

@ -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)
}

View File

@ -1,6 +0,0 @@
package code.name.monkey.retromusic.interfaces;
public interface LoaderIds {
int FOLDERS_FRAGMENT = 5;
}

View File

@ -0,0 +1,8 @@
package code.name.monkey.retromusic.interfaces
interface LoaderIds {
companion object {
val FOLDERS_FRAGMENT = 5
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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()
}

View File

@ -1,12 +0,0 @@
package code.name.monkey.retromusic.interfaces;
import androidx.annotation.ColorInt;
/**
* @author Aidan Follestad (afollestad)
*/
public interface PaletteColorHolder {
@ColorInt
int getPaletteColor();
}

View File

@ -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
}

View File

@ -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();
}
}

View File

@ -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
}
}
}

View File

@ -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();
});
});
}
}

View File

@ -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()
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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)
}
}

View File

@ -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));
}
}

View File

@ -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))
}
}

View File

@ -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);
}
}

View File

@ -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)
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}
}

View File

@ -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();
});
}
}

View File

@ -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()
}
}
}

View File

@ -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