commit
7c59273879
441 changed files with 14816 additions and 24998 deletions
148
app/app.iml
148
app/app.iml
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,6 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
|
@ -102,7 +103,7 @@ dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation 'androidx.multidex:multidex:2.0.0'
|
implementation 'androidx.multidex:multidex:2.0.0'
|
||||||
implementation "androidx.fragment:fragment:$supportLibVersion"
|
implementation "androidx.fragment:fragment:$supportLibVersion"
|
||||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||||
implementation "androidx.recyclerview:recyclerview:$supportLibVersion"
|
implementation "androidx.recyclerview:recyclerview:$supportLibVersion"
|
||||||
implementation "androidx.gridlayout:gridlayout:$supportLibVersion"
|
implementation "androidx.gridlayout:gridlayout:$supportLibVersion"
|
||||||
implementation "androidx.cardview:cardview:$supportLibVersion"
|
implementation "androidx.cardview:cardview:$supportLibVersion"
|
||||||
|
@ -112,14 +113,18 @@ dependencies {
|
||||||
implementation "androidx.legacy:legacy-support-v13:$supportLibVersion"
|
implementation "androidx.legacy:legacy-support-v13:$supportLibVersion"
|
||||||
implementation "androidx.legacy:legacy-preference-v14:$supportLibVersion"
|
implementation "androidx.legacy:legacy-preference-v14:$supportLibVersion"
|
||||||
implementation "com.google.android.material:material:$supportLibVersion"
|
implementation "com.google.android.material:material:$supportLibVersion"
|
||||||
|
|
||||||
//For casting
|
//For casting
|
||||||
implementation 'androidx.mediarouter:mediarouter:1.0.0'
|
implementation 'androidx.mediarouter:mediarouter:1.0.0'
|
||||||
implementation 'com.google.android.gms:play-services-cast-framework:16.1.0'
|
implementation 'com.google.android.gms:play-services-cast-framework:16.1.0'
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
|
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
|
implementation "com.squareup.retrofit2:retrofit:2.4.0"
|
||||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
|
implementation "com.squareup.retrofit2:converter-gson:2.4.0"
|
||||||
|
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
|
||||||
|
|
||||||
implementation "com.jakewharton:butterknife:$butterKnife"
|
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:core:$materialDialog"
|
||||||
implementation "com.afollestad.material-dialogs:commons:$materialDialog"
|
implementation "com.afollestad.material-dialogs:commons:$materialDialog"
|
||||||
implementation 'com.afollestad:material-cab:0.1.12'
|
implementation 'com.afollestad:material-cab:0.1.12'
|
||||||
|
@ -135,8 +140,8 @@ dependencies {
|
||||||
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
|
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
|
||||||
implementation 'com.github.kabouzeid:RecyclerView-FastScroll:1.0.16-kmod'
|
implementation 'com.github.kabouzeid:RecyclerView-FastScroll:1.0.16-kmod'
|
||||||
implementation 'com.anjlab.android.iab.v3:library:1.0.44'
|
implementation 'com.anjlab.android.iab.v3:library:1.0.44'
|
||||||
|
|
||||||
/*UI Library*/
|
/*UI Library*/
|
||||||
implementation 'uk.co.chrisjenx:calligraphy:2.3.0'
|
|
||||||
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2'
|
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2'
|
||||||
implementation 'com.r0adkll:slidableactivity:2.0.6'
|
implementation 'com.r0adkll:slidableactivity:2.0.6'
|
||||||
/*Backend all*/
|
/*Backend all*/
|
||||||
|
@ -144,10 +149,8 @@ dependencies {
|
||||||
implementation 'com.github.hannesa2:AndroidSlidingUpPanel:3.5.0'
|
implementation 'com.github.hannesa2:AndroidSlidingUpPanel:3.5.0'
|
||||||
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
|
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
|
||||||
implementation 'org.nanohttpd:nanohttpd:2.3.1'
|
implementation 'org.nanohttpd:nanohttpd:2.3.1'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".RetroApplication"
|
android:name=".App"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -103,27 +103,19 @@
|
||||||
<activity android:name=".ui.activities.tageditor.AlbumTagEditorActivity" />
|
<activity android:name=".ui.activities.tageditor.AlbumTagEditorActivity" />
|
||||||
<activity android:name=".ui.activities.tageditor.SongTagEditorActivity" />
|
<activity android:name=".ui.activities.tageditor.SongTagEditorActivity" />
|
||||||
<activity android:name=".ui.activities.SettingsActivity" />
|
<activity android:name=".ui.activities.SettingsActivity" />
|
||||||
<activity android:name=".ui.activities.SearchActivity"
|
<activity
|
||||||
android:windowSoftInputMode="stateVisible" >
|
android:name=".ui.activities.SearchActivity"
|
||||||
</activity>
|
android:windowSoftInputMode="stateVisible"/>
|
||||||
<activity android:name=".ui.activities.LyricsActivity" />
|
<activity android:name=".ui.activities.LyricsActivity" />
|
||||||
<activity android:name=".ui.activities.UserInfoActivity" />
|
<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.SupportDevelopmentActivity" />
|
||||||
<activity android:name=".ui.activities.GenreDetailsActivity" />
|
<activity android:name=".ui.activities.GenreDetailsActivity" />
|
||||||
<activity android:name=".ui.activities.LicenseActivity" />
|
<activity android:name=".ui.activities.LicenseActivity" />
|
||||||
<activity android:name=".ui.activities.ProVersionActivity" />
|
<activity android:name=".ui.activities.ProVersionActivity" />
|
||||||
<activity android:name=".ui.activities.EqualizerActivity" />
|
<activity android:name=".ui.activities.EqualizerActivity" />
|
||||||
<activity android:name=".ui.activities.ErrorHandlerActivity" />
|
<activity android:name=".ui.activities.ErrorHandlerActivity" />
|
||||||
|
<activity android:name=".ui.activities.WhatsNewActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".cast.ExpandedCastControlsActivity"
|
android:name=".cast.ExpandedCastControlsActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -163,66 +155,7 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</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
|
<meta-data
|
||||||
android:name="android.max_aspect"
|
android:name="android.max_aspect"
|
||||||
|
@ -256,9 +189,6 @@
|
||||||
android:resource="@xml/provider_paths" />
|
android:resource="@xml/provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<activity android:name=".ui.activities.WhatsNewActivity"></activity>
|
|
||||||
<activity android:name=".ui.activities.album.SmallAlbumDetailsActivity" />
|
|
||||||
<activity android:name=".ui.activities.NowPayingActivity" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<html>
<head>
<style type="text/css">
* {
word-wrap: break-word;
}
{style-placeholder}
a {
color: #{link-color};
}
a:active {
color: #{link-color-active};
}
ul {
list-style-position: outside;
padding-left: 0;
padding-right: 0;
margin-left: 1em;
}
li {
padding-top: 8px;
}
</style>
</head>
<body>
<h1 style="text-align:center;">Are you subscribed to <a
href="https://www.youtube.com/user/PewDiePie">PewDiePie</a></h1>
<p style="line-height:150%">You can view the changelog dialog again at any time from the
<i>about</i> section.</p>
<h3>Version 2.2.100</h3>
<ul style="line-height:150%">
<li>Click new music mix to play songs</li>
<li>Gradient image option for gird list</li>
<li>Clear button for playing queue</li>
<li>Click toolbar (Library) to open options</li>
<li>Folder list back button</li>
<li>New theme Fit</li>
<li>On library click on toolbar for accessing main menu
</li>
<li>On home click on toolbar for accessing search
</li>
<li>BottomSheetDialogue is now adaptable to screens, background colour and text size
consistency.
</li>
<li>Removed coloured navigation bar option to making app adapt the primary colour</li>
<li>Swipe up gesture for now playing removed, replaced with "tap to open", To achieve
transparent navigation bar for desired themes.
</li>
<li>Improved tablet UI and home screen by adding suggestions toggle banner issues.</li>
<li>Improving lyrics page</li>
</ul>
<p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a>
</p>
<p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again. </p>
</body>
|
<html>
<head>
<style type="text/css">
* {
word-wrap: break-word;
}
{style-placeholder}
a {
color: #{link-color};
}
a:active {
color: #{link-color-active};
}
ul {
list-style-position: outside;
padding-left: 0;
padding-right: 0;
margin-left: 1em;
}
li {
padding-top: 8px;
}
</style>
</head>
<body>
<h3>Version 2.2.100</h3>
<ul style="line-height:150%">
<li>Click new music mix to play songs</li>
<li>Gradient image option for gird list</li>
<li>Clear button for playing queue</li>
<li>Click toolbar (Library) to open options</li>
<li>Folder list back button</li>
<li>New theme Fit</li>
<li>On library click on toolbar for accessing main menu
</li>
<li>On home click on toolbar for accessing search
</li>
<li>BottomSheetDialogue is now adaptable to screens, background colour and text size
consistency.
</li>
<li>Removed coloured navigation bar option to making app adapt the primary colour</li>
<li>Swipe up gesture for now playing removed, replaced with "tap to open", To achieve
transparent navigation bar for desired themes.
</li>
<li>Improved tablet UI and home screen by adding suggestions toggle banner issues.</li>
<li>Improving lyrics page</li>
</ul>
<p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a>
</p>
<p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again. </p>
</body>
|
93
app/src/main/java/code/name/monkey/retromusic/App.kt
Normal file
93
app/src/main/java/code/name/monkey/retromusic/App.kt
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
class App : 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: App
|
||||||
|
private set
|
||||||
|
|
||||||
|
val context: Context
|
||||||
|
get() = instance.applicationContext
|
||||||
|
|
||||||
|
val isProVersion: Boolean
|
||||||
|
get() = BuildConfig.DEBUG || instance.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID)
|
||||||
|
|
||||||
|
fun deleteAppData() {
|
||||||
|
try {
|
||||||
|
// clearing app data
|
||||||
|
val packageName = instance.packageName
|
||||||
|
val runtime = Runtime.getRuntime()
|
||||||
|
runtime.exec("pm clear $packageName")
|
||||||
|
|
||||||
|
System.exit(0)
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
package code.name.monkey.retromusic;
|
|
||||||
|
|
||||||
public class Constants {
|
|
||||||
|
|
||||||
public static final String DISCORD_LINK = "https://discord.gg/qTecXXn";
|
|
||||||
|
|
||||||
public static final String RETRO_MUSIC_PACKAGE_NAME = "code.name.monkey.retromusic";
|
|
||||||
public static final String MUSIC_PACKAGE_NAME = "com.android.music";
|
|
||||||
public static final String ACTION_TOGGLE_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".togglepause";
|
|
||||||
public static final String ACTION_PLAY = RETRO_MUSIC_PACKAGE_NAME + ".play";
|
|
||||||
public static final String ACTION_PLAY_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + ".play.playlist";
|
|
||||||
public static final String ACTION_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".pause";
|
|
||||||
public static final String ACTION_STOP = RETRO_MUSIC_PACKAGE_NAME + ".stop";
|
|
||||||
public static final String ACTION_SKIP = RETRO_MUSIC_PACKAGE_NAME + ".skip";
|
|
||||||
public static final String ACTION_REWIND = RETRO_MUSIC_PACKAGE_NAME + ".rewind";
|
|
||||||
public static final String ACTION_QUIT = RETRO_MUSIC_PACKAGE_NAME + ".quitservice";
|
|
||||||
public static final String INTENT_EXTRA_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist";
|
|
||||||
public static final String INTENT_EXTRA_SHUFFLE_MODE = RETRO_MUSIC_PACKAGE_NAME + ".intentextra.shufflemode";
|
|
||||||
public static final String APP_WIDGET_UPDATE = RETRO_MUSIC_PACKAGE_NAME + ".appwidgetupdate";
|
|
||||||
public static final String EXTRA_APP_WIDGET_NAME = RETRO_MUSIC_PACKAGE_NAME + "app_widget_name";
|
|
||||||
// do not change these three strings as it will break support with other apps (e.g. last.fm scrobbling)
|
|
||||||
public static final String META_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".metachanged";
|
|
||||||
public static final String QUEUE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".queuechanged";
|
|
||||||
public static final String PLAY_STATE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".playstatechanged";
|
|
||||||
public static final String REPEAT_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".repeatmodechanged";
|
|
||||||
public static final String SHUFFLE_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".shufflemodechanged";
|
|
||||||
public static final String MEDIA_STORE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".mediastorechanged";
|
|
||||||
public static final String RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic";
|
|
||||||
public static final String PAYPAL_ME_URL = "https://www.paypal.me/h4h14";
|
|
||||||
public static final String GOOGLE_PLUS_COMMUNITY = "https://plus.google.com/communities/110811566242871492162";
|
|
||||||
public static final String TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534";
|
|
||||||
public static final String GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicPlayer";
|
|
||||||
public static final String BASE_API_URL_KUGOU = "http://lyrics.kugou.com/";
|
|
||||||
public static final String TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog";
|
|
||||||
public static final String USER_PROFILE = "profile.jpg";
|
|
||||||
public static final String USER_BANNER = "banner.jpg";
|
|
||||||
public static final String APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/";
|
|
||||||
public static final String APP_TELEGRAM_LINK = "https://t.me/retromusicapp/";
|
|
||||||
public static final String APP_TWITTER_LINK = "https://twitter.com/retromusicapp";
|
|
||||||
public static final String FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md";
|
|
||||||
public static final int CAST_SERVER_PORT = 8080;
|
|
||||||
}
|
|
97
app/src/main/java/code/name/monkey/retromusic/Constants.kt
Normal file
97
app/src/main/java/code/name/monkey/retromusic/Constants.kt
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package code.name.monkey.retromusic
|
||||||
|
|
||||||
|
import android.provider.BaseColumns
|
||||||
|
import android.provider.MediaStore
|
||||||
|
|
||||||
|
object Constants {
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val DISCORD_LINK = "https://discord.gg/qTecXXn"
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val RETRO_MUSIC_PACKAGE_NAME = "code.name.monkey.retromusic"
|
||||||
|
@JvmField
|
||||||
|
val MUSIC_PACKAGE_NAME = "com.android.music"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_TOGGLE_PAUSE = "$RETRO_MUSIC_PACKAGE_NAME.togglepause"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_PLAY = "$RETRO_MUSIC_PACKAGE_NAME.play"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_PLAY_PLAYLIST = "$RETRO_MUSIC_PACKAGE_NAME.play.playlist"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_PAUSE = "$RETRO_MUSIC_PACKAGE_NAME.pause"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_STOP = "$RETRO_MUSIC_PACKAGE_NAME.stop"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_SKIP = "$RETRO_MUSIC_PACKAGE_NAME.skip"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_REWIND = "$RETRO_MUSIC_PACKAGE_NAME.rewind"
|
||||||
|
@JvmField
|
||||||
|
val ACTION_QUIT = "$RETRO_MUSIC_PACKAGE_NAME.quitservice"
|
||||||
|
@JvmField
|
||||||
|
val INTENT_EXTRA_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist"
|
||||||
|
@JvmField
|
||||||
|
val INTENT_EXTRA_SHUFFLE_MODE = "$RETRO_MUSIC_PACKAGE_NAME.intentextra.shufflemode"
|
||||||
|
@JvmField
|
||||||
|
val APP_WIDGET_UPDATE = "$RETRO_MUSIC_PACKAGE_NAME.appwidgetupdate"
|
||||||
|
@JvmField
|
||||||
|
val EXTRA_APP_WIDGET_NAME = RETRO_MUSIC_PACKAGE_NAME + "app_widget_name"
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val META_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.metachanged"
|
||||||
|
@JvmField
|
||||||
|
val QUEUE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.queuechanged"
|
||||||
|
@JvmField
|
||||||
|
val PLAY_STATE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.playstatechanged"
|
||||||
|
@JvmField
|
||||||
|
val REPEAT_MODE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.repeatmodechanged"
|
||||||
|
@JvmField
|
||||||
|
val SHUFFLE_MODE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.shufflemodechanged"
|
||||||
|
@JvmField
|
||||||
|
val MEDIA_STORE_CHANGED = "$RETRO_MUSIC_PACKAGE_NAME.mediastorechanged"
|
||||||
|
@JvmField
|
||||||
|
val RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic"
|
||||||
|
@JvmField
|
||||||
|
val PAYPAL_ME_URL = "https://www.paypal.me/h4h14"
|
||||||
|
@JvmField
|
||||||
|
val GOOGLE_PLUS_COMMUNITY = "https://plus.google.com/communities/110811566242871492162"
|
||||||
|
@JvmField
|
||||||
|
val TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534"
|
||||||
|
@JvmField
|
||||||
|
val GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicPlayer"
|
||||||
|
@JvmField
|
||||||
|
val BASE_API_URL_KUGOU = "http://lyrics.kugou.com/"
|
||||||
|
@JvmField
|
||||||
|
val TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog"
|
||||||
|
@JvmField
|
||||||
|
val USER_PROFILE = "profile.jpg"
|
||||||
|
@JvmField
|
||||||
|
val USER_BANNER = "banner.jpg"
|
||||||
|
@JvmField
|
||||||
|
val APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/"
|
||||||
|
@JvmField
|
||||||
|
val APP_TELEGRAM_LINK = "https://t.me/retromusicapp/"
|
||||||
|
@JvmField
|
||||||
|
val APP_TWITTER_LINK = "https://twitter.com/retromusicapp"
|
||||||
|
@JvmField
|
||||||
|
val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
||||||
|
@JvmField
|
||||||
|
val CAST_SERVER_PORT = 8080
|
||||||
|
|
||||||
|
const val BASE_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
||||||
|
@JvmField
|
||||||
|
val BASE_PROJECTION = arrayOf(BaseColumns._ID, // 0
|
||||||
|
MediaStore.Audio.AudioColumns.TITLE, // 1
|
||||||
|
MediaStore.Audio.AudioColumns.TRACK, // 2
|
||||||
|
MediaStore.Audio.AudioColumns.YEAR, // 3
|
||||||
|
MediaStore.Audio.AudioColumns.DURATION, // 4
|
||||||
|
MediaStore.Audio.AudioColumns.DATA, // 5
|
||||||
|
MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
|
||||||
|
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
|
||||||
|
MediaStore.Audio.AudioColumns.ALBUM, // 8
|
||||||
|
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
|
||||||
|
MediaStore.Audio.AudioColumns.ARTIST)// 10
|
||||||
|
const val NUMBER_OF_TOP_TRACKS = 99
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
package code.name.monkey.retromusic;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.providers.RepositoryImpl;
|
|
||||||
import code.name.monkey.retromusic.providers.interfaces.Repository;
|
|
||||||
import code.name.monkey.retromusic.rest.KogouClient;
|
|
||||||
import code.name.monkey.retromusic.rest.service.KuGouApiService;
|
|
||||||
import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider;
|
|
||||||
import code.name.monkey.retromusic.util.schedulers.SchedulerProvider;
|
|
||||||
|
|
||||||
public class Injection {
|
|
||||||
|
|
||||||
public static Repository provideRepository() {
|
|
||||||
return RepositoryImpl.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BaseSchedulerProvider provideSchedulerProvider() {
|
|
||||||
return SchedulerProvider.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KuGouApiService provideKuGouApiService() {
|
|
||||||
return new KogouClient().getApiService();
|
|
||||||
}
|
|
||||||
}
|
|
23
app/src/main/java/code/name/monkey/retromusic/Injection.kt
Normal file
23
app/src/main/java/code/name/monkey/retromusic/Injection.kt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package code.name.monkey.retromusic
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.providers.RepositoryImpl
|
||||||
|
import code.name.monkey.retromusic.providers.interfaces.Repository
|
||||||
|
import code.name.monkey.retromusic.rest.KogouClient
|
||||||
|
import code.name.monkey.retromusic.rest.service.KuGouApiService
|
||||||
|
import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider
|
||||||
|
import code.name.monkey.retromusic.util.schedulers.SchedulerProvider
|
||||||
|
|
||||||
|
object Injection {
|
||||||
|
|
||||||
|
fun provideRepository(): Repository {
|
||||||
|
return RepositoryImpl.getInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun provideSchedulerProvider(): BaseSchedulerProvider {
|
||||||
|
return SchedulerProvider.getInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun provideKuGouApiService(): KuGouApiService {
|
||||||
|
return KogouClient().apiService
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,125 +0,0 @@
|
||||||
package code.name.monkey.retromusic;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import com.anjlab.android.iab.v3.BillingProcessor;
|
|
||||||
import com.anjlab.android.iab.v3.TransactionDetails;
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.multidex.MultiDexApplication;
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager;
|
|
||||||
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
|
|
||||||
|
|
||||||
public class RetroApplication extends MultiDexApplication {
|
|
||||||
|
|
||||||
public static final String PRO_VERSION_PRODUCT_ID = "pro_version";
|
|
||||||
|
|
||||||
private static RetroApplication app;
|
|
||||||
|
|
||||||
private BillingProcessor billingProcessor;
|
|
||||||
|
|
||||||
public static RetroApplication getInstance() {
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Context getContext() {
|
|
||||||
return app.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isProVersion() {
|
|
||||||
return BuildConfig.DEBUG || app.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteAppData() {
|
|
||||||
try {
|
|
||||||
// clearing app data
|
|
||||||
String packageName = app.getPackageName();
|
|
||||||
Runtime runtime = Runtime.getRuntime();
|
|
||||||
runtime.exec("pm clear " + packageName);
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
app = this;
|
|
||||||
|
|
||||||
setupErrorHandler();
|
|
||||||
|
|
||||||
// default theme
|
|
||||||
if (!ThemeStore.isConfigured(this, 3)) {
|
|
||||||
ThemeStore.editTheme(this)
|
|
||||||
.accentColorRes(R.color.md_green_A200)
|
|
||||||
.coloredNavigationBar(true)
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
|
|
||||||
.setDefaultFontPath("fonts/circular_std_book.otf")
|
|
||||||
.setFontAttrId(R.attr.fontPath)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
|
||||||
new DynamicShortcutManager(this).initDynamicShortcuts();
|
|
||||||
}
|
|
||||||
|
|
||||||
// automatically restores purchases
|
|
||||||
billingProcessor = new BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY,
|
|
||||||
new BillingProcessor.IBillingHandler() {
|
|
||||||
@Override
|
|
||||||
public void onProductPurchased(@NonNull String productId, TransactionDetails details) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPurchaseHistoryRestored() {
|
|
||||||
//Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBillingError(int errorCode, Throwable error) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBillingInitialized() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupErrorHandler() {
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
|
||||||
@Override
|
|
||||||
public void uncaughtException(Thread thread, Throwable throwable) {
|
|
||||||
handleUncaughtException(thread, throwable);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleUncaughtException(Thread thread, Throwable throwable) {
|
|
||||||
throwable.printStackTrace();
|
|
||||||
deleteAppData();
|
|
||||||
//Intent intent = new Intent(this, ErrorHandlerActivity.class);
|
|
||||||
//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
//startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLowMemory() {
|
|
||||||
super.onLowMemory();
|
|
||||||
Glide.with(this).onLowMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTerminate() {
|
|
||||||
super.onTerminate();
|
|
||||||
billingProcessor.release();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.graphics.drawable.Icon;
|
|
||||||
import android.graphics.drawable.LayerDrawable;
|
|
||||||
import android.os.Build;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
|
||||||
public final class AppShortcutIconGenerator {
|
|
||||||
public static Icon generateThemedIcon(Context context, int iconId) {
|
|
||||||
if (PreferenceUtil.getInstance().coloredAppShortcuts()){
|
|
||||||
return generateUserThemedIcon(context, iconId);
|
|
||||||
} else {
|
|
||||||
return generateDefaultThemedIcon(context, iconId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Icon generateDefaultThemedIcon(Context context, int iconId) {
|
|
||||||
// Return an Icon of iconId with default colors
|
|
||||||
return generateThemedIcon(context, iconId,
|
|
||||||
context.getColor(R.color.app_shortcut_default_foreground),
|
|
||||||
context.getColor(R.color.app_shortcut_default_background)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Icon generateUserThemedIcon(Context context, int iconId) {
|
|
||||||
// Get background color from context's theme
|
|
||||||
final TypedValue typedColorBackground = new TypedValue();
|
|
||||||
context.getTheme().resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true);
|
|
||||||
|
|
||||||
// Return an Icon of iconId with those colors
|
|
||||||
return generateThemedIcon(context, iconId,
|
|
||||||
ThemeStore.accentColor(context),
|
|
||||||
typedColorBackground.data
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Icon generateThemedIcon(Context context, int iconId, int foregroundColor, int backgroundColor) {
|
|
||||||
// Get and tint foreground and background drawables
|
|
||||||
Drawable vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor);
|
|
||||||
Drawable backgroundDrawable = RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor);
|
|
||||||
|
|
||||||
// Squash the two drawables together
|
|
||||||
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, vectorDrawable});
|
|
||||||
|
|
||||||
// Return as an Icon
|
|
||||||
return Icon.createWithBitmap(drawableToBitmap(layerDrawable));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bitmap drawableToBitmap(Drawable drawable) {
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
|
||||||
drawable.draw(canvas);
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
|
|
||||||
import static code.name.monkey.retromusic.Constants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class AppShortcutLauncherActivity extends Activity {
|
|
||||||
public static final String KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType";
|
|
||||||
|
|
||||||
public static final int SHORTCUT_TYPE_SHUFFLE_ALL = 0;
|
|
||||||
public static final int SHORTCUT_TYPE_TOP_TRACKS = 1;
|
|
||||||
public static final int SHORTCUT_TYPE_LAST_ADDED = 2;
|
|
||||||
public static final int SHORTCUT_TYPE_NONE = 3;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
int shortcutType = SHORTCUT_TYPE_NONE;
|
|
||||||
|
|
||||||
// Set shortcutType from the intent extras
|
|
||||||
Bundle extras = getIntent().getExtras();
|
|
||||||
if (extras != null) {
|
|
||||||
//noinspection WrongConstant
|
|
||||||
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (shortcutType) {
|
|
||||||
case SHORTCUT_TYPE_SHUFFLE_ALL:
|
|
||||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_SHUFFLE,
|
|
||||||
new ShuffleAllPlaylist(getApplicationContext()));
|
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.getId());
|
|
||||||
break;
|
|
||||||
case SHORTCUT_TYPE_TOP_TRACKS:
|
|
||||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
|
||||||
new MyTopTracksPlaylist(getApplicationContext()));
|
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.getId());
|
|
||||||
break;
|
|
||||||
case SHORTCUT_TYPE_LAST_ADDED:
|
|
||||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
|
||||||
new LastAddedPlaylist(getApplicationContext()));
|
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.getId());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startServiceWithPlaylist(int shuffleMode, Playlist playlist) {
|
|
||||||
Intent intent = new Intent(this, MusicService.class);
|
|
||||||
intent.setAction(ACTION_PLAY_PLAYLIST);
|
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist);
|
|
||||||
bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode);
|
|
||||||
|
|
||||||
intent.putExtras(bundle);
|
|
||||||
|
|
||||||
startService(intent);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
|
||||||
import android.content.pm.ShortcutManager;
|
|
||||||
import android.graphics.drawable.Icon;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
||||||
public class DynamicShortcutManager {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
private ShortcutManager shortcutManager;
|
|
||||||
|
|
||||||
public DynamicShortcutManager(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
shortcutManager = this.context.getSystemService(ShortcutManager.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShortcutInfo createShortcut(Context context, String id, String shortLabel, String longLabel, Icon icon, Intent intent) {
|
|
||||||
return new ShortcutInfo.Builder(context, id)
|
|
||||||
.setShortLabel(shortLabel)
|
|
||||||
.setLongLabel(longLabel)
|
|
||||||
.setIcon(icon)
|
|
||||||
.setIntent(intent)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initDynamicShortcuts() {
|
|
||||||
if (shortcutManager.getDynamicShortcuts().size() == 0) {
|
|
||||||
shortcutManager.setDynamicShortcuts(getDefaultShortcuts());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateDynamicShortcuts() {
|
|
||||||
shortcutManager.updateShortcuts(getDefaultShortcuts());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ShortcutInfo> getDefaultShortcuts() {
|
|
||||||
return (Arrays.asList(
|
|
||||||
new ShuffleAllShortcutType(context).getShortcutInfo(),
|
|
||||||
new TopTracksShortcutType(context).getShortcutInfo(),
|
|
||||||
new LastAddedShortcutType(context).getShortcutInfo()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reportShortcutUsed(Context context, String shortcutId){
|
|
||||||
context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
||||||
public abstract class BaseShortcutType {
|
|
||||||
|
|
||||||
static final String ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id.";
|
|
||||||
|
|
||||||
Context context;
|
|
||||||
|
|
||||||
public BaseShortcutType(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
static public String getId() {
|
|
||||||
return ID_PREFIX + "invalid";
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract ShortcutInfo getShortcutInfo();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
|
|
||||||
*
|
|
||||||
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Intent getPlaySongsIntent(int shortcutType) {
|
|
||||||
Intent intent = new Intent(context, AppShortcutLauncherActivity.class);
|
|
||||||
intent.setAction(Intent.ACTION_VIEW);
|
|
||||||
|
|
||||||
Bundle b = new Bundle();
|
|
||||||
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType);
|
|
||||||
|
|
||||||
intent.putExtras(b);
|
|
||||||
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
||||||
public final class LastAddedShortcutType extends BaseShortcutType {
|
|
||||||
public LastAddedShortcutType(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getId() {
|
|
||||||
return ID_PREFIX + "last_added";
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShortcutInfo getShortcutInfo() {
|
|
||||||
return new ShortcutInfo.Builder(context, getId())
|
|
||||||
.setShortLabel(context.getString(R.string.app_shortcut_last_added_short))
|
|
||||||
.setLongLabel(context.getString(R.string.app_shortcut_last_added_long))
|
|
||||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added))
|
|
||||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
||||||
public final class ShuffleAllShortcutType extends BaseShortcutType {
|
|
||||||
public ShuffleAllShortcutType(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getId() {
|
|
||||||
return ID_PREFIX + "shuffle_all";
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShortcutInfo getShortcutInfo() {
|
|
||||||
return new ShortcutInfo.Builder(context, getId())
|
|
||||||
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
|
|
||||||
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
|
|
||||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
|
|
||||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.ShortcutInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
|
||||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Adrian Campos
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
|
||||||
public final class TopTracksShortcutType extends BaseShortcutType {
|
|
||||||
public TopTracksShortcutType(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getId() {
|
|
||||||
return ID_PREFIX + "top_tracks";
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShortcutInfo getShortcutInfo() {
|
|
||||||
return new ShortcutInfo.Builder(context, getId())
|
|
||||||
.setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short))
|
|
||||||
.setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long))
|
|
||||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks))
|
|
||||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,174 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appwidgets;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Point;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
|
||||||
import com.bumptech.glide.request.target.SimpleTarget;
|
|
||||||
import com.bumptech.glide.request.target.Target;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
|
||||||
import code.name.monkey.retromusic.Constants;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
|
||||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
|
||||||
|
|
||||||
public class AppWidgetBig extends BaseAppWidget {
|
|
||||||
|
|
||||||
public static final String NAME = "app_widget_big";
|
|
||||||
|
|
||||||
private static AppWidgetBig mInstance;
|
|
||||||
private Target<Bitmap> target; // for cancellation
|
|
||||||
|
|
||||||
public static synchronized AppWidgetBig getInstance() {
|
|
||||||
if (mInstance == null) {
|
|
||||||
mInstance = new AppWidgetBig();
|
|
||||||
}
|
|
||||||
return mInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
|
||||||
* actions if service not running.
|
|
||||||
*/
|
|
||||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
|
||||||
R.layout.app_widget_big);
|
|
||||||
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
|
||||||
MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
|
|
||||||
|
|
||||||
linkButtons(context, appWidgetView);
|
|
||||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update all active widget instances by pushing changes
|
|
||||||
*/
|
|
||||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
|
||||||
R.layout.app_widget_big);
|
|
||||||
|
|
||||||
final boolean isPlaying = service.isPlaying();
|
|
||||||
final Song song = service.getCurrentSong();
|
|
||||||
|
|
||||||
// Set the titles and artwork
|
|
||||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
|
||||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
|
||||||
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set correct drawable for pause state
|
|
||||||
int playPauseRes =
|
|
||||||
isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, playPauseRes,
|
|
||||||
MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
|
|
||||||
|
|
||||||
// Set prev/next button drawables
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
|
|
||||||
|
|
||||||
// Link actions buttons to intents
|
|
||||||
linkButtons(service, appWidgetView);
|
|
||||||
|
|
||||||
// Load the album cover async and push the update on completion
|
|
||||||
Point p = RetroUtil.getScreenSize(service);
|
|
||||||
final int widgetImageSize = Math.min(p.x, p.y);
|
|
||||||
final Context appContext = service.getApplicationContext();
|
|
||||||
service.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (target != null) {
|
|
||||||
Glide.clear(target);
|
|
||||||
}
|
|
||||||
target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
|
|
||||||
.checkIgnoreMediaStore(appContext)
|
|
||||||
.asBitmap().build()
|
|
||||||
.into(new SimpleTarget<Bitmap>(widgetImageSize, widgetImageSize) {
|
|
||||||
@Override
|
|
||||||
public void onResourceReady(Bitmap resource,
|
|
||||||
GlideAnimation<? super Bitmap> glideAnimation) {
|
|
||||||
update(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
|
||||||
super.onLoadFailed(e, errorDrawable);
|
|
||||||
update(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update(@Nullable Bitmap bitmap) {
|
|
||||||
if (bitmap == null) {
|
|
||||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
|
||||||
} else {
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.image, bitmap);
|
|
||||||
}
|
|
||||||
pushUpdate(appContext, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link up various button actions using {@link PendingIntent}.
|
|
||||||
*/
|
|
||||||
private void linkButtons(final Context context, final RemoteViews views) {
|
|
||||||
Intent action;
|
|
||||||
PendingIntent pendingIntent;
|
|
||||||
|
|
||||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
|
||||||
|
|
||||||
// Home
|
|
||||||
action = new Intent(context, NowPayingActivity.class);
|
|
||||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
|
||||||
views.setOnClickPendingIntent(R.id.clickable_area, pendingIntent);
|
|
||||||
|
|
||||||
// Previous track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
|
||||||
|
|
||||||
// Play and pause
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
|
||||||
|
|
||||||
// Next track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appwidgets;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
|
||||||
import com.bumptech.glide.request.target.SimpleTarget;
|
|
||||||
import com.bumptech.glide.request.target.Target;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.palette.graphics.Palette;
|
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
|
||||||
import code.name.monkey.retromusic.Constants;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
|
||||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
|
||||||
|
|
||||||
public class AppWidgetCard extends BaseAppWidget {
|
|
||||||
|
|
||||||
public static final String NAME = "app_widget_card";
|
|
||||||
|
|
||||||
private static AppWidgetCard mInstance;
|
|
||||||
private static int imageSize = 0;
|
|
||||||
private static float cardRadius = 0f;
|
|
||||||
private Target<BitmapPaletteWrapper> target; // for cancellation
|
|
||||||
|
|
||||||
public static synchronized AppWidgetCard getInstance() {
|
|
||||||
if (mInstance == null) {
|
|
||||||
mInstance = new AppWidgetCard();
|
|
||||||
}
|
|
||||||
return mInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
|
||||||
* actions if service not running.
|
|
||||||
*/
|
|
||||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
|
||||||
R.layout.app_widget_card);
|
|
||||||
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
|
|
||||||
linkButtons(context, appWidgetView);
|
|
||||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update all active widget instances by pushing changes
|
|
||||||
*/
|
|
||||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
|
||||||
R.layout.app_widget_card);
|
|
||||||
|
|
||||||
final boolean isPlaying = service.isPlaying();
|
|
||||||
final Song song = service.getCurrentSong();
|
|
||||||
|
|
||||||
// Set the titles and artwork
|
|
||||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
|
||||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
|
||||||
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set correct drawable for pause state
|
|
||||||
int playPauseRes =
|
|
||||||
isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, playPauseRes,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
|
|
||||||
|
|
||||||
// Set prev/next button drawables
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
|
|
||||||
|
|
||||||
// Link actions buttons to intents
|
|
||||||
linkButtons(service, appWidgetView);
|
|
||||||
|
|
||||||
if (imageSize == 0) {
|
|
||||||
imageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_card_image_size);
|
|
||||||
}
|
|
||||||
if (cardRadius == 0f) {
|
|
||||||
cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the album cover async and push the update on completion
|
|
||||||
service.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (target != null) {
|
|
||||||
Glide.clear(target);
|
|
||||||
}
|
|
||||||
target = SongGlideRequest.Builder.from(Glide.with(service), song)
|
|
||||||
.checkIgnoreMediaStore(service)
|
|
||||||
.generatePalette(service).build()
|
|
||||||
.centerCrop()
|
|
||||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
|
||||||
@Override
|
|
||||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
|
||||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
|
||||||
Palette palette = resource.getPalette();
|
|
||||||
update(resource.getBitmap(), palette.getVibrantColor(palette
|
|
||||||
.getMutedColor(MaterialValueHelper.getSecondaryTextColor(service, true))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
|
||||||
super.onLoadFailed(e, errorDrawable);
|
|
||||||
update(null, MaterialValueHelper.getSecondaryTextColor(service, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update(@Nullable Bitmap bitmap, int color) {
|
|
||||||
// Set correct drawable for pause state
|
|
||||||
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp
|
|
||||||
: R.drawable.ic_play_arrow_white_24dp;
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause,
|
|
||||||
createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f));
|
|
||||||
|
|
||||||
// Set prev/next button drawables
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
color), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
color), 1f));
|
|
||||||
|
|
||||||
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
|
|
||||||
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize,
|
|
||||||
cardRadius, 0, cardRadius, 0);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap);
|
|
||||||
|
|
||||||
pushUpdate(service, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link up various button actions using {@link PendingIntent}.
|
|
||||||
*/
|
|
||||||
private void linkButtons(final Context context, final RemoteViews views) {
|
|
||||||
Intent action;
|
|
||||||
PendingIntent pendingIntent;
|
|
||||||
|
|
||||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
|
||||||
|
|
||||||
// Home
|
|
||||||
action = new Intent(context, NowPayingActivity.class);
|
|
||||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent);
|
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent);
|
|
||||||
|
|
||||||
// Previous track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
|
||||||
|
|
||||||
// Play and pause
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
|
||||||
|
|
||||||
// Next track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,182 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appwidgets;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.palette.graphics.Palette;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
|
||||||
import code.name.monkey.retromusic.Constants;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
|
||||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
|
||||||
import com.bumptech.glide.request.target.SimpleTarget;
|
|
||||||
import com.bumptech.glide.request.target.Target;
|
|
||||||
|
|
||||||
public class AppWidgetClassic extends BaseAppWidget {
|
|
||||||
|
|
||||||
public static final String NAME = "app_widget_classic";
|
|
||||||
|
|
||||||
private static AppWidgetClassic mInstance;
|
|
||||||
private static int imageSize = 0;
|
|
||||||
private static float cardRadius = 0f;
|
|
||||||
private Target<BitmapPaletteWrapper> target; // for cancellation
|
|
||||||
|
|
||||||
public static synchronized AppWidgetClassic getInstance() {
|
|
||||||
if (mInstance == null) {
|
|
||||||
mInstance = new AppWidgetClassic();
|
|
||||||
}
|
|
||||||
return mInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
|
||||||
* actions if service not running.
|
|
||||||
*/
|
|
||||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
|
||||||
R.layout.app_widget_classic);
|
|
||||||
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
|
|
||||||
linkButtons(context, appWidgetView);
|
|
||||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update all active widget instances by pushing changes
|
|
||||||
*/
|
|
||||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
|
||||||
R.layout.app_widget_classic);
|
|
||||||
|
|
||||||
final boolean isPlaying = service.isPlaying();
|
|
||||||
final Song song = service.getCurrentSong();
|
|
||||||
|
|
||||||
// Set the titles and artwork
|
|
||||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
|
||||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
|
||||||
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link actions buttons to intents
|
|
||||||
linkButtons(service, appWidgetView);
|
|
||||||
|
|
||||||
if (imageSize == 0) {
|
|
||||||
imageSize = service.getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.app_widget_classic_image_size);
|
|
||||||
}
|
|
||||||
if (cardRadius == 0f) {
|
|
||||||
cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the album cover async and push the update on completion
|
|
||||||
final Context appContext = service.getApplicationContext();
|
|
||||||
service.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (target != null) {
|
|
||||||
Glide.clear(target);
|
|
||||||
}
|
|
||||||
target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
|
|
||||||
.checkIgnoreMediaStore(appContext)
|
|
||||||
.generatePalette(service).build()
|
|
||||||
.centerCrop()
|
|
||||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
|
||||||
@Override
|
|
||||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
|
||||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
|
||||||
Palette palette = resource.getPalette();
|
|
||||||
update(resource.getBitmap(), palette.getVibrantColor(palette
|
|
||||||
.getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
|
||||||
super.onLoadFailed(e, errorDrawable);
|
|
||||||
update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update(@Nullable Bitmap bitmap, int color) {
|
|
||||||
// Set correct drawable for pause state
|
|
||||||
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp
|
|
||||||
: R.drawable.ic_play_arrow_white_24dp;
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause,
|
|
||||||
createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f));
|
|
||||||
|
|
||||||
// Set prev/next button drawables
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
color), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
color), 1f));
|
|
||||||
|
|
||||||
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
|
|
||||||
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize,
|
|
||||||
cardRadius, 0, cardRadius, 0);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap);
|
|
||||||
|
|
||||||
pushUpdate(appContext, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link up various button actions using {@link PendingIntent}.
|
|
||||||
*/
|
|
||||||
private void linkButtons(final Context context, final RemoteViews views) {
|
|
||||||
Intent action;
|
|
||||||
PendingIntent pendingIntent;
|
|
||||||
|
|
||||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
|
||||||
|
|
||||||
// Home
|
|
||||||
action = new Intent(context, NowPayingActivity.class);
|
|
||||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent);
|
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent);
|
|
||||||
|
|
||||||
// Previous track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
|
||||||
|
|
||||||
// Play and pause
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
|
||||||
|
|
||||||
// Next track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,187 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appwidgets;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.palette.graphics.Palette;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
|
||||||
import code.name.monkey.retromusic.Constants;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget;
|
|
||||||
import code.name.monkey.retromusic.glide.SongGlideRequest;
|
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
|
||||||
import com.bumptech.glide.request.target.SimpleTarget;
|
|
||||||
import com.bumptech.glide.request.target.Target;
|
|
||||||
|
|
||||||
public class AppWidgetSmall extends BaseAppWidget {
|
|
||||||
|
|
||||||
public static final String NAME = "app_widget_small";
|
|
||||||
|
|
||||||
private static AppWidgetSmall mInstance;
|
|
||||||
private static int imageSize = 0;
|
|
||||||
private static float cardRadius = 0f;
|
|
||||||
private Target<BitmapPaletteWrapper> target; // for cancellation
|
|
||||||
|
|
||||||
public static synchronized AppWidgetSmall getInstance() {
|
|
||||||
if (mInstance == null) {
|
|
||||||
mInstance = new AppWidgetSmall();
|
|
||||||
}
|
|
||||||
return mInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize given widgets to default state, where we launch Music on default click and hide
|
|
||||||
* actions if service not running.
|
|
||||||
*/
|
|
||||||
protected void defaultAppWidget(final Context context, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(),
|
|
||||||
R.layout.app_widget_small);
|
|
||||||
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp,
|
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
|
|
||||||
|
|
||||||
linkButtons(context, appWidgetView);
|
|
||||||
pushUpdate(context, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update all active widget instances by pushing changes
|
|
||||||
*/
|
|
||||||
public void performUpdate(final MusicService service, final int[] appWidgetIds) {
|
|
||||||
final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(),
|
|
||||||
R.layout.app_widget_small);
|
|
||||||
|
|
||||||
final boolean isPlaying = service.isPlaying();
|
|
||||||
final Song song = service.getCurrentSong();
|
|
||||||
|
|
||||||
// Set the titles and artwork
|
|
||||||
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
if (TextUtils.isEmpty(song.title) || TextUtils.isEmpty(song.artistName)) {
|
|
||||||
appWidgetView.setTextViewText(R.id.text_separator, "");
|
|
||||||
} else {
|
|
||||||
appWidgetView.setTextViewText(R.id.text_separator, "•");
|
|
||||||
}
|
|
||||||
|
|
||||||
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
|
|
||||||
appWidgetView.setTextViewText(R.id.title, song.title);
|
|
||||||
appWidgetView.setTextViewText(R.id.text, song.artistName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link actions buttons to intents
|
|
||||||
linkButtons(service, appWidgetView);
|
|
||||||
|
|
||||||
if (imageSize == 0) {
|
|
||||||
imageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_small_image_size);
|
|
||||||
}
|
|
||||||
if (cardRadius == 0f) {
|
|
||||||
cardRadius = service.getResources().getDimension(R.dimen.app_widget_card_radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the album cover async and push the update on completion
|
|
||||||
final Context appContext = service.getApplicationContext();
|
|
||||||
service.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (target != null) {
|
|
||||||
Glide.clear(target);
|
|
||||||
}
|
|
||||||
target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
|
|
||||||
.checkIgnoreMediaStore(appContext)
|
|
||||||
.generatePalette(service).build()
|
|
||||||
.centerCrop()
|
|
||||||
.into(new SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
|
|
||||||
@Override
|
|
||||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
|
||||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
|
||||||
Palette palette = resource.getPalette();
|
|
||||||
update(resource.getBitmap(), palette.getVibrantColor(palette
|
|
||||||
.getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
|
||||||
super.onLoadFailed(e, errorDrawable);
|
|
||||||
update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update(@Nullable Bitmap bitmap, int color) {
|
|
||||||
// Set correct drawable for pause state
|
|
||||||
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp
|
|
||||||
: R.drawable.ic_play_arrow_white_24dp;
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause,
|
|
||||||
createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color), 1f));
|
|
||||||
|
|
||||||
// Set prev/next button drawables
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
|
|
||||||
color), 1f));
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(
|
|
||||||
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
|
|
||||||
color), 1f));
|
|
||||||
|
|
||||||
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
|
|
||||||
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize,
|
|
||||||
cardRadius, 0, 0, 0);
|
|
||||||
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap);
|
|
||||||
|
|
||||||
pushUpdate(appContext, appWidgetIds, appWidgetView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link up various button actions using {@link PendingIntent}.
|
|
||||||
*/
|
|
||||||
private void linkButtons(final Context context, final RemoteViews views) {
|
|
||||||
Intent action;
|
|
||||||
PendingIntent pendingIntent;
|
|
||||||
|
|
||||||
final ComponentName serviceName = new ComponentName(context, MusicService.class);
|
|
||||||
|
|
||||||
// Home
|
|
||||||
action = new Intent(context, NowPayingActivity.class);
|
|
||||||
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
|
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent);
|
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent);
|
|
||||||
|
|
||||||
// Previous track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
|
|
||||||
|
|
||||||
// Play and pause
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
|
|
||||||
|
|
||||||
// Next track
|
|
||||||
pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName);
|
|
||||||
views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appwidgets;
|
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Eugene Cheung (arkon)
|
|
||||||
*/
|
|
||||||
public class BootReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
|
|
||||||
|
|
||||||
// Start music service if there are any existing widgets
|
|
||||||
if (widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetBig.class)).length > 0 ||
|
|
||||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetClassic.class)).length > 0 ||
|
|
||||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetSmall.class)).length > 0 ||
|
|
||||||
widgetManager.getAppWidgetIds(new ComponentName(context, AppWidgetCard.class)).length > 0) {
|
|
||||||
final Intent serviceIntent = new Intent(context, MusicService.class);
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // not allowed on Oreo
|
|
||||||
context.startService(serviceIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,163 +0,0 @@
|
||||||
package code.name.monkey.retromusic.appwidgets.base;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.appwidget.AppWidgetManager;
|
|
||||||
import android.appwidget.AppWidgetProvider;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapShader;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Path;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.Constants;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
|
|
||||||
public abstract class BaseAppWidget extends AppWidgetProvider {
|
|
||||||
|
|
||||||
public static final String NAME = "app_widget";
|
|
||||||
|
|
||||||
protected static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) {
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier),
|
|
||||||
(int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas c = new Canvas(bitmap);
|
|
||||||
drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
|
|
||||||
drawable.draw(c);
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Bitmap createRoundedBitmap(Drawable drawable, int width, int height, float tl,
|
|
||||||
float tr, float bl, float br) {
|
|
||||||
if (drawable == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas c = new Canvas(bitmap);
|
|
||||||
drawable.setBounds(0, 0, width, height);
|
|
||||||
drawable.draw(c);
|
|
||||||
|
|
||||||
Bitmap rounded = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
||||||
|
|
||||||
Canvas canvas = new Canvas(rounded);
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setShader(
|
|
||||||
new BitmapShader(bitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
canvas.drawPath(composeRoundedRectPath(new RectF(0, 0, width, height), tl, tr, bl, br), paint);
|
|
||||||
|
|
||||||
return rounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Path composeRoundedRectPath(RectF rect, float tl, float tr, float bl, float br) {
|
|
||||||
Path path = new Path();
|
|
||||||
tl = tl < 0 ? 0 : tl;
|
|
||||||
tr = tr < 0 ? 0 : tr;
|
|
||||||
bl = bl < 0 ? 0 : bl;
|
|
||||||
br = br < 0 ? 0 : br;
|
|
||||||
|
|
||||||
path.moveTo(rect.left + tl, rect.top);
|
|
||||||
path.lineTo(rect.right - tr, rect.top);
|
|
||||||
path.quadTo(rect.right, rect.top, rect.right, rect.top + tr);
|
|
||||||
path.lineTo(rect.right, rect.bottom - br);
|
|
||||||
path.quadTo(rect.right, rect.bottom, rect.right - br, rect.bottom);
|
|
||||||
path.lineTo(rect.left + bl, rect.bottom);
|
|
||||||
path.quadTo(rect.left, rect.bottom, rect.left, rect.bottom - bl);
|
|
||||||
path.lineTo(rect.left, rect.top + tl);
|
|
||||||
path.quadTo(rect.left, rect.top, rect.left + tl, rect.top);
|
|
||||||
path.close();
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager,
|
|
||||||
final int[] appWidgetIds) {
|
|
||||||
defaultAppWidget(context, appWidgetIds);
|
|
||||||
final Intent updateIntent = new Intent(Constants.APP_WIDGET_UPDATE);
|
|
||||||
updateIntent.putExtra(Constants.EXTRA_APP_WIDGET_NAME, NAME);
|
|
||||||
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
|
|
||||||
updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
|
||||||
context.sendBroadcast(updateIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a change notification coming over from {@link MusicService}
|
|
||||||
*/
|
|
||||||
public void notifyChange(final MusicService service, final String what) {
|
|
||||||
if (hasInstances(service)) {
|
|
||||||
if (Constants.META_CHANGED.equals(what) || Constants.PLAY_STATE_CHANGED.equals(what)) {
|
|
||||||
performUpdate(service, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void pushUpdate(final Context context, final int[] appWidgetIds,
|
|
||||||
final RemoteViews views) {
|
|
||||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
|
||||||
if (appWidgetIds != null) {
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetIds, views);
|
|
||||||
} else {
|
|
||||||
appWidgetManager.updateAppWidget(new ComponentName(context, getClass()), views);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check against {@link AppWidgetManager} if there are any instances of this widget.
|
|
||||||
*/
|
|
||||||
protected boolean hasInstances(final Context context) {
|
|
||||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
|
||||||
final int[] mAppWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context,
|
|
||||||
getClass()));
|
|
||||||
return mAppWidgetIds.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PendingIntent buildPendingIntent(Context context, final String action,
|
|
||||||
final ComponentName serviceName) {
|
|
||||||
Intent intent = new Intent(action);
|
|
||||||
intent.setComponent(serviceName);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
return PendingIntent.getForegroundService(context, 0, intent, 0);
|
|
||||||
} else {
|
|
||||||
return PendingIntent.getService(context, 0, intent, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected void defaultAppWidget(final Context context, final int[] appWidgetIds);
|
|
||||||
|
|
||||||
abstract public void performUpdate(final MusicService service, final int[] appWidgetIds);
|
|
||||||
|
|
||||||
protected Drawable getAlbumArtDrawable(final Resources resources, final Bitmap bitmap) {
|
|
||||||
Drawable image;
|
|
||||||
if (bitmap == null) {
|
|
||||||
image = resources.getDrawable(R.drawable.default_album_art);
|
|
||||||
} else {
|
|
||||||
image = new BitmapDrawable(resources, bitmap);
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getSongArtistAndAlbum(final Song song) {
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append(song.artistName);
|
|
||||||
if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) {
|
|
||||||
builder.append(" • ");
|
|
||||||
}
|
|
||||||
builder.append(song.albumName);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,6 +16,8 @@ import code.name.monkey.retromusic.Constants;
|
||||||
import code.name.monkey.retromusic.model.Song;
|
import code.name.monkey.retromusic.model.Song;
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
import code.name.monkey.retromusic.util.RetroUtil;
|
||||||
|
|
||||||
|
import static code.name.monkey.retromusic.Constants.CAST_SERVER_PORT;
|
||||||
|
|
||||||
public class CastHelper {
|
public class CastHelper {
|
||||||
|
|
||||||
public static void startCasting(CastSession castSession, Song song) {
|
public static void startCasting(CastSession castSession, Song song) {
|
||||||
|
@ -23,22 +25,22 @@ public class CastHelper {
|
||||||
String ipAddress = RetroUtil.getIPAddress(true);
|
String ipAddress = RetroUtil.getIPAddress(true);
|
||||||
URL baseUrl;
|
URL baseUrl;
|
||||||
try {
|
try {
|
||||||
baseUrl = new URL("https", ipAddress, Constants.CAST_SERVER_PORT, "");
|
baseUrl = new URL("https", ipAddress,CAST_SERVER_PORT, "");
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String songUrl = baseUrl.toString() + "/song?id=" + song.id;
|
String songUrl = baseUrl.toString() + "/song?id=" + song.getId();
|
||||||
String albumArtUrl = baseUrl.toString() + "/albumart?id=" + song.albumId;
|
String albumArtUrl = baseUrl.toString() + "/albumart?id=" + song.getAlbumId();
|
||||||
|
|
||||||
|
|
||||||
MediaMetadata musicMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
|
MediaMetadata musicMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
|
||||||
|
|
||||||
musicMetadata.putString(MediaMetadata.KEY_TITLE, song.title);
|
musicMetadata.putString(MediaMetadata.KEY_TITLE, song.getTitle());
|
||||||
musicMetadata.putString(MediaMetadata.KEY_ARTIST, song.artistName);
|
musicMetadata.putString(MediaMetadata.KEY_ARTIST, song.getArtistName());
|
||||||
musicMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, song.albumName);
|
musicMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, song.getAlbumName());
|
||||||
musicMetadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.trackNumber);
|
musicMetadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.getTrackNumber());
|
||||||
musicMetadata.addImage(new WebImage(Uri.parse(albumArtUrl)));
|
musicMetadata.addImage(new WebImage(Uri.parse(albumArtUrl)));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -46,7 +48,7 @@ public class CastHelper {
|
||||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||||
.setContentType("audio/mpeg")
|
.setContentType("audio/mpeg")
|
||||||
.setMetadata(musicMetadata)
|
.setMetadata(musicMetadata)
|
||||||
.setStreamDuration(song.duration)
|
.setStreamDuration(song.getDuration())
|
||||||
.build();
|
.build();
|
||||||
RemoteMediaClient remoteMediaClient = castSession.getRemoteMediaClient();
|
RemoteMediaClient remoteMediaClient = castSession.getRemoteMediaClient();
|
||||||
remoteMediaClient.load(mediaInfo, new MediaLoadOptions.Builder()
|
remoteMediaClient.load(mediaInfo, new MediaLoadOptions.Builder()
|
||||||
|
|
|
@ -13,13 +13,15 @@ import code.name.monkey.retromusic.Constants;
|
||||||
import code.name.monkey.retromusic.util.RetroUtil;
|
import code.name.monkey.retromusic.util.RetroUtil;
|
||||||
import fi.iki.elonen.NanoHTTPD;
|
import fi.iki.elonen.NanoHTTPD;
|
||||||
|
|
||||||
|
import static code.name.monkey.retromusic.Constants.CAST_SERVER_PORT;
|
||||||
|
|
||||||
public class WebServer extends NanoHTTPD {
|
public class WebServer extends NanoHTTPD {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private Uri songUri, albumArtUri;
|
private Uri songUri, albumArtUri;
|
||||||
|
|
||||||
public WebServer(Context context) {
|
public WebServer(Context context) {
|
||||||
super(Constants.CAST_SERVER_PORT);
|
super(CAST_SERVER_PORT);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
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 androidx.recyclerview.widget.DefaultItemAnimator;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
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.loaders.PlaylistLoader;
|
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.ui.adapter.playlist.AddToPlaylist;
|
|
||||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
|
|
||||||
*/
|
|
||||||
public class AddToPlaylistDialog extends RoundedBottomSheetDialogFragment {
|
|
||||||
|
|
||||||
@BindView(R.id.playlists)
|
|
||||||
RecyclerView playlist;
|
|
||||||
|
|
||||||
@BindView(R.id.title)
|
|
||||||
TextView title;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static AddToPlaylistDialog create(Song song) {
|
|
||||||
ArrayList<Song> list = new ArrayList<>();
|
|
||||||
list.add(song);
|
|
||||||
return create(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static AddToPlaylistDialog create(ArrayList<Song> songs) {
|
|
||||||
AddToPlaylistDialog dialog = new AddToPlaylistDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putParcelableArrayList("songs", songs);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
View layout = inflater.inflate(R.layout.dialog_add_to_playlist, container, false);
|
|
||||||
ButterKnife.bind(this, layout);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@OnClick(R.id.action_add_playlist)
|
|
||||||
void newPlaylist() {
|
|
||||||
final ArrayList<Song> songs = getArguments().getParcelableArrayList("songs");
|
|
||||||
CreatePlaylistDialog.create(songs)
|
|
||||||
.show(getActivity().getSupportFragmentManager(), "ADD_TO_PLAYLIST");
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
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 AddToPlaylist playlistAdapter = new AddToPlaylist(getActivity(), playlists, R.layout.item_playlist, songs, getDialog());
|
|
||||||
playlist.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
||||||
playlist.setItemAnimator(new DefaultItemAnimator());
|
|
||||||
playlist.setAdapter(playlistAdapter);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import butterknife.ButterKnife
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.loaders.PlaylistLoader
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.ui.adapter.playlist.AddToPlaylist
|
||||||
|
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment
|
||||||
|
import kotlinx.android.synthetic.main.dialog_add_to_playlist.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class AddToPlaylistDialog : RoundedBottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
val layout = inflater.inflate(R.layout.dialog_add_to_playlist, container, false)
|
||||||
|
ButterKnife.bind(this, layout)
|
||||||
|
return layout
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
actionAddPlaylist.setOnClickListener {
|
||||||
|
val songs = arguments!!.getParcelableArrayList<Song>("songs")
|
||||||
|
CreatePlaylistDialog.create(songs).show(activity!!.supportFragmentManager, "ADD_TO_PLAYLIST")
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
val songs = arguments!!.getParcelableArrayList<Song>("songs")
|
||||||
|
val playlists = PlaylistLoader.getAllPlaylists(activity!!).blockingFirst()
|
||||||
|
val playlistAdapter = AddToPlaylist(activity!!, playlists, R.layout.item_playlist, songs!!, dialog)
|
||||||
|
recyclerView.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
itemAnimator = DefaultItemAnimator()
|
||||||
|
adapter = playlistAdapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun create(song: Song): AddToPlaylistDialog {
|
||||||
|
val list = ArrayList<Song>()
|
||||||
|
list.add(song)
|
||||||
|
return create(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(songs: ArrayList<Song>): AddToPlaylistDialog {
|
||||||
|
val dialog = AddToPlaylistDialog()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putParcelableArrayList("songs", songs)
|
||||||
|
dialog.arguments = args
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Html;
|
|
||||||
|
|
||||||
import com.afollestad.materialdialogs.DialogAction;
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist;
|
|
||||||
|
|
||||||
|
|
||||||
public class ClearSmartPlaylistDialog extends DialogFragment {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static ClearSmartPlaylistDialog create(AbsSmartPlaylist playlist) {
|
|
||||||
ClearSmartPlaylistDialog dialog = new ClearSmartPlaylistDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putParcelable("playlist", playlist);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
//noinspection unchecked
|
|
||||||
final AbsSmartPlaylist playlist = getArguments().getParcelable("playlist");
|
|
||||||
int title = R.string.clear_playlist_title;
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
CharSequence content = Html.fromHtml(getString(R.string.clear_playlist_x, playlist.name));
|
|
||||||
|
|
||||||
return new MaterialDialog.Builder(getActivity())
|
|
||||||
.title(title)
|
|
||||||
.content(content)
|
|
||||||
.positiveText(R.string.clear_action)
|
|
||||||
.negativeText(android.R.string.cancel)
|
|
||||||
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
|
||||||
@Override
|
|
||||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
|
||||||
if (getActivity() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
playlist.clear(getActivity());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Html
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
|
||||||
|
|
||||||
|
class ClearSmartPlaylistDialog : DialogFragment() {
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
|
||||||
|
val playlist = arguments!!.getParcelable<AbsSmartPlaylist>("playlist")
|
||||||
|
val title = R.string.clear_playlist_title
|
||||||
|
|
||||||
|
val content = Html.fromHtml(getString(R.string.clear_playlist_x, playlist!!.name))
|
||||||
|
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(title)
|
||||||
|
.content(content)
|
||||||
|
.positiveText(R.string.clear_action)
|
||||||
|
.negativeText(android.R.string.cancel)
|
||||||
|
.onPositive { _, _ ->
|
||||||
|
if (activity == null) {
|
||||||
|
return@onPositive
|
||||||
|
}
|
||||||
|
playlist.clear(activity)
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun create(playlist: AbsSmartPlaylist): ClearSmartPlaylistDialog {
|
||||||
|
val dialog = ClearSmartPlaylistDialog()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putParcelable("playlist", playlist)
|
||||||
|
dialog.arguments = args
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,123 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
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.appthemehelper.util.MaterialUtil;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
|
||||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
|
|
||||||
*/
|
|
||||||
public class CreatePlaylistDialog extends RoundedBottomSheetDialogFragment {
|
|
||||||
|
|
||||||
@BindView(R.id.option_1)
|
|
||||||
TextInputEditText playlistName;
|
|
||||||
|
|
||||||
@BindView(R.id.action_new_playlist)
|
|
||||||
TextInputLayout textInputLayout;
|
|
||||||
|
|
||||||
@BindView(R.id.action_cancel)
|
|
||||||
MaterialButton actionCancel;
|
|
||||||
|
|
||||||
@BindView(R.id.action_create)
|
|
||||||
MaterialButton actionCreate;
|
|
||||||
|
|
||||||
@BindView(R.id.title)
|
|
||||||
TextView title;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static CreatePlaylistDialog create() {
|
|
||||||
return create((Song) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static CreatePlaylistDialog create(@Nullable Song song) {
|
|
||||||
ArrayList<Song> list = new ArrayList<>();
|
|
||||||
if (song != null) {
|
|
||||||
list.add(song);
|
|
||||||
}
|
|
||||||
return create(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static CreatePlaylistDialog create(ArrayList<Song> songs) {
|
|
||||||
CreatePlaylistDialog dialog = new CreatePlaylistDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putParcelableArrayList("songs", songs);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
||||||
View layout = inflater.inflate(R.layout.dialog_create_playlist, container, false);
|
|
||||||
ButterKnife.bind(this, layout);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
int accentColor = ThemeStore.accentColor(Objects.requireNonNull(getContext()));
|
|
||||||
|
|
||||||
MaterialUtil.setTint(actionCreate, true);
|
|
||||||
|
|
||||||
MaterialUtil.setTint(actionCancel, false);
|
|
||||||
|
|
||||||
MaterialUtil.setTint(textInputLayout, true);
|
|
||||||
|
|
||||||
|
|
||||||
playlistName.setHintTextColor(ColorStateList.valueOf(accentColor));
|
|
||||||
playlistName.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
|
|
||||||
title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick({R.id.action_cancel, R.id.action_create})
|
|
||||||
void actions(View view) {
|
|
||||||
switch (view.getId()) {
|
|
||||||
case R.id.action_cancel:
|
|
||||||
dismiss();
|
|
||||||
break;
|
|
||||||
case R.id.action_create:
|
|
||||||
if (getActivity() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!playlistName.getText().toString().trim().isEmpty()) {
|
|
||||||
final int playlistId = PlaylistsUtil
|
|
||||||
.createPlaylist(getActivity(), playlistName.getText().toString());
|
|
||||||
if (playlistId != -1 && getActivity() != null) {
|
|
||||||
//noinspection unchecked
|
|
||||||
ArrayList<Song> songs = getArguments().getParcelableArrayList("songs");
|
|
||||||
if (songs != null) {
|
|
||||||
PlaylistsUtil.addToPlaylist(getActivity(), songs, playlistId, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import butterknife.ButterKnife
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialUtil
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||||
|
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment
|
||||||
|
import kotlinx.android.synthetic.main.dialog_playlist.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
class CreatePlaylistDialog : RoundedBottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val layout = inflater.inflate(R.layout.dialog_playlist, container, false)
|
||||||
|
ButterKnife.bind(this, layout)
|
||||||
|
return layout
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val accentColor = ThemeStore.accentColor(Objects.requireNonNull<Context>(context))
|
||||||
|
|
||||||
|
MaterialUtil.setTint(actionCreate, true)
|
||||||
|
MaterialUtil.setTint(actionCancel, false)
|
||||||
|
MaterialUtil.setTint(actionNewPlaylistContainer, true)
|
||||||
|
|
||||||
|
actionNewPlaylist.setHintTextColor(ColorStateList.valueOf(accentColor))
|
||||||
|
actionNewPlaylist.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
|
||||||
|
|
||||||
|
actionCancel.setOnClickListener { dismiss() }
|
||||||
|
actionCreate.setOnClickListener {
|
||||||
|
if (activity == null) {
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
if (!actionNewPlaylist!!.text!!.toString().trim { it <= ' ' }.isEmpty()) {
|
||||||
|
val playlistId = PlaylistsUtil
|
||||||
|
.createPlaylist(activity!!, actionNewPlaylist!!.text!!.toString())
|
||||||
|
if (playlistId != -1 && activity != null) {
|
||||||
|
|
||||||
|
val songs = arguments!!.getParcelableArrayList<Song>("songs")
|
||||||
|
if (songs != null) {
|
||||||
|
PlaylistsUtil.addToPlaylist(activity!!, songs, playlistId, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
fun create(song: Song? = null): CreatePlaylistDialog {
|
||||||
|
val list = ArrayList<Song>()
|
||||||
|
if (song != null) {
|
||||||
|
list.add(song)
|
||||||
|
}
|
||||||
|
return create(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(songs: ArrayList<Song>): CreatePlaylistDialog {
|
||||||
|
val dialog = CreatePlaylistDialog()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putParcelableArrayList("songs", songs)
|
||||||
|
dialog.arguments = args
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,102 +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 com.google.android.material.button.MaterialButton;
|
|
||||||
|
|
||||||
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.appthemehelper.util.MaterialUtil;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
|
||||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
|
||||||
|
|
||||||
|
|
||||||
public class DeletePlaylistDialog extends RoundedBottomSheetDialogFragment {
|
|
||||||
|
|
||||||
@BindView(R.id.action_delete)
|
|
||||||
MaterialButton actionDelete;
|
|
||||||
|
|
||||||
@BindView(R.id.title)
|
|
||||||
TextView title;
|
|
||||||
|
|
||||||
@BindView(R.id.action_cancel)
|
|
||||||
MaterialButton actionCancel;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static DeletePlaylistDialog create(Playlist playlist) {
|
|
||||||
ArrayList<Playlist> list = new ArrayList<>();
|
|
||||||
list.add(playlist);
|
|
||||||
return create(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static DeletePlaylistDialog create(ArrayList<Playlist> playlists) {
|
|
||||||
DeletePlaylistDialog dialog = new DeletePlaylistDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putParcelableArrayList("playlists", playlists);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
View layout = inflater.inflate(R.layout.dialog_delete, container, false);
|
|
||||||
ButterKnife.bind(this, layout);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
//noinspection unchecked
|
|
||||||
final ArrayList<Playlist> playlists = getArguments().getParcelableArrayList("playlists");
|
|
||||||
int title;
|
|
||||||
CharSequence content;
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
if (playlists.size() > 1) {
|
|
||||||
content = Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size()));
|
|
||||||
} else {
|
|
||||||
content = Html.fromHtml(getString(R.string.delete_playlist_x, playlists.get(0).name));
|
|
||||||
}
|
|
||||||
this.title.setText(content);
|
|
||||||
this.title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
|
|
||||||
actionDelete.setText(R.string.action_delete);
|
|
||||||
|
|
||||||
MaterialUtil.setTint(actionDelete, true);
|
|
||||||
MaterialUtil.setTint(actionCancel, false);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick({R.id.action_cancel, R.id.action_delete})
|
|
||||||
void actions(View view) {
|
|
||||||
final ArrayList<Playlist> playlists = getArguments().getParcelableArrayList("playlists");
|
|
||||||
switch (view.getId()) {
|
|
||||||
case R.id.action_delete:
|
|
||||||
if (getActivity() == null)
|
|
||||||
return;
|
|
||||||
PlaylistsUtil.deletePlaylists(getActivity(), playlists);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
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 butterknife.ButterKnife
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
|
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||||
|
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment
|
||||||
|
import kotlinx.android.synthetic.main.dialog_remove_from_playlist.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class DeletePlaylistDialog : RoundedBottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
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 playlists = arguments!!.getParcelableArrayList<Playlist>("playlists")
|
||||||
|
val content: CharSequence
|
||||||
|
|
||||||
|
content = if (playlists!!.size > 1) {
|
||||||
|
Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size))
|
||||||
|
} else {
|
||||||
|
Html.fromHtml(getString(R.string.delete_playlist_x, playlists[0].name))
|
||||||
|
}
|
||||||
|
bannerTitle.text = content
|
||||||
|
bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
|
||||||
|
actionRemove.setText(R.string.action_delete)
|
||||||
|
actionRemove.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||||
|
actionCancel.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||||
|
|
||||||
|
actionCancel.setOnClickListener { dismiss() }
|
||||||
|
actionRemove.setOnClickListener {
|
||||||
|
PlaylistsUtil.deletePlaylists(activity!!, playlists)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun create(playlist: Playlist): DeletePlaylistDialog {
|
||||||
|
val list = ArrayList<Playlist>()
|
||||||
|
list.add(playlist)
|
||||||
|
return create(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(playlist: ArrayList<Playlist>): DeletePlaylistDialog {
|
||||||
|
val dialog = DeletePlaylistDialog()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putParcelableArrayList("playlist", playlist)
|
||||||
|
dialog.arguments = args
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -82,7 +82,7 @@ public class DeleteSongsDialog extends RoundedBottomSheetDialogFragment {
|
||||||
if (songs.size() > 1) {
|
if (songs.size() > 1) {
|
||||||
content = Html.fromHtml(getString(R.string.delete_x_songs, songs.size()));
|
content = Html.fromHtml(getString(R.string.delete_x_songs, songs.size()));
|
||||||
} else {
|
} 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);
|
this.title.setText(content);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,167 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.BindViews;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.RetroApplication;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
|
||||||
import code.name.monkey.retromusic.ui.fragments.mainactivity.folders.FoldersFragment;
|
|
||||||
import code.name.monkey.retromusic.util.Compressor;
|
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import code.name.monkey.retromusic.views.CircularImageView;
|
|
||||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
|
|
||||||
import static code.name.monkey.retromusic.Constants.USER_PROFILE;
|
|
||||||
|
|
||||||
public class MainOptionsBottomSheetDialogFragment extends RoundedBottomSheetDialogFragment {
|
|
||||||
|
|
||||||
private static final String TAG = "MainOptionsBottomSheetD";
|
|
||||||
private static ButterKnife.Setter<MaterialButton, Integer> textColor = (view, value, index) -> view.setTextColor(ColorStateList.valueOf(value));
|
|
||||||
|
|
||||||
|
|
||||||
@BindViews({R.id.action_folders, R.id.action_about, R.id.action_buy_pro, R.id.action_rate,
|
|
||||||
R.id.action_sleep_timer})
|
|
||||||
List<MaterialButton> materialButtons;
|
|
||||||
|
|
||||||
@BindView(R.id.user_image_bottom)
|
|
||||||
CircularImageView userImageBottom;
|
|
||||||
|
|
||||||
@BindView(R.id.title_welcome)
|
|
||||||
AppCompatTextView titleWelcome;
|
|
||||||
|
|
||||||
@BindView(R.id.text)
|
|
||||||
AppCompatTextView text;
|
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
|
|
||||||
public static MainOptionsBottomSheetDialogFragment newInstance(int selected_id) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putInt("selected_id", selected_id);
|
|
||||||
MainOptionsBottomSheetDialogFragment fragment = new MainOptionsBottomSheetDialogFragment();
|
|
||||||
fragment.setArguments(bundle);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MainOptionsBottomSheetDialogFragment newInstance() {
|
|
||||||
return new MainOptionsBottomSheetDialogFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
super.onDestroyView();
|
|
||||||
disposable.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
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()));
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
text.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
|
||||||
titleWelcome.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
titleWelcome.setText(String.format("%s %s!", getTimeOfTheDay(), PreferenceUtil.getInstance().getUserName()));
|
|
||||||
loadImageFromStorage();
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick({R.id.action_folders, R.id.user_info_container, R.id.action_settings, R.id.action_sleep_timer, R.id.action_rate,
|
|
||||||
R.id.action_buy_pro, R.id.action_about})
|
|
||||||
void onClick(View view) {
|
|
||||||
MainActivity mainActivity = (MainActivity) getActivity();
|
|
||||||
if (mainActivity == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (view.getId()) {
|
|
||||||
case R.id.action_folders:
|
|
||||||
mainActivity.setCurrentFragment(FoldersFragment.newInstance(getContext()), true, FoldersFragment.TAG);
|
|
||||||
break;
|
|
||||||
case R.id.action_settings:
|
|
||||||
NavigationUtil.goToSettings(mainActivity);
|
|
||||||
break;
|
|
||||||
case R.id.action_about:
|
|
||||||
NavigationUtil.goToAbout(mainActivity);
|
|
||||||
break;
|
|
||||||
case R.id.action_buy_pro:
|
|
||||||
NavigationUtil.goToProVersion(mainActivity);
|
|
||||||
break;
|
|
||||||
case R.id.action_sleep_timer:
|
|
||||||
if (getFragmentManager() != null) {
|
|
||||||
new SleepTimerDialog().show(getFragmentManager(), TAG);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case R.id.user_info_container:
|
|
||||||
NavigationUtil.goToUserInfo(getActivity());
|
|
||||||
break;
|
|
||||||
case R.id.action_rate:
|
|
||||||
NavigationUtil.goToPlayStore(mainActivity);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTimeOfTheDay() {
|
|
||||||
String message = getString(R.string.title_good_day);
|
|
||||||
Calendar c = Calendar.getInstance();
|
|
||||||
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
|
|
||||||
|
|
||||||
if (timeOfDay >= 0 && timeOfDay < 6) {
|
|
||||||
message = getString(R.string.title_good_night);
|
|
||||||
} else if (timeOfDay >= 6 && timeOfDay < 12) {
|
|
||||||
message = getString(R.string.title_good_morning);
|
|
||||||
} else if (timeOfDay >= 12 && timeOfDay < 16) {
|
|
||||||
message = getString(R.string.title_good_afternoon);
|
|
||||||
} else if (timeOfDay >= 16 && timeOfDay < 20) {
|
|
||||||
message = getString(R.string.title_good_evening);
|
|
||||||
} else if (timeOfDay >= 20 && timeOfDay < 24) {
|
|
||||||
message = getString(R.string.title_good_night);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadImageFromStorage() {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
disposable.add(new Compressor(getContext())
|
|
||||||
.setMaxHeight(300)
|
|
||||||
.setMaxWidth(300)
|
|
||||||
.setQuality(75)
|
|
||||||
.setCompressFormat(Bitmap.CompressFormat.WEBP)
|
|
||||||
.compressToBitmapAsFlowable(
|
|
||||||
new File(PreferenceUtil.getInstance().getProfileImage(), USER_PROFILE))
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(userImageBottom::setImageBitmap,
|
|
||||||
throwable -> userImageBottom.setImageDrawable(ContextCompat
|
|
||||||
.getDrawable(getContext(), R.drawable.ic_person_flat))));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.retromusic.Constants.USER_PROFILE
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.ui.activities.MainActivity
|
||||||
|
import code.name.monkey.retromusic.util.Compressor
|
||||||
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import kotlinx.android.synthetic.main.fragment_main_options.*
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MainOptionsBottomSheetDialogFragment : RoundedBottomSheetDialogFragment(), View.OnClickListener {
|
||||||
|
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
private val timeOfTheDay: String
|
||||||
|
get() {
|
||||||
|
var message = getString(R.string.title_good_day)
|
||||||
|
val c = Calendar.getInstance()
|
||||||
|
val timeOfDay = c.get(Calendar.HOUR_OF_DAY)
|
||||||
|
|
||||||
|
when (timeOfDay) {
|
||||||
|
in 0..5 -> message = getString(R.string.title_good_night)
|
||||||
|
in 6..11 -> message = getString(R.string.title_good_morning)
|
||||||
|
in 12..15 -> message = getString(R.string.title_good_afternoon)
|
||||||
|
in 16..19 -> message = getString(R.string.title_good_evening)
|
||||||
|
in 20..23 -> message = getString(R.string.title_good_night)
|
||||||
|
}
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
disposable.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_main_options, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
text!!.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||||
|
titleWelcome!!.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
titleWelcome!!.text = String.format("%s %s!", timeOfTheDay, PreferenceUtil.getInstance().userName)
|
||||||
|
loadImageFromStorage()
|
||||||
|
|
||||||
|
actionSettings.setOnClickListener(this)
|
||||||
|
actionAbout.setOnClickListener(this)
|
||||||
|
actionSleepTimer.setOnClickListener(this)
|
||||||
|
userInfoContainer.setOnClickListener(this)
|
||||||
|
actionRate.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onClick(view: View) {
|
||||||
|
val mainActivity = activity as MainActivity? ?: return
|
||||||
|
when (view.id) {
|
||||||
|
R.id.actionSettings -> NavigationUtil.goToSettings(mainActivity)
|
||||||
|
R.id.actionAbout -> NavigationUtil.goToAbout(mainActivity)
|
||||||
|
R.id.actionSleepTimer -> if (fragmentManager != null) {
|
||||||
|
SleepTimerDialog().show(fragmentManager!!, TAG)
|
||||||
|
}
|
||||||
|
R.id.userInfoContainer -> NavigationUtil.goToUserInfo(activity!!)
|
||||||
|
R.id.actionRate -> NavigationUtil.goToPlayStore(mainActivity)
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadImageFromStorage() {
|
||||||
|
|
||||||
|
disposable.add(Compressor(context!!)
|
||||||
|
.setMaxHeight(300)
|
||||||
|
.setMaxWidth(300)
|
||||||
|
.setQuality(75)
|
||||||
|
.setCompressFormat(Bitmap.CompressFormat.WEBP)
|
||||||
|
.compressToBitmapAsFlowable(
|
||||||
|
File(PreferenceUtil.getInstance().profileImage, USER_PROFILE))
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ userImage!!.setImageBitmap(it) }, {
|
||||||
|
userImage!!.setImageDrawable(ContextCompat
|
||||||
|
.getDrawable(context!!, R.drawable.ic_person_flat))
|
||||||
|
}, {
|
||||||
|
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG: String = "MainOptionsBottomSheetD"
|
||||||
|
|
||||||
|
fun newInstance(selected_id: Int): MainOptionsBottomSheetDialogFragment {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putInt("selected_id", selected_id)
|
||||||
|
val fragment = MainOptionsBottomSheetDialogFragment()
|
||||||
|
fragment.arguments = bundle
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newInstance(): MainOptionsBottomSheetDialogFragment {
|
||||||
|
return MainOptionsBottomSheetDialogFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,93 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong;
|
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
|
||||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
|
||||||
|
|
||||||
|
|
||||||
public class RemoveFromPlaylistDialog extends RoundedBottomSheetDialogFragment {
|
|
||||||
@BindView(R.id.action_remove)
|
|
||||||
TextView remove;
|
|
||||||
|
|
||||||
@BindView(R.id.title)
|
|
||||||
TextView title;
|
|
||||||
|
|
||||||
@BindView(R.id.action_cancel)
|
|
||||||
TextView cancel;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static RemoveFromPlaylistDialog create(PlaylistSong song) {
|
|
||||||
ArrayList<PlaylistSong> list = new ArrayList<>();
|
|
||||||
list.add(song);
|
|
||||||
return create(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static RemoveFromPlaylistDialog create(ArrayList<PlaylistSong> songs) {
|
|
||||||
RemoveFromPlaylistDialog dialog = new RemoveFromPlaylistDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putParcelableArrayList("songs", songs);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick({R.id.action_cancel, R.id.action_remove})
|
|
||||||
void actions(View view) {
|
|
||||||
final ArrayList<PlaylistSong> songs = getArguments().getParcelableArrayList("songs");
|
|
||||||
switch (view.getId()) {
|
|
||||||
case R.id.action_remove:
|
|
||||||
if (getActivity() == null)
|
|
||||||
return;
|
|
||||||
PlaylistsUtil.removeFromPlaylist(getActivity(), songs);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
||||||
View layout = inflater.inflate(R.layout.dialog_remove_from_playlist, container, false);
|
|
||||||
ButterKnife.bind(this, layout);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
//noinspection unchecked
|
|
||||||
final ArrayList<PlaylistSong> songs = getArguments().getParcelableArrayList("songs");
|
|
||||||
int title;
|
|
||||||
CharSequence content;
|
|
||||||
if (songs != null && songs.size() > 1) {
|
|
||||||
title = R.string.remove_songs_from_playlist_title;
|
|
||||||
content = Html.fromHtml(getString(R.string.remove_x_songs_from_playlist, songs.size()));
|
|
||||||
} else {
|
|
||||||
title = R.string.remove_song_from_playlist_title;
|
|
||||||
content = Html.fromHtml(getString(R.string.remove_song_x_from_playlist, songs.get(0).title));
|
|
||||||
}
|
|
||||||
this.remove.setText(content);
|
|
||||||
this.title.setText(title);
|
|
||||||
|
|
||||||
this.title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
this.remove.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
|
||||||
this.cancel.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
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 butterknife.ButterKnife
|
||||||
|
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 kotlinx.android.synthetic.main.dialog_remove_from_playlist.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveFromPlaylistDialog : RoundedBottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
actionRemove.text = content
|
||||||
|
bannerTitle.setText(title)
|
||||||
|
|
||||||
|
bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
actionRemove.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||||
|
actionCancel.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||||
|
|
||||||
|
actionRemove.setOnClickListener {
|
||||||
|
PlaylistsUtil.removeFromPlaylist(activity!!, songs)
|
||||||
|
}
|
||||||
|
actionCancel.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,98 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
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.appthemehelper.util.MaterialUtil;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
|
||||||
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment;
|
|
||||||
|
|
||||||
public class RenamePlaylistDialog extends RoundedBottomSheetDialogFragment {
|
|
||||||
|
|
||||||
@BindView(R.id.title)
|
|
||||||
TextView title;
|
|
||||||
|
|
||||||
@BindView(R.id.option_1)
|
|
||||||
TextInputEditText playlistName;
|
|
||||||
|
|
||||||
@BindView(R.id.action_new_playlist)
|
|
||||||
TextInputLayout textInputLayout;
|
|
||||||
|
|
||||||
@BindView(R.id.action_cancel)
|
|
||||||
MaterialButton actionCancel;
|
|
||||||
|
|
||||||
@BindView(R.id.action_rename)
|
|
||||||
MaterialButton rename;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static RenamePlaylistDialog create(long playlistId) {
|
|
||||||
RenamePlaylistDialog dialog = new RenamePlaylistDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putLong("playlist_id", playlistId);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick({R.id.action_cancel, R.id.action_rename})
|
|
||||||
void actions(View view) {
|
|
||||||
switch (view.getId()) {
|
|
||||||
case R.id.action_cancel:
|
|
||||||
dismiss();
|
|
||||||
break;
|
|
||||||
case R.id.action_rename:
|
|
||||||
if (!playlistName.toString().trim().equals("")) {
|
|
||||||
long playlistId = getArguments().getLong("playlist_id");
|
|
||||||
PlaylistsUtil.renamePlaylist(getActivity(), playlistId,
|
|
||||||
playlistName.getText().toString());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
View layout = inflater.inflate(R.layout.dialog_playlist_rename, container, false);
|
|
||||||
ButterKnife.bind(this, layout);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
int accentColor = ThemeStore.accentColor(Objects.requireNonNull(getContext()));
|
|
||||||
MaterialUtil.setTint(rename,true);
|
|
||||||
MaterialUtil.setTint(actionCancel,false);
|
|
||||||
MaterialUtil.setTint(textInputLayout,false);
|
|
||||||
|
|
||||||
playlistName.setHintTextColor(ColorStateList.valueOf(accentColor));
|
|
||||||
playlistName.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
|
|
||||||
title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
|
||||||
|
|
||||||
long playlistId = 0;
|
|
||||||
if (getArguments() != null) {
|
|
||||||
playlistId = getArguments().getLong("playlist_id");
|
|
||||||
}
|
|
||||||
playlistName.setText(PlaylistsUtil.getNameForPlaylist(getActivity(), playlistId));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import butterknife.ButterKnife
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialUtil
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||||
|
import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment
|
||||||
|
import kotlinx.android.synthetic.main.dialog_playlist.*
|
||||||
|
|
||||||
|
class RenamePlaylistDialog : RoundedBottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
val layout = inflater.inflate(R.layout.dialog_playlist, container, false)
|
||||||
|
ButterKnife.bind(this, layout)
|
||||||
|
return layout
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val accentColor = ThemeStore.accentColor(context!!)
|
||||||
|
actionCreate.setText(R.string.action_rename)
|
||||||
|
|
||||||
|
MaterialUtil.setTint(actionCreate, true)
|
||||||
|
MaterialUtil.setTint(actionCancel, false)
|
||||||
|
MaterialUtil.setTint(actionNewPlaylistContainer, false)
|
||||||
|
|
||||||
|
actionNewPlaylist.apply {
|
||||||
|
var playlistId: Long = 0
|
||||||
|
if (arguments != null) {
|
||||||
|
playlistId = arguments!!.getLong("playlist_id")
|
||||||
|
}
|
||||||
|
setText(PlaylistsUtil.getNameForPlaylist(activity!!, playlistId))
|
||||||
|
setHintTextColor(ColorStateList.valueOf(accentColor))
|
||||||
|
setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||||
|
bannerTitle.setText(R.string.rename_playlist_title)
|
||||||
|
actionCancel.setOnClickListener { dismiss() }
|
||||||
|
actionCreate.setOnClickListener {
|
||||||
|
if (actionNewPlaylist.toString().trim { it <= ' ' } != "") {
|
||||||
|
val playlistId = arguments!!.getLong("playlist_id")
|
||||||
|
PlaylistsUtil.renamePlaylist(context!!, playlistId, actionNewPlaylist.text!!.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun create(playlistId: Long): RenamePlaylistDialog {
|
||||||
|
val dialog = RenamePlaylistDialog()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putLong("playlist_id", playlistId)
|
||||||
|
dialog.arguments = args
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,7 +94,7 @@ public class SongDetailDialog extends RoundedBottomSheetDialogFragment {
|
||||||
|
|
||||||
final Song song = getArguments().getParcelable("song");
|
final Song song = getArguments().getParcelable("song");
|
||||||
if (song != null) {
|
if (song != null) {
|
||||||
final File songFile = new File(song.data);
|
final File songFile = new File(song.getData());
|
||||||
if (songFile.exists()) {
|
if (songFile.exists()) {
|
||||||
textViews.get(1).setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName()));
|
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()));
|
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) {
|
} catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||||
Log.e(TAG, "error while reading the song file", e);
|
Log.e(TAG, "error while reading the song file", e);
|
||||||
// fallback
|
// 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 {
|
} else {
|
||||||
// fallback
|
// fallback
|
||||||
textViews.get(1).setText(makeTextWithTitle(context, R.string.label_file_name, song.title));
|
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.duration)));
|
textViews.get(5).setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.getDuration())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class SongShareDialog extends RoundedBottomSheetDialogFragment {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
final Song song = getArguments().getParcelable("song");
|
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()));
|
audioFile.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
||||||
audioText.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
audioText.setTextColor(ThemeStore.textColorSecondary(getContext()));
|
||||||
title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
title.setTextColor(ThemeStore.textColorPrimary(getContext()));
|
||||||
|
@ -60,7 +60,7 @@ public class SongShareDialog extends RoundedBottomSheetDialogFragment {
|
||||||
@OnClick({R.id.option_2, R.id.option_1})
|
@OnClick({R.id.option_2, R.id.option_1})
|
||||||
void onClick(View view) {
|
void onClick(View view) {
|
||||||
final Song song = getArguments().getParcelable("song");
|
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()) {
|
switch (view.getId()) {
|
||||||
case R.id.option_1:
|
case R.id.option_1:
|
||||||
startActivity(Intent.createChooser(
|
startActivity(Intent.createChooser(
|
||||||
|
|
|
@ -15,7 +15,7 @@ import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||||
import com.bumptech.glide.request.target.Target;
|
import com.bumptech.glide.request.target.Target;
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
import code.name.monkey.retromusic.R;
|
||||||
import code.name.monkey.retromusic.RetroApplication;
|
import code.name.monkey.retromusic.App;
|
||||||
import code.name.monkey.retromusic.glide.artistimage.ArtistImage;
|
import code.name.monkey.retromusic.glide.artistimage.ArtistImage;
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder;
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder;
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
||||||
|
@ -31,7 +31,7 @@ public class ArtistGlideRequest {
|
||||||
|
|
||||||
private static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist,
|
private static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist,
|
||||||
boolean noCustomImage, boolean forceDownload) {
|
boolean noCustomImage, boolean forceDownload) {
|
||||||
boolean hasCustomImage = CustomArtistImageUtil.getInstance(RetroApplication.getInstance())
|
boolean hasCustomImage = CustomArtistImageUtil.getInstance(App.Companion.getInstance())
|
||||||
.hasCustomArtistImage(artist);
|
.hasCustomArtistImage(artist);
|
||||||
if (noCustomImage || !hasCustomImage) {
|
if (noCustomImage || !hasCustomImage) {
|
||||||
return requestManager.load(new ArtistImage(artist.getName(), forceDownload));
|
return requestManager.load(new ArtistImage(artist.getName(), forceDownload));
|
||||||
|
@ -41,7 +41,7 @@ public class ArtistGlideRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Key createSignature(Artist artist) {
|
private static Key createSignature(Artist artist) {
|
||||||
return ArtistSignatureUtil.getInstance(RetroApplication.getInstance())
|
return ArtistSignatureUtil.getInstance(App.Companion.getInstance())
|
||||||
.getArtistSignature(artist.getName());
|
.getArtistSignature(artist.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package code.name.monkey.retromusic.glide;
|
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
|
||||||
|
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.RetroApplication;
|
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget;
|
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
|
|
||||||
import static code.name.monkey.retromusic.util.RetroColorUtil.getColor;
|
|
||||||
import static code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class RetroMusicColoredTarget extends BitmapPaletteTarget {
|
|
||||||
|
|
||||||
public RetroMusicColoredTarget(ImageView view) {
|
|
||||||
super(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
|
||||||
super.onLoadFailed(e, errorDrawable);
|
|
||||||
onColorReady(getDefaultFooterColor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResourceReady(BitmapPaletteWrapper resource,
|
|
||||||
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
|
|
||||||
super.onResourceReady(resource, glideAnimation);
|
|
||||||
int defaultColor = getDefaultFooterColor();
|
|
||||||
|
|
||||||
int primaryColor = getColor(resource.getPalette(), defaultColor);
|
|
||||||
int dominantColor = getDominantColor(resource.getBitmap(), defaultColor);
|
|
||||||
|
|
||||||
onColorReady(PreferenceUtil.getInstance().isDominantColor() ?
|
|
||||||
dominantColor : primaryColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getDefaultFooterColor() {
|
|
||||||
return ATHUtil.resolveColor(getView().getContext(), R.attr.defaultFooterColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getAlbumArtistFooterColor() {
|
|
||||||
return ATHUtil.resolveColor(getView().getContext(), R.attr.cardBackgroundColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void onColorReady(int color);
|
|
||||||
}
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
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.glide.palette.BitmapPaletteTarget
|
||||||
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
|
||||||
|
import code.name.monkey.retromusic.util.RetroColorUtil.getDominantColor
|
||||||
|
|
||||||
|
|
||||||
|
abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) {
|
||||||
|
|
||||||
|
protected val defaultFooterColor: Int
|
||||||
|
get() = ATHUtil.resolveColor(getView().context, R.attr.defaultFooterColor)
|
||||||
|
|
||||||
|
protected val albumArtistFooterColor: Int
|
||||||
|
get() = ATHUtil.resolveColor(getView().context, R.attr.cardBackgroundColor)
|
||||||
|
|
||||||
|
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
|
||||||
|
super.onLoadFailed(e, errorDrawable)
|
||||||
|
onColorReady(defaultFooterColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(resource: BitmapPaletteWrapper,
|
||||||
|
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) {
|
||||||
|
super.onResourceReady(resource, glideAnimation)
|
||||||
|
val defaultColor = defaultFooterColor
|
||||||
|
|
||||||
|
val primaryColor = getColor(resource.palette, defaultColor)
|
||||||
|
val dominantColor = getDominantColor(resource.bitmap, defaultColor)
|
||||||
|
|
||||||
|
onColorReady(if (PreferenceUtil.getInstance().isDominantColor)
|
||||||
|
dominantColor
|
||||||
|
else
|
||||||
|
primaryColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun onColorReady(color: Int)
|
||||||
|
}
|
|
@ -29,14 +29,14 @@ public class SongGlideRequest {
|
||||||
static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Song song,
|
static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Song song,
|
||||||
boolean ignoreMediaStore) {
|
boolean ignoreMediaStore) {
|
||||||
if (ignoreMediaStore) {
|
if (ignoreMediaStore) {
|
||||||
return requestManager.load(new AudioFileCover(song.data));
|
return requestManager.load(new AudioFileCover(song.getData()));
|
||||||
} else {
|
} else {
|
||||||
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.albumId));
|
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Key createSignature(Song song) {
|
static Key createSignature(Song song) {
|
||||||
return new MediaStoreSignature("", song.dateModified, 0);
|
return new MediaStoreSignature("", song.getDateModified(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package code.name.monkey.retromusic.glide.palette;
|
|
||||||
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import com.bumptech.glide.request.target.ImageViewTarget;
|
|
||||||
|
|
||||||
public class BitmapPaletteTarget extends ImageViewTarget<BitmapPaletteWrapper> {
|
|
||||||
|
|
||||||
public BitmapPaletteTarget(ImageView view) {
|
|
||||||
super(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setResource(BitmapPaletteWrapper bitmapPaletteWrapper) {
|
|
||||||
view.setImageBitmap(bitmapPaletteWrapper.getBitmap());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package code.name.monkey.retromusic.glide.palette
|
||||||
|
|
||||||
|
import android.widget.ImageView
|
||||||
|
import com.bumptech.glide.request.target.ImageViewTarget
|
||||||
|
|
||||||
|
open class BitmapPaletteTarget(view: ImageView) : ImageViewTarget<BitmapPaletteWrapper>(view) {
|
||||||
|
|
||||||
|
override fun setResource(bitmapPaletteWrapper: BitmapPaletteWrapper) {
|
||||||
|
view.setImageBitmap(bitmapPaletteWrapper.bitmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,171 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.media.audiofx.BassBoost;
|
|
||||||
import android.media.audiofx.Equalizer;
|
|
||||||
import android.media.audiofx.Virtualizer;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.interfaces.EqualizerInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Hemanth S (h4h13).
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class EqualizerHelper implements EqualizerInterface {
|
|
||||||
private static final String TAG = "EqualizerHelper";
|
|
||||||
private static volatile EqualizerHelper ourInstance;
|
|
||||||
private Equalizer mEqualizer;
|
|
||||||
private BassBoost mBassBoost;
|
|
||||||
private Virtualizer mVirtualizer;
|
|
||||||
|
|
||||||
private int mMaxLevel, mMinLevel;
|
|
||||||
private boolean isRunning = false;
|
|
||||||
|
|
||||||
private EqualizerHelper() {
|
|
||||||
|
|
||||||
//Prevent form the reflection api.
|
|
||||||
if (ourInstance != null) {
|
|
||||||
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = MusicPlayerRemote.getAudioSessionId();
|
|
||||||
|
|
||||||
mEqualizer = new Equalizer(100, i);
|
|
||||||
if (mEqualizer == null) {
|
|
||||||
Log.i(TAG, "onCreate: Equalizer is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mEqualizer.setEnabled(true);
|
|
||||||
|
|
||||||
|
|
||||||
mBassBoost = new BassBoost(100, i);
|
|
||||||
if (mBassBoost == null) {
|
|
||||||
Log.i(TAG, "onCreate: BassBoost is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mVirtualizer = new Virtualizer(100, i);
|
|
||||||
if (mVirtualizer == null) {
|
|
||||||
Log.i(TAG, "onCreate: Virtualizer is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mMaxLevel = (int) mEqualizer.getBandLevelRange()[1];
|
|
||||||
mMinLevel = (int) mEqualizer.getBandLevelRange()[0];
|
|
||||||
|
|
||||||
Log.i(TAG, "onCreate: " + mMaxLevel + " " + mMinLevel);
|
|
||||||
isRunning = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EqualizerHelper getInstance() {
|
|
||||||
//Double check locking pattern
|
|
||||||
if (ourInstance == null) {//Check for the first time
|
|
||||||
|
|
||||||
synchronized (EqualizerHelper.class) {//Check for the second time.
|
|
||||||
|
|
||||||
//if there is no instance available... create new one
|
|
||||||
if (ourInstance == null) {
|
|
||||||
ourInstance = new EqualizerHelper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ourInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Make singleton from serialize and deserialize operation.
|
|
||||||
protected EqualizerHelper readResolve() {
|
|
||||||
return getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Equalizer getEqualizer() {
|
|
||||||
return mEqualizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BassBoost getBassBoost() {
|
|
||||||
return mBassBoost;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Virtualizer getVirtualizer() {
|
|
||||||
return mVirtualizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBandLevelLow() {
|
|
||||||
return mMinLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBandLevelHigh() {
|
|
||||||
return mMaxLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getNumberOfBands() {
|
|
||||||
return (int) mEqualizer.getNumberOfBands();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCenterFreq(int band) {
|
|
||||||
return (int) mEqualizer.getCenterFreq((short) band);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBandLevel(int band) {
|
|
||||||
return (int) mEqualizer.getBandLevel((short) band);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBandLevel(int band, int level) {
|
|
||||||
mEqualizer.setBandLevel((short) band, (short) level);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isBassBoostEnabled() {
|
|
||||||
return mBassBoost.getEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBassBoostEnabled(boolean isEnabled) {
|
|
||||||
mBassBoost.setEnabled(isEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBassBoostStrength() {
|
|
||||||
return (int) mBassBoost.getRoundedStrength();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBassBoostStrength(int strength) {
|
|
||||||
mBassBoost.setStrength((short) strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isVirtualizerEnabled() {
|
|
||||||
return mVirtualizer.getEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVirtualizerEnabled(boolean isEnabled) {
|
|
||||||
mVirtualizer.setEnabled(isEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getVirtualizerStrength() {
|
|
||||||
return mVirtualizer.getRoundedStrength();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVirtualizerStrength(int strength) {
|
|
||||||
mVirtualizer.setStrength((short) strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRunning() {
|
|
||||||
return isRunning;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.media.audiofx.BassBoost
|
||||||
|
import android.media.audiofx.Equalizer
|
||||||
|
import android.media.audiofx.Virtualizer
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.interfaces.EqualizerInterface
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hemanth S (h4h13).
|
||||||
|
*/
|
||||||
|
|
||||||
|
class EqualizerHelper private constructor() : EqualizerInterface {
|
||||||
|
override val equalizer: Equalizer
|
||||||
|
override val bassBoost: BassBoost
|
||||||
|
override val virtualizer: Virtualizer
|
||||||
|
|
||||||
|
override val bandLevelHigh: Int
|
||||||
|
override val bandLevelLow: Int
|
||||||
|
override var isRunning = false
|
||||||
|
|
||||||
|
override val numberOfBands: Int
|
||||||
|
get() = equalizer.numberOfBands.toInt()
|
||||||
|
|
||||||
|
override var isBassBoostEnabled: Boolean
|
||||||
|
get() = bassBoost.enabled
|
||||||
|
set(isEnabled) {
|
||||||
|
bassBoost.enabled = isEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override var bassBoostStrength: Int
|
||||||
|
get() = bassBoost.roundedStrength.toInt()
|
||||||
|
set(strength) = bassBoost.setStrength(strength.toShort())
|
||||||
|
|
||||||
|
override var isVirtualizerEnabled: Boolean
|
||||||
|
get() = virtualizer.enabled
|
||||||
|
set(isEnabled) {
|
||||||
|
virtualizer.enabled = isEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override var virtualizerStrength: Int
|
||||||
|
get() = virtualizer.roundedStrength.toInt()
|
||||||
|
set(strength) = virtualizer.setStrength(strength.toShort())
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
//Prevent form the reflection api.
|
||||||
|
if (ourInstance != null) {
|
||||||
|
throw RuntimeException("Use getInstance() method to get the single instance of this class.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val i = MusicPlayerRemote.audioSessionId
|
||||||
|
|
||||||
|
equalizer = Equalizer(100, i)
|
||||||
|
|
||||||
|
equalizer.enabled = true
|
||||||
|
bassBoost = BassBoost(100, i)
|
||||||
|
virtualizer = Virtualizer(100, i)
|
||||||
|
|
||||||
|
bandLevelHigh = equalizer.bandLevelRange[1].toInt()
|
||||||
|
bandLevelLow = equalizer.bandLevelRange[0].toInt()
|
||||||
|
|
||||||
|
Log.i(TAG, "onCreate: $bandLevelHigh $bandLevelLow")
|
||||||
|
isRunning = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//Make singleton from serialize and deserialize operation.
|
||||||
|
protected fun readResolve(): EqualizerHelper? {
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCenterFreq(band: Int): Int {
|
||||||
|
return equalizer.getCenterFreq(band.toShort())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getBandLevel(band: Int): Int {
|
||||||
|
return equalizer.getBandLevel(band.toShort()).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBandLevel(band: Int, level: Int) {
|
||||||
|
equalizer.setBandLevel(band.toShort(), level.toShort())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = "EqualizerHelper"
|
||||||
|
@Volatile
|
||||||
|
private var ourInstance: EqualizerHelper? = null
|
||||||
|
|
||||||
|
//Double check locking pattern
|
||||||
|
//Check for the first time
|
||||||
|
//Check for the second time.
|
||||||
|
//if there is no instance available... create new one
|
||||||
|
val instance: EqualizerHelper?
|
||||||
|
get() {
|
||||||
|
if (ourInstance == null) {
|
||||||
|
|
||||||
|
synchronized(EqualizerHelper::class.java) {
|
||||||
|
if (ourInstance == null) {
|
||||||
|
ourInstance = EqualizerHelper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ourInstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
|
|
||||||
|
|
||||||
public class HorizontalAdapterHelper {
|
|
||||||
|
|
||||||
public static final int LAYOUT_RES = R.layout.item_image;
|
|
||||||
|
|
||||||
public static final int TYPE_FIRST = 1;
|
|
||||||
public static final int TYPE_MIDDLE = 2;
|
|
||||||
public static final int TYPE_LAST = 3;
|
|
||||||
|
|
||||||
public static void applyMarginToLayoutParams(Context context,
|
|
||||||
ViewGroup.MarginLayoutParams layoutParams, int viewType) {
|
|
||||||
int listMargin = context.getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.now_playing_top_margin);
|
|
||||||
if (viewType == TYPE_FIRST) {
|
|
||||||
layoutParams.leftMargin = listMargin;
|
|
||||||
} else if (viewType == TYPE_LAST) {
|
|
||||||
layoutParams.rightMargin = listMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getItemViewtype(int position, int itemCount) {
|
|
||||||
if (position == 0) {
|
|
||||||
return TYPE_FIRST;
|
|
||||||
} else if (position == itemCount - 1) {
|
|
||||||
return TYPE_LAST;
|
|
||||||
} else {
|
|
||||||
return TYPE_MIDDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
|
||||||
|
|
||||||
|
object HorizontalAdapterHelper {
|
||||||
|
|
||||||
|
val LAYOUT_RES = R.layout.item_image
|
||||||
|
|
||||||
|
val TYPE_FIRST = 1
|
||||||
|
val TYPE_MIDDLE = 2
|
||||||
|
val TYPE_LAST = 3
|
||||||
|
|
||||||
|
fun applyMarginToLayoutParams(context: Context,
|
||||||
|
layoutParams: ViewGroup.MarginLayoutParams, viewType: Int) {
|
||||||
|
val listMargin = context.resources
|
||||||
|
.getDimensionPixelSize(R.dimen.now_playing_top_margin)
|
||||||
|
if (viewType == TYPE_FIRST) {
|
||||||
|
layoutParams.leftMargin = listMargin
|
||||||
|
} else if (viewType == TYPE_LAST) {
|
||||||
|
layoutParams.rightMargin = listMargin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getItemViewtype(position: Int, itemCount: Int): Int {
|
||||||
|
return if (position == 0) {
|
||||||
|
TYPE_FIRST
|
||||||
|
} else if (position == itemCount - 1) {
|
||||||
|
TYPE_LAST
|
||||||
|
} else {
|
||||||
|
TYPE_MIDDLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
public interface M3UConstants {
|
|
||||||
String EXTENSION = "m3u";
|
|
||||||
String HEADER = "#EXTM3U";
|
|
||||||
String ENTRY = "#EXTINF:";
|
|
||||||
String DURATION_SEPARATOR = ",";
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
interface M3UConstants {
|
||||||
|
companion object {
|
||||||
|
val EXTENSION = "m3u"
|
||||||
|
val HEADER = "#EXTM3U"
|
||||||
|
val ENTRY = "#EXTINF:"
|
||||||
|
val DURATION_SEPARATOR = ","
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,58 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
|
|
||||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.ObservableEmitter;
|
|
||||||
|
|
||||||
public class M3UWriter implements M3UConstants {
|
|
||||||
public static final String TAG = M3UWriter.class.getSimpleName();
|
|
||||||
|
|
||||||
public static Observable<File> write(@NonNull Context context,
|
|
||||||
@NonNull File dir, @NonNull Playlist playlist) {
|
|
||||||
if (!dir.exists()) //noinspection ResultOfMethodCallIgnored
|
|
||||||
dir.mkdirs();
|
|
||||||
File file = new File(dir, playlist.name.concat("." + EXTENSION));
|
|
||||||
|
|
||||||
if (playlist instanceof AbsCustomPlaylist) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
((AbsCustomPlaylist) playlist).getSongs(context).subscribe(songs -> {
|
|
||||||
saveSongsToFile(file, e, songs);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
return Observable.create(e ->
|
|
||||||
PlaylistSongsLoader.getPlaylistSongList(context, playlist.id)
|
|
||||||
.subscribe(songs -> {
|
|
||||||
saveSongsToFile(file, e, songs);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void saveSongsToFile(File file, ObservableEmitter<File> e, ArrayList<Song> songs) throws IOException {
|
|
||||||
if (songs.size() > 0) {
|
|
||||||
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
|
|
||||||
bw.write(HEADER);
|
|
||||||
for (Song song : songs) {
|
|
||||||
bw.newLine();
|
|
||||||
bw.write(ENTRY + song.duration + DURATION_SEPARATOR + song.artistName + " - " + song.title);
|
|
||||||
bw.newLine();
|
|
||||||
bw.write(song.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bw.close();
|
|
||||||
}
|
|
||||||
e.onNext(file);
|
|
||||||
e.onComplete();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
import java.io.BufferedWriter
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
|
||||||
|
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||||
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.ObservableEmitter
|
||||||
|
|
||||||
|
class M3UWriter : M3UConstants {
|
||||||
|
companion object {
|
||||||
|
val TAG: String = M3UWriter::class.java.simpleName
|
||||||
|
|
||||||
|
fun write(context: Context,
|
||||||
|
dir: File, playlist: Playlist): Observable<File> {
|
||||||
|
if (!dir.exists())
|
||||||
|
|
||||||
|
dir.mkdirs()
|
||||||
|
val file = File(dir, playlist.name + ("." + M3UConstants.EXTENSION))
|
||||||
|
|
||||||
|
return if (playlist is AbsCustomPlaylist) {
|
||||||
|
Observable.create { e -> playlist.getSongs(context).subscribe { songs -> saveSongsToFile(file, e, songs) } }
|
||||||
|
} else
|
||||||
|
Observable.create { e -> PlaylistSongsLoader.getPlaylistSongList(context, playlist.id).subscribe { songs -> saveSongsToFile(file, e, songs) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
private fun saveSongsToFile(file: File, e: ObservableEmitter<File>, songs: ArrayList<Song>) {
|
||||||
|
if (songs.size > 0) {
|
||||||
|
val bw = BufferedWriter(FileWriter(file))
|
||||||
|
bw.write(M3UConstants.HEADER)
|
||||||
|
for (song in songs) {
|
||||||
|
bw.newLine()
|
||||||
|
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
|
||||||
|
bw.newLine()
|
||||||
|
bw.write(song.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
bw.close()
|
||||||
|
}
|
||||||
|
e.onNext(file)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,496 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.ContextWrapper;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.provider.DocumentsContract;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.google.android.gms.cast.framework.CastContext;
|
|
||||||
import com.google.android.gms.cast.framework.CastSession;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.RetroApplication;
|
|
||||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
|
|
||||||
|
|
||||||
public class MusicPlayerRemote {
|
|
||||||
public static final String TAG = MusicPlayerRemote.class.getSimpleName();
|
|
||||||
private static final WeakHashMap<Context, ServiceBinder> mConnectionMap = new WeakHashMap<>();
|
|
||||||
@Nullable
|
|
||||||
public static MusicService musicService;
|
|
||||||
private static int playbackLocation = PlaybackLocation.LOCAL;
|
|
||||||
|
|
||||||
|
|
||||||
private static CastSession getCastSession() {
|
|
||||||
CastSession castSession = CastContext.getSharedInstance(RetroApplication.getInstance()).getSessionManager().getCurrentCastSession();
|
|
||||||
if (castSession != null) {
|
|
||||||
playbackLocation = PlaybackLocation.REMOTE;
|
|
||||||
} else {
|
|
||||||
playbackLocation = PlaybackLocation.LOCAL;
|
|
||||||
}
|
|
||||||
return castSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ServiceToken bindToService(@NonNull final Context context,
|
|
||||||
final ServiceConnection callback) {
|
|
||||||
|
|
||||||
Activity realActivity = ((Activity) context).getParent();
|
|
||||||
if (realActivity == null) {
|
|
||||||
realActivity = (Activity) context;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ContextWrapper contextWrapper = new ContextWrapper(realActivity);
|
|
||||||
contextWrapper.startService(new Intent(contextWrapper, MusicService.class));
|
|
||||||
|
|
||||||
final ServiceBinder binder = new ServiceBinder(callback);
|
|
||||||
|
|
||||||
if (contextWrapper.bindService(new Intent().setClass(contextWrapper, MusicService.class), binder, Context.BIND_AUTO_CREATE)) {
|
|
||||||
mConnectionMap.put(contextWrapper, binder);
|
|
||||||
return new ServiceToken(contextWrapper);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void unbindFromService(@Nullable final ServiceToken token) {
|
|
||||||
if (token == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ContextWrapper mContextWrapper = token.mWrappedContext;
|
|
||||||
final ServiceBinder mBinder = mConnectionMap.remove(mContextWrapper);
|
|
||||||
if (mBinder == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mContextWrapper.unbindService(mBinder);
|
|
||||||
if (mConnectionMap.isEmpty()) {
|
|
||||||
musicService = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String getFilePathFromUri(Context context, Uri uri) {
|
|
||||||
|
|
||||||
final String column = "_data";
|
|
||||||
final String[] projection = {
|
|
||||||
column
|
|
||||||
};
|
|
||||||
try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null,
|
|
||||||
null)) {
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
final int column_index = cursor.getColumnIndexOrThrow(column);
|
|
||||||
return cursor.getString(column_index);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, e.getMessage());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void playSongAt(final int position) {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.playSongAt(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void pauseSong() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void playNextSong() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.playNextSong(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void playPreviousSong() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.playPreviousSong(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void back() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.back(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPlaying() {
|
|
||||||
return musicService != null && musicService.isPlaying();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void resumePlaying() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void openQueue(final ArrayList<Song> queue, final int startPosition, final boolean startPlaying) {
|
|
||||||
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
|
||||||
musicService.openQueue(queue, startPosition, startPlaying);
|
|
||||||
if (PreferenceUtil.getInstance().isShuffleModeOn())
|
|
||||||
setShuffleMode(MusicService.SHUFFLE_MODE_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void openAndShuffleQueue(final ArrayList<Song> queue, boolean startPlaying) {
|
|
||||||
int startPosition = 0;
|
|
||||||
if (!queue.isEmpty()) {
|
|
||||||
startPosition = new Random().nextInt(queue.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
|
||||||
openQueue(queue, startPosition, startPlaying);
|
|
||||||
setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean tryToHandleOpenPlayingQueue(final ArrayList<Song> queue, final int startPosition, final boolean startPlaying) {
|
|
||||||
if (getPlayingQueue() == queue) {
|
|
||||||
if (startPlaying) {
|
|
||||||
playSongAt(startPosition);
|
|
||||||
} else {
|
|
||||||
setPosition(startPosition);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Song getCurrentSong() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getCurrentSong();
|
|
||||||
}
|
|
||||||
return Song.EMPTY_SONG;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getPosition() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getPosition();
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async
|
|
||||||
*/
|
|
||||||
public static void setPosition(final int position) {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.setPosition(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<Song> getPlayingQueue() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getPlayingQueue();
|
|
||||||
}
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getSongProgressMillis() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getSongProgressMillis();
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getSongDurationMillis() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getSongDurationMillis();
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getQueueDurationMillis(int position) {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getQueueDurationMillis(position);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int seekTo(int millis) {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.seek(millis);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getRepeatMode() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getRepeatMode();
|
|
||||||
}
|
|
||||||
return MusicService.REPEAT_MODE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getShuffleMode() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getShuffleMode();
|
|
||||||
}
|
|
||||||
return MusicService.SHUFFLE_MODE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean cycleRepeatMode() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.cycleRepeatMode();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean toggleShuffleMode() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.toggleShuffle();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean setShuffleMode(final int shuffleMode) {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.setShuffleMode(shuffleMode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean playNext(Song song) {
|
|
||||||
if (musicService != null) {
|
|
||||||
if (getPlayingQueue().size() > 0) {
|
|
||||||
musicService.addSong(getPosition() + 1, song);
|
|
||||||
} else {
|
|
||||||
ArrayList<Song> queue = new ArrayList<>();
|
|
||||||
queue.add(song);
|
|
||||||
openQueue(queue, 0, false);
|
|
||||||
}
|
|
||||||
Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean playNext(@NonNull ArrayList<Song> songs) {
|
|
||||||
if (musicService != null) {
|
|
||||||
if (getPlayingQueue().size() > 0) {
|
|
||||||
musicService.addSongs(getPosition() + 1, songs);
|
|
||||||
} else {
|
|
||||||
openQueue(songs, 0, false);
|
|
||||||
}
|
|
||||||
final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size());
|
|
||||||
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean enqueue(Song song) {
|
|
||||||
if (musicService != null) {
|
|
||||||
if (getPlayingQueue().size() > 0) {
|
|
||||||
musicService.addSong(song);
|
|
||||||
} else {
|
|
||||||
ArrayList<Song> queue = new ArrayList<>();
|
|
||||||
queue.add(song);
|
|
||||||
openQueue(queue, 0, false);
|
|
||||||
}
|
|
||||||
Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean enqueue(@NonNull ArrayList<Song> songs) {
|
|
||||||
if (musicService != null) {
|
|
||||||
if (getPlayingQueue().size() > 0) {
|
|
||||||
musicService.addSongs(songs);
|
|
||||||
} else {
|
|
||||||
openQueue(songs, 0, false);
|
|
||||||
}
|
|
||||||
final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size());
|
|
||||||
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean removeFromQueue(@NonNull Song song) {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.removeSong(song);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean removeFromQueue(int position) {
|
|
||||||
if (musicService != null && position >= 0 && position < getPlayingQueue().size()) {
|
|
||||||
musicService.removeSong(position);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean moveSong(int from, int to) {
|
|
||||||
if (musicService != null && from >= 0 && to >= 0 && from < getPlayingQueue().size() && to < getPlayingQueue().size()) {
|
|
||||||
musicService.moveSong(from, to);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean clearQueue() {
|
|
||||||
if (musicService != null) {
|
|
||||||
musicService.clearQueue();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getAudioSessionId() {
|
|
||||||
if (musicService != null) {
|
|
||||||
return musicService.getAudioSessionId();
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void playFromUri(Uri uri) {
|
|
||||||
if (musicService != null) {
|
|
||||||
ArrayList<Song> songs = null;
|
|
||||||
if (uri.getScheme() != null && uri.getAuthority() != null) {
|
|
||||||
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
|
|
||||||
String songId = null;
|
|
||||||
if (uri.getAuthority().equals("com.android.providers.media.documents")) {
|
|
||||||
songId = getSongIdFromMediaProvider(uri);
|
|
||||||
} else if (uri.getAuthority().equals("media")) {
|
|
||||||
songId = uri.getLastPathSegment();
|
|
||||||
}
|
|
||||||
if (songId != null) {
|
|
||||||
/* songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
|
||||||
musicService,
|
|
||||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
|
||||||
new String[]{songId}
|
|
||||||
));*/
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
musicService,
|
|
||||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
|
||||||
new String[]{songId}))
|
|
||||||
.subscribeOn(Schedulers.io()).blockingFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (songs == null) {
|
|
||||||
File songFile = null;
|
|
||||||
if (uri.getAuthority() != null && uri.getAuthority().equals("com.android.externalstorage.documents")) {
|
|
||||||
songFile = new File(Environment.getExternalStorageDirectory(), uri.getPath().split(":", 2)[1]);
|
|
||||||
}
|
|
||||||
if (songFile == null) {
|
|
||||||
String path = getFilePathFromUri(musicService, uri);
|
|
||||||
if (path != null)
|
|
||||||
songFile = new File(path);
|
|
||||||
}
|
|
||||||
if (songFile == null && uri.getPath() != null) {
|
|
||||||
songFile = new File(uri.getPath());
|
|
||||||
}
|
|
||||||
if (songFile != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
musicService,
|
|
||||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
|
||||||
new String[]{songFile.getAbsolutePath()}
|
|
||||||
)).blockingFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (songs != null && !songs.isEmpty()) {
|
|
||||||
openQueue(songs, 0, true);
|
|
||||||
} else {
|
|
||||||
//TODO the file is not listed in the media store
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
||||||
private static String getSongIdFromMediaProvider(Uri uri) {
|
|
||||||
return DocumentsContract.getDocumentId(uri).split(":")[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isServiceConnected() {
|
|
||||||
return musicService != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface PlaybackLocation {
|
|
||||||
int REMOTE = 0;
|
|
||||||
int LOCAL = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class ServiceBinder implements ServiceConnection {
|
|
||||||
private final ServiceConnection mCallback;
|
|
||||||
|
|
||||||
ServiceBinder(final ServiceConnection callback) {
|
|
||||||
mCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceConnected(final ComponentName className, final IBinder service) {
|
|
||||||
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
|
|
||||||
musicService = binder.getService();
|
|
||||||
if (mCallback != null) {
|
|
||||||
mCallback.onServiceConnected(className, service);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceDisconnected(final ComponentName className) {
|
|
||||||
if (mCallback != null) {
|
|
||||||
mCallback.onServiceDisconnected(className);
|
|
||||||
}
|
|
||||||
musicService = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class ServiceToken {
|
|
||||||
ContextWrapper mWrappedContext;
|
|
||||||
|
|
||||||
ServiceToken(final ContextWrapper context) {
|
|
||||||
mWrappedContext = context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,440 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.*
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.App
|
||||||
|
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(App.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.emptySong
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
var position: Int
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.position
|
||||||
|
} else -1
|
||||||
|
set(position) {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.position = position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val playingQueue: ArrayList<Song>
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.playingQueue
|
||||||
|
} else ArrayList()
|
||||||
|
|
||||||
|
val songProgressMillis: Int
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.songProgressMillis
|
||||||
|
} else -1
|
||||||
|
|
||||||
|
val songDurationMillis: Int
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.songDurationMillis
|
||||||
|
} else -1
|
||||||
|
|
||||||
|
val repeatMode: Int
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.repeatMode
|
||||||
|
} else MusicService.REPEAT_MODE_NONE
|
||||||
|
|
||||||
|
val shuffleMode: Int
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.shuffleMode
|
||||||
|
} else MusicService.SHUFFLE_MODE_NONE
|
||||||
|
|
||||||
|
val audioSessionId: Int
|
||||||
|
get() = if (musicService != null) {
|
||||||
|
musicService!!.audioSessionId
|
||||||
|
} else -1
|
||||||
|
|
||||||
|
val isServiceConnected: Boolean
|
||||||
|
get() = musicService != null
|
||||||
|
|
||||||
|
fun bindToService(context: Context,
|
||||||
|
callback: ServiceConnection): ServiceToken? {
|
||||||
|
|
||||||
|
var realActivity: Activity? = (context as Activity).parent
|
||||||
|
if (realActivity == null) {
|
||||||
|
realActivity = context
|
||||||
|
}
|
||||||
|
|
||||||
|
val contextWrapper = ContextWrapper(realActivity)
|
||||||
|
contextWrapper.startService(Intent(contextWrapper, MusicService::class.java))
|
||||||
|
|
||||||
|
val binder = ServiceBinder(callback)
|
||||||
|
|
||||||
|
if (contextWrapper.bindService(Intent().setClass(contextWrapper, MusicService::class.java), binder, Context.BIND_AUTO_CREATE)) {
|
||||||
|
mConnectionMap[contextWrapper] = binder
|
||||||
|
return ServiceToken(contextWrapper)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unbindFromService(token: ServiceToken?) {
|
||||||
|
if (token == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val mContextWrapper = token.mWrappedContext
|
||||||
|
val mBinder = mConnectionMap.remove(mContextWrapper) ?: return
|
||||||
|
mContextWrapper.unbindService(mBinder)
|
||||||
|
if (mConnectionMap.isEmpty()) {
|
||||||
|
musicService = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFilePathFromUri(context: Context, uri: Uri): String? {
|
||||||
|
|
||||||
|
val column = "_data"
|
||||||
|
val projection = arrayOf(column)
|
||||||
|
try {
|
||||||
|
context.contentResolver.query(uri, projection, null, null, null)!!.use { cursor ->
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
val column_index = cursor.getColumnIndexOrThrow(column)
|
||||||
|
return cursor.getString(column_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, e.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
fun playSongAt(position: Int) {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.playSongAt(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pauseSong() {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
fun playNextSong() {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.playNextSong(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
fun playPreviousSong() {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.playPreviousSong(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
fun back() {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.back(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resumePlaying() {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
fun openQueue(queue: ArrayList<Song>, startPosition: Int, startPlaying: Boolean) {
|
||||||
|
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
||||||
|
musicService!!.openQueue(queue, startPosition, startPlaying)
|
||||||
|
if (PreferenceUtil.getInstance().isShuffleModeOn)
|
||||||
|
setShuffleMode(MusicService.SHUFFLE_MODE_NONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async
|
||||||
|
*/
|
||||||
|
fun openAndShuffleQueue(queue: ArrayList<Song>, startPlaying: Boolean) {
|
||||||
|
var startPosition = 0
|
||||||
|
if (!queue.isEmpty()) {
|
||||||
|
startPosition = Random().nextInt(queue.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
|
||||||
|
openQueue(queue, startPosition, startPlaying)
|
||||||
|
setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryToHandleOpenPlayingQueue(queue: ArrayList<Song>, startPosition: Int, startPlaying: Boolean): Boolean {
|
||||||
|
if (playingQueue === queue) {
|
||||||
|
if (startPlaying) {
|
||||||
|
playSongAt(startPosition)
|
||||||
|
} else {
|
||||||
|
position = startPosition
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getQueueDurationMillis(position: Int): Long {
|
||||||
|
return if (musicService != null) {
|
||||||
|
musicService!!.getQueueDurationMillis(position)
|
||||||
|
} else -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun seekTo(millis: Int): Int {
|
||||||
|
return if (musicService != null) {
|
||||||
|
musicService!!.seek(millis)
|
||||||
|
} else -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cycleRepeatMode(): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.cycleRepeatMode()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleShuffleMode(): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.toggleShuffle()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setShuffleMode(shuffleMode: Int): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.shuffleMode = shuffleMode
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playNext(song: Song): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
if (playingQueue.size > 0) {
|
||||||
|
musicService!!.addSong(position + 1, song)
|
||||||
|
} else {
|
||||||
|
val queue = ArrayList<Song>()
|
||||||
|
queue.add(song)
|
||||||
|
openQueue(queue, 0, false)
|
||||||
|
}
|
||||||
|
Toast.makeText(musicService, musicService!!.resources.getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playNext(songs: ArrayList<Song>): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
if (playingQueue.size > 0) {
|
||||||
|
musicService!!.addSongs(position + 1, songs)
|
||||||
|
} else {
|
||||||
|
openQueue(songs, 0, false)
|
||||||
|
}
|
||||||
|
val toast = if (songs.size == 1) musicService!!.resources.getString(R.string.added_title_to_playing_queue) else musicService!!.resources.getString(R.string.added_x_titles_to_playing_queue, songs.size)
|
||||||
|
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enqueue(song: Song): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
if (playingQueue.size > 0) {
|
||||||
|
musicService!!.addSong(song)
|
||||||
|
} else {
|
||||||
|
val queue = ArrayList<Song>()
|
||||||
|
queue.add(song)
|
||||||
|
openQueue(queue, 0, false)
|
||||||
|
}
|
||||||
|
Toast.makeText(musicService, musicService!!.resources.getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enqueue(songs: ArrayList<Song>): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
if (playingQueue.size > 0) {
|
||||||
|
musicService!!.addSongs(songs)
|
||||||
|
} else {
|
||||||
|
openQueue(songs, 0, false)
|
||||||
|
}
|
||||||
|
val toast = if (songs.size == 1) musicService!!.resources.getString(R.string.added_title_to_playing_queue) else musicService!!.resources.getString(R.string.added_x_titles_to_playing_queue, songs.size)
|
||||||
|
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFromQueue(song: Song): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.removeSong(song)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFromQueue(position: Int): Boolean {
|
||||||
|
if (musicService != null && position >= 0 && position < playingQueue.size) {
|
||||||
|
musicService!!.removeSong(position)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveSong(from: Int, to: Int): Boolean {
|
||||||
|
if (musicService != null && from >= 0 && to >= 0 && from < playingQueue.size && to < playingQueue.size) {
|
||||||
|
musicService!!.moveSong(from, to)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearQueue(): Boolean {
|
||||||
|
if (musicService != null) {
|
||||||
|
musicService!!.clearQueue()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playFromUri(uri: Uri) {
|
||||||
|
if (musicService != null) {
|
||||||
|
var songs: ArrayList<Song>? = null
|
||||||
|
if (uri.scheme != null && uri.authority != null) {
|
||||||
|
if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
|
||||||
|
var songId: String? = null
|
||||||
|
if (uri.authority == "com.android.providers.media.documents") {
|
||||||
|
songId = getSongIdFromMediaProvider(uri)
|
||||||
|
} else if (uri.authority == "media") {
|
||||||
|
songId = uri.lastPathSegment
|
||||||
|
}
|
||||||
|
if (songId != null) {
|
||||||
|
/* songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||||
|
musicService,
|
||||||
|
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||||
|
new String[]{songId}
|
||||||
|
));*/
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||||
|
musicService!!,
|
||||||
|
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||||
|
arrayOf(songId)))
|
||||||
|
.subscribeOn(Schedulers.io()).blockingFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (songs == null) {
|
||||||
|
var songFile: File? = null
|
||||||
|
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
|
||||||
|
songFile = File(Environment.getExternalStorageDirectory(), uri.path!!.split(":".toRegex(), 2).toTypedArray()[1])
|
||||||
|
}
|
||||||
|
if (songFile == null) {
|
||||||
|
val path = getFilePathFromUri(musicService!!, uri)
|
||||||
|
if (path != null)
|
||||||
|
songFile = File(path)
|
||||||
|
}
|
||||||
|
if (songFile == null && uri.path != null) {
|
||||||
|
songFile = File(uri.path)
|
||||||
|
}
|
||||||
|
if (songFile != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(musicService!!, MediaStore.Audio.AudioColumns.DATA + "=?", arrayOf(songFile.absolutePath)
|
||||||
|
)).blockingFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (songs != null && !songs.isEmpty()) {
|
||||||
|
openQueue(songs, 0, true)
|
||||||
|
} else {
|
||||||
|
//TODO the file is not listed in the media store
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||||
|
private fun getSongIdFromMediaProvider(uri: Uri): String {
|
||||||
|
return DocumentsContract.getDocumentId(uri).split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
internal annotation class PlaybackLocation {
|
||||||
|
companion object {
|
||||||
|
val REMOTE = 0
|
||||||
|
val LOCAL = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServiceBinder internal constructor(private val mCallback: ServiceConnection?) : ServiceConnection {
|
||||||
|
|
||||||
|
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||||
|
val binder = service as MusicService.MusicBinder
|
||||||
|
musicService = binder.service
|
||||||
|
mCallback?.onServiceConnected(className, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(className: ComponentName) {
|
||||||
|
mCallback?.onServiceDisconnected(className)
|
||||||
|
musicService = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServiceToken internal constructor(internal var mWrappedContext: ContextWrapper)
|
||||||
|
|
||||||
|
}
|
|
@ -1,71 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
|
|
||||||
public class MusicProgressViewUpdateHelper extends Handler {
|
|
||||||
private static final int CMD_REFRESH_PROGRESS_VIEWS = 1;
|
|
||||||
|
|
||||||
private static final int MIN_INTERVAL = 20;
|
|
||||||
private static final int UPDATE_INTERVAL_PLAYING = 1000;
|
|
||||||
private static final int UPDATE_INTERVAL_PAUSED = 500;
|
|
||||||
|
|
||||||
private Callback callback;
|
|
||||||
private int intervalPlaying;
|
|
||||||
private int intervalPaused;
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
queueNextRefresh(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
removeMessages(CMD_REFRESH_PROGRESS_VIEWS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MusicProgressViewUpdateHelper(Callback callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
this.intervalPlaying = UPDATE_INTERVAL_PLAYING;
|
|
||||||
this.intervalPaused = UPDATE_INTERVAL_PAUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MusicProgressViewUpdateHelper(Callback callback, int intervalPlaying, int intervalPaused) {
|
|
||||||
this.callback = callback;
|
|
||||||
this.intervalPlaying = intervalPlaying;
|
|
||||||
this.intervalPaused = intervalPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(@NonNull Message msg) {
|
|
||||||
super.handleMessage(msg);
|
|
||||||
if (msg.what == CMD_REFRESH_PROGRESS_VIEWS) {
|
|
||||||
queueNextRefresh(refreshProgressViews());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int refreshProgressViews() {
|
|
||||||
final int progressMillis = MusicPlayerRemote.getSongProgressMillis();
|
|
||||||
final int totalMillis = MusicPlayerRemote.getSongDurationMillis();
|
|
||||||
|
|
||||||
callback.onUpdateProgressViews(progressMillis, totalMillis);
|
|
||||||
|
|
||||||
if (!MusicPlayerRemote.isPlaying()) {
|
|
||||||
return intervalPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int remainingMillis = intervalPlaying - progressMillis % intervalPlaying;
|
|
||||||
|
|
||||||
return Math.max(MIN_INTERVAL, remainingMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void queueNextRefresh(final long delay) {
|
|
||||||
final Message message = obtainMessage(CMD_REFRESH_PROGRESS_VIEWS);
|
|
||||||
removeMessages(CMD_REFRESH_PROGRESS_VIEWS);
|
|
||||||
sendMessageDelayed(message, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Callback {
|
|
||||||
void onUpdateProgressViews(int progress, int total);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Message
|
||||||
|
|
||||||
|
|
||||||
|
class MusicProgressViewUpdateHelper : Handler {
|
||||||
|
|
||||||
|
private var callback: Callback? = null
|
||||||
|
private var intervalPlaying: Int = 0
|
||||||
|
private var intervalPaused: Int = 0
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
queueNextRefresh(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(callback: Callback) {
|
||||||
|
this.callback = callback
|
||||||
|
this.intervalPlaying = UPDATE_INTERVAL_PLAYING
|
||||||
|
this.intervalPaused = UPDATE_INTERVAL_PAUSED
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(callback: Callback, intervalPlaying: Int, intervalPaused: Int) {
|
||||||
|
this.callback = callback
|
||||||
|
this.intervalPlaying = intervalPlaying
|
||||||
|
this.intervalPaused = intervalPaused
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleMessage(msg: Message) {
|
||||||
|
super.handleMessage(msg)
|
||||||
|
if (msg.what == CMD_REFRESH_PROGRESS_VIEWS) {
|
||||||
|
queueNextRefresh(refreshProgressViews().toLong())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshProgressViews(): Int {
|
||||||
|
val progressMillis = MusicPlayerRemote.songProgressMillis
|
||||||
|
val totalMillis = MusicPlayerRemote.songDurationMillis
|
||||||
|
|
||||||
|
callback!!.onUpdateProgressViews(progressMillis, totalMillis)
|
||||||
|
|
||||||
|
if (!MusicPlayerRemote.isPlaying) {
|
||||||
|
return intervalPaused
|
||||||
|
}
|
||||||
|
|
||||||
|
val remainingMillis = intervalPlaying - progressMillis % intervalPlaying
|
||||||
|
|
||||||
|
return Math.max(MIN_INTERVAL, remainingMillis)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun queueNextRefresh(delay: Long) {
|
||||||
|
val message = obtainMessage(CMD_REFRESH_PROGRESS_VIEWS)
|
||||||
|
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
|
||||||
|
sendMessageDelayed(message, delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onUpdateProgressViews(progress: Int, total: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val CMD_REFRESH_PROGRESS_VIEWS = 1
|
||||||
|
|
||||||
|
private val MIN_INTERVAL = 20
|
||||||
|
private val UPDATE_INTERVAL_PLAYING = 1000
|
||||||
|
private val UPDATE_INTERVAL_PAUSED = 500
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
|
|
||||||
public class PlayPauseButtonOnClickHandler implements View.OnClickListener {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (MusicPlayerRemote.isPlaying()) {
|
|
||||||
MusicPlayerRemote.pauseSong();
|
|
||||||
} else {
|
|
||||||
MusicPlayerRemote.resumePlaying();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
|
||||||
|
class PlayPauseButtonOnClickHandler : View.OnClickListener {
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
if (MusicPlayerRemote.isPlaying) {
|
||||||
|
MusicPlayerRemote.pauseSong()
|
||||||
|
} else {
|
||||||
|
MusicPlayerRemote.resumePlaying()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,91 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.app.SearchManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
|
|
||||||
|
|
||||||
public class SearchQueryHelper {
|
|
||||||
private static final String TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?";
|
|
||||||
private static final String ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?";
|
|
||||||
private static final String ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?";
|
|
||||||
private static final String AND = " AND ";
|
|
||||||
private static ArrayList<Song> songs = new ArrayList<>();
|
|
||||||
|
|
||||||
public static ArrayList<Song> getSongs() {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setSongs(ArrayList<Song> songs) {
|
|
||||||
SearchQueryHelper.songs = songs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static ArrayList<Song> getSongs(@NonNull final Context context, @NonNull final Bundle extras) {
|
|
||||||
final String query = extras.getString(SearchManager.QUERY, null);
|
|
||||||
final String artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null);
|
|
||||||
final String albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null);
|
|
||||||
final String titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null);
|
|
||||||
|
|
||||||
ArrayList<Song> songs = new ArrayList<>();
|
|
||||||
if (artistName != null && albumName != null && titleName != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
|
||||||
}
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
if (artistName != null && titleName != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
|
||||||
}
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
if (albumName != null && titleName != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
|
||||||
}
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
if (artistName != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase()})).blockingFirst();
|
|
||||||
}
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
if (albumName != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase()})).blockingFirst();
|
|
||||||
}
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
if (titleName != null) {
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase()})).blockingFirst();
|
|
||||||
}
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
|
||||||
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
return new ArrayList<Song>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.app.SearchManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import code.name.monkey.retromusic.loaders.SongLoader
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
object SearchQueryHelper {
|
||||||
|
private val TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"
|
||||||
|
private val ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"
|
||||||
|
private val ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"
|
||||||
|
private val AND = " AND "
|
||||||
|
var songs = ArrayList<Song>()
|
||||||
|
|
||||||
|
fun getSongs(context: Context, extras: Bundle): ArrayList<Song> {
|
||||||
|
val query = extras.getString(SearchManager.QUERY, null)
|
||||||
|
val artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null)
|
||||||
|
val albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null)
|
||||||
|
val titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null)
|
||||||
|
|
||||||
|
var songs = ArrayList<Song>()
|
||||||
|
if (artistName != null && albumName != null && titleName != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, arrayOf(artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()))).blockingFirst()
|
||||||
|
}
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
if (artistName != null && titleName != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, arrayOf(artistName.toLowerCase(), titleName.toLowerCase()))).blockingFirst()
|
||||||
|
}
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
if (albumName != null && titleName != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, arrayOf(albumName.toLowerCase(), titleName.toLowerCase()))).blockingFirst()
|
||||||
|
}
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
if (artistName != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, arrayOf(artistName.toLowerCase()))).blockingFirst()
|
||||||
|
}
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
if (albumName != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, arrayOf(albumName.toLowerCase()))).blockingFirst()
|
||||||
|
}
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
if (titleName != null) {
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, arrayOf(titleName.toLowerCase()))).blockingFirst()
|
||||||
|
}
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, arrayOf(query.toLowerCase()))).blockingFirst()
|
||||||
|
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, arrayOf(query.toLowerCase()))).blockingFirst()
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, arrayOf(query.toLowerCase()))).blockingFirst()
|
||||||
|
return if (!songs.isEmpty()) {
|
||||||
|
songs
|
||||||
|
} else ArrayList()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
public class ShuffleHelper {
|
|
||||||
|
|
||||||
public static void makeShuffleList(@NonNull List<Song> listToShuffle, final int current) {
|
|
||||||
if (listToShuffle.isEmpty()) return;
|
|
||||||
if (current >= 0) {
|
|
||||||
Song song = listToShuffle.remove(current);
|
|
||||||
Collections.shuffle(listToShuffle);
|
|
||||||
listToShuffle.add(0, song);
|
|
||||||
} else {
|
|
||||||
Collections.shuffle(listToShuffle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
|
|
||||||
|
object ShuffleHelper {
|
||||||
|
|
||||||
|
fun makeShuffleList(listToShuffle: MutableList<Song>, current: Int) {
|
||||||
|
if (listToShuffle.isEmpty()) return
|
||||||
|
if (current >= 0) {
|
||||||
|
val song = listToShuffle.removeAt(current)
|
||||||
|
listToShuffle.shuffle()
|
||||||
|
listToShuffle.add(0, song)
|
||||||
|
} else {
|
||||||
|
listToShuffle.shuffle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2012 Andrew Neal Licensed under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with the
|
|
||||||
* License. You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
|
|
||||||
* or agreed to in writing, software distributed under the License is
|
|
||||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the specific language
|
|
||||||
* governing permissions and limitations under the License.
|
|
||||||
*/
|
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds all of the sort orders for each list type.
|
|
||||||
*
|
|
||||||
* @author Andrew Neal (andrewdneal@gmail.com)
|
|
||||||
*/
|
|
||||||
public final class SortOrder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is never instantiated
|
|
||||||
*/
|
|
||||||
public SortOrder() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Artist sort order entries.
|
|
||||||
*/
|
|
||||||
public interface ArtistSortOrder {
|
|
||||||
|
|
||||||
/* Artist sort order A-Z */
|
|
||||||
String ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Artist sort order Z-A */
|
|
||||||
String ARTIST_Z_A = ARTIST_A_Z + " DESC";
|
|
||||||
|
|
||||||
/* Artist sort order number of songs */
|
|
||||||
String ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS
|
|
||||||
+ " DESC";
|
|
||||||
|
|
||||||
/* Artist sort order number of albums */
|
|
||||||
String ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS
|
|
||||||
+ " DESC";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Album sort order entries.
|
|
||||||
*/
|
|
||||||
public interface AlbumSortOrder {
|
|
||||||
|
|
||||||
/* Album sort order A-Z */
|
|
||||||
String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Album sort order Z-A */
|
|
||||||
String ALBUM_Z_A = ALBUM_A_Z + " DESC";
|
|
||||||
|
|
||||||
/* Album sort order songs */
|
|
||||||
String ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS
|
|
||||||
+ " DESC";
|
|
||||||
|
|
||||||
/* Album sort order artist */
|
|
||||||
String ALBUM_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
|
||||||
+ ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Album sort order year */
|
|
||||||
String ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Song sort order entries.
|
|
||||||
*/
|
|
||||||
public interface SongSortOrder {
|
|
||||||
|
|
||||||
/* Song sort order A-Z */
|
|
||||||
String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Song sort order Z-A */
|
|
||||||
String SONG_Z_A = SONG_A_Z + " DESC";
|
|
||||||
|
|
||||||
/* Song sort order artist */
|
|
||||||
String SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Song sort order album */
|
|
||||||
String SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Song sort order year */
|
|
||||||
String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
|
|
||||||
|
|
||||||
/* Song sort order duration */
|
|
||||||
String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC";
|
|
||||||
|
|
||||||
/* Song sort order date */
|
|
||||||
String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Album song sort order entries.
|
|
||||||
*/
|
|
||||||
public interface AlbumSongSortOrder {
|
|
||||||
|
|
||||||
/* Album song sort order A-Z */
|
|
||||||
String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Album song sort order Z-A */
|
|
||||||
String SONG_Z_A = SONG_A_Z + " DESC";
|
|
||||||
|
|
||||||
/* Album song sort order track list */
|
|
||||||
String SONG_TRACK_LIST = MediaStore.Audio.Media.TRACK + ", "
|
|
||||||
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Album song sort order duration */
|
|
||||||
String SONG_DURATION = SongSortOrder.SONG_DURATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Artist song sort order entries.
|
|
||||||
*/
|
|
||||||
public interface ArtistSongSortOrder {
|
|
||||||
|
|
||||||
/* Artist song sort order A-Z */
|
|
||||||
String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Artist song sort order Z-A */
|
|
||||||
String SONG_Z_A = SONG_A_Z + " DESC";
|
|
||||||
|
|
||||||
/* Artist song sort order album */
|
|
||||||
String SONG_ALBUM = MediaStore.Audio.Media.ALBUM;
|
|
||||||
|
|
||||||
/* Artist song sort order year */
|
|
||||||
String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
|
|
||||||
|
|
||||||
/* Artist song sort order duration */
|
|
||||||
String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC";
|
|
||||||
|
|
||||||
/* Artist song sort order date */
|
|
||||||
String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Artist album sort order entries.
|
|
||||||
*/
|
|
||||||
public interface ArtistAlbumSortOrder {
|
|
||||||
|
|
||||||
/* Artist album sort order A-Z */
|
|
||||||
String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Artist album sort order Z-A */
|
|
||||||
String ALBUM_Z_A = ALBUM_A_Z + " DESC";
|
|
||||||
|
|
||||||
/* Artist album sort order year */
|
|
||||||
String ALBUM_YEAR = MediaStore.Audio.Media.YEAR
|
|
||||||
+ " DESC";
|
|
||||||
|
|
||||||
/* Artist album sort order year */
|
|
||||||
String ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR
|
|
||||||
+ " ASC";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Genre sort order entries.
|
|
||||||
*/
|
|
||||||
public interface GenreSortOrder {
|
|
||||||
|
|
||||||
/* Genre sort order A-Z */
|
|
||||||
String GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER;
|
|
||||||
|
|
||||||
/* Genre sort order Z-A */
|
|
||||||
String ALBUM_Z_A = GENRE_A_Z + " DESC";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Andrew Neal Licensed under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
|
||||||
|
* or agreed to in writing, software distributed under the License is
|
||||||
|
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the specific language
|
||||||
|
* governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
import android.provider.MediaStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds all of the sort orders for each list type.
|
||||||
|
*
|
||||||
|
* @author Andrew Neal (andrewdneal@gmail.com)
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This class is never instantiated
|
||||||
|
*/
|
||||||
|
class SortOrder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Artist sort order entries.
|
||||||
|
*/
|
||||||
|
interface ArtistSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Artist sort order A-Z */
|
||||||
|
val ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Artist sort order Z-A */
|
||||||
|
val ARTIST_Z_A = "$ARTIST_A_Z DESC"
|
||||||
|
|
||||||
|
/* Artist sort order number of songs */
|
||||||
|
val ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + " DESC"
|
||||||
|
|
||||||
|
/* Artist sort order number of albums */
|
||||||
|
val ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + " DESC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Album sort order entries.
|
||||||
|
*/
|
||||||
|
interface AlbumSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Album sort order A-Z */
|
||||||
|
val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Album sort order Z-A */
|
||||||
|
val ALBUM_Z_A = "$ALBUM_A_Z DESC"
|
||||||
|
|
||||||
|
/* Album sort order songs */
|
||||||
|
val ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + " DESC"
|
||||||
|
|
||||||
|
/* Album sort order artist */
|
||||||
|
val ALBUM_ARTIST = (MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||||
|
+ ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER)
|
||||||
|
|
||||||
|
/* Album sort order year */
|
||||||
|
val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Song sort order entries.
|
||||||
|
*/
|
||||||
|
interface SongSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Song sort order A-Z */
|
||||||
|
val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Song sort order Z-A */
|
||||||
|
val SONG_Z_A = "$SONG_A_Z DESC"
|
||||||
|
|
||||||
|
/* Song sort order artist */
|
||||||
|
val SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Song sort order album */
|
||||||
|
val SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Song sort order year */
|
||||||
|
val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||||
|
|
||||||
|
/* Song sort order duration */
|
||||||
|
val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"
|
||||||
|
|
||||||
|
/* Song sort order date */
|
||||||
|
val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Album song sort order entries.
|
||||||
|
*/
|
||||||
|
interface AlbumSongSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Album song sort order A-Z */
|
||||||
|
val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Album song sort order Z-A */
|
||||||
|
val SONG_Z_A = "$SONG_A_Z DESC"
|
||||||
|
|
||||||
|
/* Album song sort order track list */
|
||||||
|
val SONG_TRACK_LIST = (MediaStore.Audio.Media.TRACK + ", "
|
||||||
|
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
|
||||||
|
|
||||||
|
/* Album song sort order duration */
|
||||||
|
val SONG_DURATION = SongSortOrder.SONG_DURATION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Artist song sort order entries.
|
||||||
|
*/
|
||||||
|
interface ArtistSongSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Artist song sort order A-Z */
|
||||||
|
val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Artist song sort order Z-A */
|
||||||
|
val SONG_Z_A = "$SONG_A_Z DESC"
|
||||||
|
|
||||||
|
/* Artist song sort order album */
|
||||||
|
val SONG_ALBUM = MediaStore.Audio.Media.ALBUM
|
||||||
|
|
||||||
|
/* Artist song sort order year */
|
||||||
|
val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||||
|
|
||||||
|
/* Artist song sort order duration */
|
||||||
|
val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"
|
||||||
|
|
||||||
|
/* Artist song sort order date */
|
||||||
|
val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Artist album sort order entries.
|
||||||
|
*/
|
||||||
|
interface ArtistAlbumSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Artist album sort order A-Z */
|
||||||
|
val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Artist album sort order Z-A */
|
||||||
|
val ALBUM_Z_A = "$ALBUM_A_Z DESC"
|
||||||
|
|
||||||
|
/* Artist album sort order year */
|
||||||
|
val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
|
||||||
|
|
||||||
|
/* Artist album sort order year */
|
||||||
|
val ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR + " ASC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genre sort order entries.
|
||||||
|
*/
|
||||||
|
interface GenreSortOrder {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/* Genre sort order A-Z */
|
||||||
|
val GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
|
/* Genre sort order Z-A */
|
||||||
|
val ALBUM_Z_A = "$GENRE_A_Z DESC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,82 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple thread safe stop watch.
|
|
||||||
*
|
|
||||||
* @author Karim Abou Zeid (kabouzeid)
|
|
||||||
*/
|
|
||||||
public class StopWatch {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time the stop watch was last started.
|
|
||||||
*/
|
|
||||||
private long startTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time elapsed before the current {@link #startTime}.
|
|
||||||
*/
|
|
||||||
private long previousElapsedTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the stop watch is currently running or not.
|
|
||||||
*/
|
|
||||||
private boolean isRunning;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts or continues the stop watch.
|
|
||||||
*
|
|
||||||
* @see #pause()
|
|
||||||
* @see #reset()
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
synchronized (this) {
|
|
||||||
startTime = System.currentTimeMillis();
|
|
||||||
isRunning = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses the stop watch. It can be continued later from {@link #start()}.
|
|
||||||
*
|
|
||||||
* @see #start()
|
|
||||||
* @see #reset()
|
|
||||||
*/
|
|
||||||
public void pause() {
|
|
||||||
synchronized (this) {
|
|
||||||
previousElapsedTime += System.currentTimeMillis() - startTime;
|
|
||||||
isRunning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops and resets the stop watch to zero milliseconds.
|
|
||||||
*
|
|
||||||
* @see #start()
|
|
||||||
* @see #pause()
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
synchronized (this) {
|
|
||||||
startTime = 0;
|
|
||||||
previousElapsedTime = 0;
|
|
||||||
isRunning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the total elapsed time in milliseconds
|
|
||||||
*/
|
|
||||||
public final long getElapsedTime() {
|
|
||||||
synchronized (this) {
|
|
||||||
long currentElapsedTime = 0;
|
|
||||||
if (isRunning) {
|
|
||||||
currentElapsedTime = System.currentTimeMillis() - startTime;
|
|
||||||
}
|
|
||||||
return previousElapsedTime + currentElapsedTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("%d millis", getElapsedTime());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple thread safe stop watch.
|
||||||
|
*
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
class StopWatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the stop watch was last started.
|
||||||
|
*/
|
||||||
|
private var startTime: Long = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time elapsed before the current [.startTime].
|
||||||
|
*/
|
||||||
|
private var previousElapsedTime: Long = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the stop watch is currently running or not.
|
||||||
|
*/
|
||||||
|
private var isRunning: Boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the total elapsed time in milliseconds
|
||||||
|
*/
|
||||||
|
val elapsedTime: Long
|
||||||
|
get() = synchronized(this) {
|
||||||
|
var currentElapsedTime: Long = 0
|
||||||
|
if (isRunning) {
|
||||||
|
currentElapsedTime = System.currentTimeMillis() - startTime
|
||||||
|
}
|
||||||
|
return previousElapsedTime + currentElapsedTime
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts or continues the stop watch.
|
||||||
|
*
|
||||||
|
* @see .pause
|
||||||
|
* @see .reset
|
||||||
|
*/
|
||||||
|
fun start() {
|
||||||
|
synchronized(this) {
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
isRunning = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses the stop watch. It can be continued later from [.start].
|
||||||
|
*
|
||||||
|
* @see .start
|
||||||
|
* @see .reset
|
||||||
|
*/
|
||||||
|
fun pause() {
|
||||||
|
synchronized(this) {
|
||||||
|
previousElapsedTime += System.currentTimeMillis() - startTime
|
||||||
|
isRunning = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops and resets the stop watch to zero milliseconds.
|
||||||
|
*
|
||||||
|
* @see .start
|
||||||
|
* @see .pause
|
||||||
|
*/
|
||||||
|
fun reset() {
|
||||||
|
synchronized(this) {
|
||||||
|
startTime = 0
|
||||||
|
previousElapsedTime = 0
|
||||||
|
isRunning = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return String.format("%d millis", elapsedTime)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper.menu;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.loaders.GenreLoader;
|
|
||||||
import code.name.monkey.retromusic.model.Genre;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Hemanth S (h4h13).
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class GenreMenuHelper {
|
|
||||||
public static boolean handleMenuClick(@NonNull AppCompatActivity activity,
|
|
||||||
@NonNull Genre genre,
|
|
||||||
@NonNull MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case R.id.action_play:
|
|
||||||
MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true);
|
|
||||||
return true;
|
|
||||||
case R.id.action_play_next:
|
|
||||||
MusicPlayerRemote.playNext(getGenreSongs(activity, genre));
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_playlist:
|
|
||||||
AddToPlaylistDialog.create(getGenreSongs(activity, genre))
|
|
||||||
.show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_current_playing:
|
|
||||||
MusicPlayerRemote.enqueue(getGenreSongs(activity, genre));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static ArrayList<Song> getGenreSongs(@NonNull Activity activity,
|
|
||||||
@NonNull Genre genre) {
|
|
||||||
ArrayList<Song> songs;
|
|
||||||
songs = GenreLoader.getSongs(activity, genre.id).blockingFirst();
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package code.name.monkey.retromusic.helper.menu
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||||
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
import code.name.monkey.retromusic.loaders.GenreLoader
|
||||||
|
import code.name.monkey.retromusic.model.Genre
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hemanth S (h4h13).
|
||||||
|
*/
|
||||||
|
|
||||||
|
object GenreMenuHelper {
|
||||||
|
fun handleMenuClick(activity: AppCompatActivity, genre: Genre, item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_play -> {
|
||||||
|
MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_play_next -> {
|
||||||
|
MusicPlayerRemote.playNext(getGenreSongs(activity, genre))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_add_to_playlist -> {
|
||||||
|
AddToPlaylistDialog.create(getGenreSongs(activity, genre))
|
||||||
|
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_add_to_current_playing -> {
|
||||||
|
MusicPlayerRemote.enqueue(getGenreSongs(activity, genre))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGenreSongs(activity: Activity,
|
||||||
|
genre: Genre): ArrayList<Song> {
|
||||||
|
val songs: ArrayList<Song>
|
||||||
|
songs = GenreLoader.getSongs(activity, genre.id).blockingFirst()
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,91 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper.menu;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.RetroApplication;
|
|
||||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
|
||||||
import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog;
|
|
||||||
import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog;
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
|
||||||
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
|
|
||||||
import code.name.monkey.retromusic.misc.WeakContextAsyncTask;
|
|
||||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil;
|
|
||||||
|
|
||||||
|
|
||||||
public class PlaylistMenuHelper {
|
|
||||||
|
|
||||||
public static boolean handleMenuClick(@NonNull AppCompatActivity activity,
|
|
||||||
@NonNull final Playlist playlist, @NonNull MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case R.id.action_play:
|
|
||||||
MusicPlayerRemote.openQueue(getPlaylistSongs(activity, playlist), 9, true);
|
|
||||||
return true;
|
|
||||||
case R.id.action_play_next:
|
|
||||||
MusicPlayerRemote.playNext(getPlaylistSongs(activity, playlist));
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_playlist:
|
|
||||||
AddToPlaylistDialog.create(getPlaylistSongs(activity, playlist))
|
|
||||||
.show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_current_playing:
|
|
||||||
MusicPlayerRemote.enqueue(getPlaylistSongs(activity, playlist));
|
|
||||||
return true;
|
|
||||||
case R.id.action_rename_playlist:
|
|
||||||
RenamePlaylistDialog.create(playlist.id)
|
|
||||||
.show(activity.getSupportFragmentManager(), "RENAME_PLAYLIST");
|
|
||||||
return true;
|
|
||||||
case R.id.action_delete_playlist:
|
|
||||||
DeletePlaylistDialog.create(playlist)
|
|
||||||
.show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
|
|
||||||
return true;
|
|
||||||
case R.id.action_save_playlist:
|
|
||||||
new SavePlaylistAsyncTask(activity).execute(playlist);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static ArrayList<Song> getPlaylistSongs(@NonNull Activity activity,
|
|
||||||
@NonNull Playlist playlist) {
|
|
||||||
ArrayList<Song> songs;
|
|
||||||
if (playlist instanceof AbsCustomPlaylist) {
|
|
||||||
songs = ((AbsCustomPlaylist) playlist).getSongs(activity).blockingFirst();
|
|
||||||
} else {
|
|
||||||
songs = PlaylistSongsLoader.getPlaylistSongList(activity, playlist).blockingFirst();
|
|
||||||
}
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class SavePlaylistAsyncTask extends WeakContextAsyncTask<Playlist, String, String> {
|
|
||||||
SavePlaylistAsyncTask(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doInBackground(Playlist... params) {
|
|
||||||
return String.format(RetroApplication.getInstance().getApplicationContext().getString(R.string
|
|
||||||
.saved_playlist_to), PlaylistsUtil.savePlaylist(RetroApplication.getInstance().getApplicationContext(), params[0]).blockingFirst());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(String string) {
|
|
||||||
super.onPostExecute(string);
|
|
||||||
Context context = getContext();
|
|
||||||
if (context != null) {
|
|
||||||
Toast.makeText(context, string, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package code.name.monkey.retromusic.helper.menu
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.widget.Toast
|
||||||
|
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.App
|
||||||
|
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(App.instance.applicationContext.getString(R.string
|
||||||
|
.saved_playlist_to), PlaylistsUtil.savePlaylist(App.instance.applicationContext, params[0]).blockingFirst())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostExecute(string: String) {
|
||||||
|
super.onPostExecute(string)
|
||||||
|
val context = context
|
||||||
|
if (context != null) {
|
||||||
|
Toast.makeText(context, string, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,93 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper.menu;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.PopupMenu;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
|
||||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog;
|
|
||||||
import code.name.monkey.retromusic.dialogs.SongDetailDialog;
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
|
||||||
import code.name.monkey.retromusic.interfaces.PaletteColorHolder;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity;
|
|
||||||
import code.name.monkey.retromusic.ui.activities.tageditor.SongTagEditorActivity;
|
|
||||||
import code.name.monkey.retromusic.util.MusicUtil;
|
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil;
|
|
||||||
|
|
||||||
|
|
||||||
public class SongMenuHelper {
|
|
||||||
public static final int MENU_RES = R.menu.menu_item_song;
|
|
||||||
|
|
||||||
public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull Song song, int menuItemId) {
|
|
||||||
switch (menuItemId) {
|
|
||||||
case R.id.action_set_as_ringtone:
|
|
||||||
MusicUtil.setRingtone(activity, song.id);
|
|
||||||
return true;
|
|
||||||
case R.id.action_share:
|
|
||||||
activity.startActivity(Intent.createChooser(MusicUtil.createShareSongFileIntent(song, activity), null));
|
|
||||||
return true;
|
|
||||||
case R.id.action_delete_from_device:
|
|
||||||
DeleteSongsDialog.create(song).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_playlist:
|
|
||||||
AddToPlaylistDialog.create(song).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
|
||||||
return true;
|
|
||||||
case R.id.action_play_next:
|
|
||||||
MusicPlayerRemote.playNext(song);
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_current_playing:
|
|
||||||
MusicPlayerRemote.enqueue(song);
|
|
||||||
return true;
|
|
||||||
case R.id.action_tag_editor:
|
|
||||||
Intent tagEditorIntent = new Intent(activity, SongTagEditorActivity.class);
|
|
||||||
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id);
|
|
||||||
if (activity instanceof PaletteColorHolder)
|
|
||||||
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_PALETTE, ((PaletteColorHolder) activity).getPaletteColor());
|
|
||||||
activity.startActivity(tagEditorIntent);
|
|
||||||
return true;
|
|
||||||
case R.id.action_details:
|
|
||||||
SongDetailDialog.create(song).show(activity.getSupportFragmentManager(), "SONG_DETAILS");
|
|
||||||
return true;
|
|
||||||
case R.id.action_go_to_album:
|
|
||||||
NavigationUtil.goToAlbum(activity, song.albumId);
|
|
||||||
return true;
|
|
||||||
case R.id.action_go_to_artist:
|
|
||||||
NavigationUtil.goToArtist(activity, song.artistId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static abstract class OnClickSongMenu implements View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
|
||||||
private AppCompatActivity activity;
|
|
||||||
|
|
||||||
protected OnClickSongMenu(@NonNull AppCompatActivity activity) {
|
|
||||||
this.activity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMenuRes() {
|
|
||||||
return MENU_RES;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
PopupMenu popupMenu = new PopupMenu(activity, v);
|
|
||||||
popupMenu.inflate(getMenuRes());
|
|
||||||
popupMenu.setOnMenuItemClickListener(this);
|
|
||||||
popupMenu.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
return handleMenuClick(activity, getSong(), item.getItemId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Song getSong();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
package code.name.monkey.retromusic.helper.menu
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.PopupMenu
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||||
|
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
||||||
|
import code.name.monkey.retromusic.dialogs.SongDetailDialog
|
||||||
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.ui.activities.tageditor.AbsTagEditorActivity
|
||||||
|
import code.name.monkey.retromusic.ui.activities.tageditor.SongTagEditorActivity
|
||||||
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
|
|
||||||
|
|
||||||
|
object SongMenuHelper {
|
||||||
|
val MENU_RES = R.menu.menu_item_song
|
||||||
|
|
||||||
|
fun handleMenuClick(activity: FragmentActivity, song: Song, menuItemId: Int): Boolean {
|
||||||
|
when (menuItemId) {
|
||||||
|
R.id.action_set_as_ringtone -> {
|
||||||
|
MusicUtil.setRingtone(activity, song.id)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_share -> {
|
||||||
|
activity.startActivity(Intent.createChooser(MusicUtil.createShareSongFileIntent(song, activity), null))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_delete_from_device -> {
|
||||||
|
DeleteSongsDialog.create(song).show(activity.supportFragmentManager, "DELETE_SONGS")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_add_to_playlist -> {
|
||||||
|
AddToPlaylistDialog.create(song).show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_play_next -> {
|
||||||
|
MusicPlayerRemote.playNext(song)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_add_to_current_playing -> {
|
||||||
|
MusicPlayerRemote.enqueue(song)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_tag_editor -> {
|
||||||
|
val tagEditorIntent = Intent(activity, SongTagEditorActivity::class.java)
|
||||||
|
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id)
|
||||||
|
if (activity is PaletteColorHolder)
|
||||||
|
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_PALETTE, (activity as PaletteColorHolder).paletteColor)
|
||||||
|
activity.startActivity(tagEditorIntent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_details -> {
|
||||||
|
SongDetailDialog.create(song).show(activity.supportFragmentManager, "SONG_DETAILS")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_go_to_album -> {
|
||||||
|
NavigationUtil.goToAlbum(activity, song.albumId)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_go_to_artist -> {
|
||||||
|
NavigationUtil.goToArtist(activity, song.artistId)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class OnClickSongMenu protected constructor(private val activity: AppCompatActivity) : View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
||||||
|
|
||||||
|
open val menuRes: Int
|
||||||
|
get() = MENU_RES
|
||||||
|
|
||||||
|
abstract val song: Song
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
val popupMenu = PopupMenu(activity, v)
|
||||||
|
popupMenu.inflate(menuRes)
|
||||||
|
popupMenu.setOnMenuItemClickListener(this)
|
||||||
|
popupMenu.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
|
return handleMenuClick(activity, song, item.itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
package code.name.monkey.retromusic.helper.menu;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog;
|
|
||||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog;
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class SongsMenuHelper {
|
|
||||||
public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull ArrayList<Song> songs, int menuItemId) {
|
|
||||||
switch (menuItemId) {
|
|
||||||
case R.id.action_play_next:
|
|
||||||
MusicPlayerRemote.playNext(songs);
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_current_playing:
|
|
||||||
MusicPlayerRemote.enqueue(songs);
|
|
||||||
return true;
|
|
||||||
case R.id.action_add_to_playlist:
|
|
||||||
AddToPlaylistDialog.create(songs).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
|
|
||||||
return true;
|
|
||||||
case R.id.action_delete_from_device:
|
|
||||||
DeleteSongsDialog.create(songs).show(activity.getSupportFragmentManager(), "DELETE_SONGS");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package code.name.monkey.retromusic.helper.menu
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||||
|
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
||||||
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
object SongsMenuHelper {
|
||||||
|
fun handleMenuClick(activity: FragmentActivity, songs: ArrayList<Song>, menuItemId: Int): Boolean {
|
||||||
|
when (menuItemId) {
|
||||||
|
R.id.action_play_next -> {
|
||||||
|
MusicPlayerRemote.playNext(songs)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_add_to_current_playing -> {
|
||||||
|
MusicPlayerRemote.enqueue(songs)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_add_to_playlist -> {
|
||||||
|
AddToPlaylistDialog.create(songs).show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_delete_from_device -> {
|
||||||
|
DeleteSongsDialog.create(songs).show(activity.supportFragmentManager, "DELETE_SONGS")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
package code.name.monkey.retromusic.interfaces;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.afollestad.materialcab.MaterialCab;
|
|
||||||
|
|
||||||
|
|
||||||
public interface CabHolder {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
MaterialCab openCab(final int menuRes, final MaterialCab.Callback callback);
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package code.name.monkey.retromusic.interfaces
|
||||||
|
|
||||||
|
import com.afollestad.materialcab.MaterialCab
|
||||||
|
|
||||||
|
|
||||||
|
interface CabHolder {
|
||||||
|
|
||||||
|
fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
package code.name.monkey.retromusic.interfaces;
|
|
||||||
|
|
||||||
import android.media.audiofx.BassBoost;
|
|
||||||
import android.media.audiofx.Equalizer;
|
|
||||||
import android.media.audiofx.Virtualizer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Hemanth S (h4h13).
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface EqualizerInterface {
|
|
||||||
int getBandLevelLow();
|
|
||||||
|
|
||||||
int getBandLevelHigh();
|
|
||||||
|
|
||||||
int getNumberOfBands();
|
|
||||||
|
|
||||||
int getCenterFreq(int band);
|
|
||||||
|
|
||||||
int getBandLevel(int band);
|
|
||||||
|
|
||||||
void setBandLevel(int band, int level);
|
|
||||||
|
|
||||||
boolean isBassBoostEnabled();
|
|
||||||
|
|
||||||
void setBassBoostEnabled(boolean isEnabled);
|
|
||||||
|
|
||||||
int getBassBoostStrength();
|
|
||||||
|
|
||||||
void setBassBoostStrength(int strength);
|
|
||||||
|
|
||||||
boolean isVirtualizerEnabled();
|
|
||||||
|
|
||||||
void setVirtualizerEnabled(boolean isEnabled);
|
|
||||||
|
|
||||||
int getVirtualizerStrength();
|
|
||||||
|
|
||||||
void setVirtualizerStrength(int strength);
|
|
||||||
|
|
||||||
boolean isRunning();
|
|
||||||
|
|
||||||
Equalizer getEqualizer();
|
|
||||||
|
|
||||||
BassBoost getBassBoost();
|
|
||||||
|
|
||||||
Virtualizer getVirtualizer();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package code.name.monkey.retromusic.interfaces
|
||||||
|
|
||||||
|
import android.media.audiofx.BassBoost
|
||||||
|
import android.media.audiofx.Equalizer
|
||||||
|
import android.media.audiofx.Virtualizer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hemanth S (h4h13).
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface EqualizerInterface {
|
||||||
|
val bandLevelLow: Int
|
||||||
|
|
||||||
|
val bandLevelHigh: Int
|
||||||
|
|
||||||
|
val numberOfBands: Int
|
||||||
|
|
||||||
|
var isBassBoostEnabled: Boolean
|
||||||
|
|
||||||
|
var bassBoostStrength: Int
|
||||||
|
|
||||||
|
var isVirtualizerEnabled: Boolean
|
||||||
|
|
||||||
|
var virtualizerStrength: Int
|
||||||
|
|
||||||
|
val isRunning: Boolean
|
||||||
|
|
||||||
|
val equalizer: Equalizer
|
||||||
|
|
||||||
|
val bassBoost: BassBoost
|
||||||
|
|
||||||
|
val virtualizer: Virtualizer
|
||||||
|
|
||||||
|
fun getCenterFreq(band: Int): Int
|
||||||
|
|
||||||
|
fun getBandLevel(band: Int): Int
|
||||||
|
|
||||||
|
fun setBandLevel(band: Int, level: Int)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
package code.name.monkey.retromusic.interfaces;
|
|
||||||
|
|
||||||
|
|
||||||
public interface LoaderIds {
|
|
||||||
int FOLDERS_FRAGMENT = 5;
|
|
||||||
}
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package code.name.monkey.retromusic.interfaces
|
||||||
|
|
||||||
|
|
||||||
|
interface LoaderIds {
|
||||||
|
companion object {
|
||||||
|
val FOLDERS_FRAGMENT = 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
package code.name.monkey.retromusic.interfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by hemanths on 14/08/17.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface MainActivityFragmentCallbacks {
|
|
||||||
boolean handleBackPress();
|
|
||||||
|
|
||||||
//void selectedFragment(Fragment fragment);
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package code.name.monkey.retromusic.interfaces
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by hemanths on 14/08/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface MainActivityFragmentCallbacks {
|
||||||
|
fun handleBackPress(): Boolean
|
||||||
|
|
||||||
|
//void selectedFragment(Fragment fragment);
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
package code.name.monkey.retromusic.interfaces;
|
|
||||||
|
|
||||||
|
|
||||||
public interface MusicServiceEventListener {
|
|
||||||
void onServiceConnected();
|
|
||||||
|
|
||||||
void onServiceDisconnected();
|
|
||||||
|
|
||||||
void onQueueChanged();
|
|
||||||
|
|
||||||
void onPlayingMetaChanged();
|
|
||||||
|
|
||||||
void onPlayStateChanged();
|
|
||||||
|
|
||||||
void onRepeatModeChanged();
|
|
||||||
|
|
||||||
void onShuffleModeChanged();
|
|
||||||
|
|
||||||
void onMediaStoreChanged();
|
|
||||||
}
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package code.name.monkey.retromusic.interfaces
|
||||||
|
|
||||||
|
|
||||||
|
interface MusicServiceEventListener {
|
||||||
|
fun onServiceConnected()
|
||||||
|
|
||||||
|
fun onServiceDisconnected()
|
||||||
|
|
||||||
|
fun onQueueChanged()
|
||||||
|
|
||||||
|
fun onPlayingMetaChanged()
|
||||||
|
|
||||||
|
fun onPlayStateChanged()
|
||||||
|
|
||||||
|
fun onRepeatModeChanged()
|
||||||
|
|
||||||
|
fun onShuffleModeChanged()
|
||||||
|
|
||||||
|
fun onMediaStoreChanged()
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
package code.name.monkey.retromusic.interfaces;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Aidan Follestad (afollestad)
|
|
||||||
*/
|
|
||||||
public interface PaletteColorHolder {
|
|
||||||
|
|
||||||
@ColorInt
|
|
||||||
int getPaletteColor();
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package code.name.monkey.retromusic.interfaces
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad)
|
||||||
|
*/
|
||||||
|
interface PaletteColorHolder {
|
||||||
|
|
||||||
|
@get:ColorInt
|
||||||
|
val paletteColor: Int
|
||||||
|
}
|
|
@ -1,104 +0,0 @@
|
||||||
package code.name.monkey.retromusic.loaders;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.provider.MediaStore.Audio.AudioColumns;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import code.name.monkey.retromusic.model.Album;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by hemanths on 11/08/17.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class AlbumLoader {
|
|
||||||
|
|
||||||
public static Observable<ArrayList<Album>> getAllAlbums(@NonNull Context context) {
|
|
||||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
context,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
getSongLoaderSortOrder(context))
|
|
||||||
);
|
|
||||||
|
|
||||||
return splitIntoAlbums(songs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Album>> getAlbums(@NonNull final Context context,
|
|
||||||
String query) {
|
|
||||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
context,
|
|
||||||
AudioColumns.ALBUM + " LIKE ?",
|
|
||||||
new String[]{"%" + query + "%"},
|
|
||||||
getSongLoaderSortOrder(context))
|
|
||||||
);
|
|
||||||
return splitIntoAlbums(songs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<Album> getAlbum(@NonNull final Context context, int albumId) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion
|
|
||||||
.makeSongCursor(context, AudioColumns.ALBUM_ID + "=?",
|
|
||||||
new String[]{String.valueOf(albumId)}, getSongLoaderSortOrder(context)));
|
|
||||||
songs.subscribe(songs1 -> {
|
|
||||||
e.onNext(new Album(songs1));
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Album>> splitIntoAlbums(
|
|
||||||
@Nullable final Observable<ArrayList<Song>> songs) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
ArrayList<Album> albums = new ArrayList<>();
|
|
||||||
if (songs != null) {
|
|
||||||
songs.subscribe(songs1 -> {
|
|
||||||
for (Song song : songs1) {
|
|
||||||
getOrCreateAlbum(albums, song.albumId).subscribe(album -> album.songs.add(song));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
e.onNext(albums);
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static ArrayList<Album> splitIntoAlbums(@Nullable final ArrayList<Song> songs) {
|
|
||||||
ArrayList<Album> albums = new ArrayList<>();
|
|
||||||
if (songs != null) {
|
|
||||||
for (Song song : songs) {
|
|
||||||
getOrCreateAlbum(albums, song.albumId).subscribe(album -> album.songs.add(song));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return albums;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Observable<Album> getOrCreateAlbum(ArrayList<Album> albums, int albumId) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
for (Album album : albums) {
|
|
||||||
if (!album.songs.isEmpty() && album.songs.get(0).albumId == albumId) {
|
|
||||||
e.onNext(album);
|
|
||||||
e.onComplete();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Album album = new Album();
|
|
||||||
albums.add(album);
|
|
||||||
e.onNext(album);
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getSongLoaderSortOrder(Context context) {
|
|
||||||
return PreferenceUtil.getInstance().getAlbumSortOrder() + ", " +
|
|
||||||
//PreferenceUtil.getInstance().getAlbumSongSortOrder() + "," +
|
|
||||||
PreferenceUtil.getInstance().getAlbumDetailSongSortOrder();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package code.name.monkey.retromusic.loaders
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
import code.name.monkey.retromusic.model.Album
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by hemanths on 11/08/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
open class AlbumLoader {
|
||||||
|
companion object {
|
||||||
|
fun getAllAlbums(context: Context): Observable<ArrayList<Album>> {
|
||||||
|
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||||
|
context, null, null,
|
||||||
|
getSongLoaderSortOrder())
|
||||||
|
)
|
||||||
|
|
||||||
|
return splitIntoAlbums(songs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlbums(context: Context,
|
||||||
|
query: String): Observable<ArrayList<Album>> {
|
||||||
|
val songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||||
|
context,
|
||||||
|
AudioColumns.ALBUM + " LIKE ?",
|
||||||
|
arrayOf("%$query%"),
|
||||||
|
getSongLoaderSortOrder())
|
||||||
|
)
|
||||||
|
return splitIntoAlbums(songs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlbum(context: Context, albumId: Int): Observable<Album> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
val songs = SongLoader.getSongs(SongLoader
|
||||||
|
.makeSongCursor(context, AudioColumns.ALBUM_ID + "=?",
|
||||||
|
arrayOf(albumId.toString()), getSongLoaderSortOrder()))
|
||||||
|
songs.subscribe { songs1 ->
|
||||||
|
e.onNext(Album(songs1))
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun splitIntoAlbums(
|
||||||
|
songs: Observable<ArrayList<Song>>?): Observable<ArrayList<Album>> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
val albums = ArrayList<Album>()
|
||||||
|
songs?.subscribe { songs1 ->
|
||||||
|
for (song in songs1) {
|
||||||
|
getOrCreateAlbum(albums, song.albumId).subscribe { album -> album.songs!!.add(song) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.onNext(albums)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun splitIntoAlbums(songs: ArrayList<Song>?): ArrayList<Album> {
|
||||||
|
val albums = ArrayList<Album>()
|
||||||
|
if (songs != null) {
|
||||||
|
for (song in songs) {
|
||||||
|
getOrCreateAlbum(albums, song.albumId).subscribe { album -> album.songs!!.add(song) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return albums
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOrCreateAlbum(albums: ArrayList<Album>, albumId: Int): Observable<Album> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
for (album in albums) {
|
||||||
|
if (!album.songs!!.isEmpty() && album.songs[0].albumId == albumId) {
|
||||||
|
e.onNext(album)
|
||||||
|
e.onComplete()
|
||||||
|
return@create
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val album = Album()
|
||||||
|
albums.add(album)
|
||||||
|
e.onNext(album)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSongLoaderSortOrder(): String {
|
||||||
|
return PreferenceUtil.getInstance().albumSortOrder + ", " +
|
||||||
|
//PreferenceUtil.getInstance().getAlbumSongSortOrder() + "," +
|
||||||
|
PreferenceUtil.getInstance().albumDetailSongSortOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,101 +0,0 @@
|
||||||
package code.name.monkey.retromusic.loaders;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.provider.MediaStore.Audio.AudioColumns;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Album;
|
|
||||||
import code.name.monkey.retromusic.model.Artist;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
|
|
||||||
public class ArtistLoader {
|
|
||||||
private static String getSongLoaderSortOrder(Context context) {
|
|
||||||
return PreferenceUtil.getInstance().getArtistSortOrder() + ", " +
|
|
||||||
PreferenceUtil.getInstance().getArtistAlbumSortOrder() + ", " +
|
|
||||||
PreferenceUtil.getInstance().getAlbumDetailSongSortOrder() + ", " +
|
|
||||||
PreferenceUtil.getInstance().getArtistDetailSongSortOrder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<Artist> getArtist(@NonNull final Context context, int artistId) {
|
|
||||||
return Observable.create(e -> SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
context,
|
|
||||||
AudioColumns.ARTIST_ID + "=?",
|
|
||||||
new String[]{String.valueOf(artistId)},
|
|
||||||
getSongLoaderSortOrder(context)))
|
|
||||||
.subscribe(songs -> {
|
|
||||||
Artist artist = new Artist(AlbumLoader.splitIntoAlbums(songs));
|
|
||||||
e.onNext(artist);
|
|
||||||
e.onComplete();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Artist>> getAllArtists(@NonNull final Context context) {
|
|
||||||
return Observable.create(e -> SongLoader.Companion
|
|
||||||
.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
context,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
getSongLoaderSortOrder(context))
|
|
||||||
).subscribe(songs -> {
|
|
||||||
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)));
|
|
||||||
e.onComplete();
|
|
||||||
}));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Artist>> getArtists(@NonNull final Context context, String query) {
|
|
||||||
return Observable.create(e -> SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
|
||||||
context,
|
|
||||||
AudioColumns.ARTIST + " LIKE ?",
|
|
||||||
new String[]{"%" + query + "%"},
|
|
||||||
getSongLoaderSortOrder(context))
|
|
||||||
).subscribe(songs -> {
|
|
||||||
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)));
|
|
||||||
e.onComplete();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static ArrayList<Artist> splitIntoArtists(@Nullable final ArrayList<Album> albums) {
|
|
||||||
ArrayList<Artist> artists = new ArrayList<>();
|
|
||||||
if (albums != null) {
|
|
||||||
for (Album album : albums) {
|
|
||||||
getOrCreateArtist(artists, album.getArtistId()).albums.add(album);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return artists;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Artist getOrCreateArtist(ArrayList<Artist> artists, int artistId) {
|
|
||||||
for (Artist artist : artists) {
|
|
||||||
if (!artist.albums.isEmpty() && !artist.albums.get(0).songs.isEmpty() && artist.albums.get(0).songs.get(0).artistId == artistId) {
|
|
||||||
return artist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Artist album = new Artist();
|
|
||||||
artists.add(album);
|
|
||||||
return album;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Observable<ArrayList<Artist>> splitIntoArtists(Observable<ArrayList<Album>> albums) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
ArrayList<Artist> artists = new ArrayList<>();
|
|
||||||
albums.subscribe(localAlbums -> {
|
|
||||||
if (localAlbums != null) {
|
|
||||||
for (Album album : localAlbums) {
|
|
||||||
getOrCreateArtist(artists, album.getArtistId()).albums.add(album);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.onNext(artists);
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package code.name.monkey.retromusic.loaders
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.model.Album
|
||||||
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import io.reactivex.Observable
|
||||||
|
|
||||||
|
object ArtistLoader {
|
||||||
|
private fun getSongLoaderSortOrder(): String {
|
||||||
|
return PreferenceUtil.getInstance().artistSortOrder + ", " +
|
||||||
|
PreferenceUtil.getInstance().artistAlbumSortOrder + ", " +
|
||||||
|
PreferenceUtil.getInstance().albumDetailSongSortOrder + ", " +
|
||||||
|
PreferenceUtil.getInstance().artistDetailSongSortOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getArtist(context: Context, artistId: Int): Observable<Artist> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||||
|
context,
|
||||||
|
AudioColumns.ARTIST_ID + "=?",
|
||||||
|
arrayOf(artistId.toString()),
|
||||||
|
getSongLoaderSortOrder()))
|
||||||
|
.subscribe { songs ->
|
||||||
|
val artist = Artist(AlbumLoader.splitIntoAlbums(songs))
|
||||||
|
e.onNext(artist)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAllArtists(context: Context): Observable<ArrayList<Artist>> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
SongLoader
|
||||||
|
.getSongs(SongLoader.makeSongCursor(
|
||||||
|
context, null, null,
|
||||||
|
getSongLoaderSortOrder())
|
||||||
|
).subscribe { songs ->
|
||||||
|
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)))
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getArtists(context: Context, query: String): Observable<ArrayList<Artist>> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||||
|
context,
|
||||||
|
AudioColumns.ARTIST + " LIKE ?",
|
||||||
|
arrayOf("%$query%"),
|
||||||
|
getSongLoaderSortOrder())
|
||||||
|
).subscribe { songs ->
|
||||||
|
e.onNext(splitIntoArtists(AlbumLoader.splitIntoAlbums(songs)))
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun splitIntoArtists(albums: ArrayList<Album>?): ArrayList<Artist> {
|
||||||
|
val artists = ArrayList<Artist>()
|
||||||
|
if (albums != null) {
|
||||||
|
for (album in albums) {
|
||||||
|
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return artists
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOrCreateArtist(artists: ArrayList<Artist>, artistId: Int): Artist {
|
||||||
|
for (artist in artists) {
|
||||||
|
if (!artist.albums!!.isEmpty() && !artist.albums[0].songs!!.isEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
|
||||||
|
return artist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val album = Artist()
|
||||||
|
artists.add(album)
|
||||||
|
return album
|
||||||
|
}
|
||||||
|
|
||||||
|
fun splitIntoArtists(albums: Observable<ArrayList<Album>>): Observable<ArrayList<Artist>> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
val artists = ArrayList<Artist>()
|
||||||
|
albums.subscribe { localAlbums ->
|
||||||
|
if (localAlbums != null) {
|
||||||
|
for (album in localAlbums) {
|
||||||
|
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.onNext(artists)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
package code.name.monkey.retromusic.loaders;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
|
|
||||||
|
|
||||||
public class ArtistSongLoader extends SongLoader {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Song>> getArtistSongList(@NonNull final Context context, final int artistId) {
|
|
||||||
return Companion.getSongs(makeArtistSongCursor(context, artistId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor makeArtistSongCursor(@NonNull final Context context, final int artistId) {
|
|
||||||
try {
|
|
||||||
return Companion.makeSongCursor(
|
|
||||||
context,
|
|
||||||
MediaStore.Audio.AudioColumns.ARTIST_ID + "=?",
|
|
||||||
new String[]{
|
|
||||||
String.valueOf(artistId)
|
|
||||||
},
|
|
||||||
PreferenceUtil.getInstance().getArtistSongSortOrder()
|
|
||||||
);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package code.name.monkey.retromusic.loaders;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.BaseColumns;
|
|
||||||
import android.provider.MediaStore.Audio.Genres;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import code.name.monkey.retromusic.model.Genre;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
|
|
||||||
public class GenreLoader {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Genre>> getAllGenres(@NonNull final Context context) {
|
|
||||||
return getGenresFromCursor(context, makeGenreCursor(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Observable<ArrayList<Song>> getSongs(@NonNull final Context context, final int genreId) {
|
|
||||||
// The genres table only stores songs that have a genre specified,
|
|
||||||
// so we need to get songs without a genre a different way.
|
|
||||||
if (genreId == -1) {
|
|
||||||
return getSongsWithNoGenre(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SongLoader.Companion.getSongs(makeGenreSongCursor(context, genreId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static Genre getGenreFromCursor(@NonNull Context context, @NonNull final Cursor cursor) {
|
|
||||||
final int id = cursor.getInt(0);
|
|
||||||
final String name = cursor.getString(1);
|
|
||||||
final int songCount = getSongs(context, id).blockingFirst().size();
|
|
||||||
return new Genre(id, name, songCount);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static Observable<ArrayList<Song>> getSongsWithNoGenre(@NonNull final Context context) {
|
|
||||||
String selection = BaseColumns._ID + " NOT IN " +
|
|
||||||
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)";
|
|
||||||
return SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, selection, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasSongsWithNoGenre(@NonNull final Context context) {
|
|
||||||
final Cursor allSongsCursor = SongLoader.Companion.makeSongCursor(context, null, null);
|
|
||||||
final Cursor allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context);
|
|
||||||
|
|
||||||
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean hasSongsWithNoGenre = allSongsCursor.getCount() > allSongsWithGenreCursor.getCount();
|
|
||||||
allSongsCursor.close();
|
|
||||||
allSongsWithGenreCursor.close();
|
|
||||||
return hasSongsWithNoGenre;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Cursor makeAllSongsWithGenreCursor(@NonNull final Context context) {
|
|
||||||
try {
|
|
||||||
return context.getContentResolver().query(
|
|
||||||
Uri.parse("content://media/external/audio/genres/all/members"),
|
|
||||||
new String[]{Genres.Members.AUDIO_ID}, null, null, null);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Cursor makeGenreSongCursor(@NonNull final Context context, int genreId) {
|
|
||||||
try {
|
|
||||||
return context.getContentResolver().query(
|
|
||||||
Genres.Members.getContentUri("external", genreId),
|
|
||||||
SongLoader.Companion.getBASE_PROJECTION(), SongLoader.BASE_SELECTION, null, PreferenceUtil.getInstance().getSongSortOrder());
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static Observable<ArrayList<Genre>> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
final ArrayList<Genre> genres = new ArrayList<>();
|
|
||||||
if (cursor != null) {
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
do {
|
|
||||||
Genre genre = getGenreFromCursor(context, cursor);
|
|
||||||
if (genre.songCount > 0) {
|
|
||||||
genres.add(genre);
|
|
||||||
} else {
|
|
||||||
// try to remove the empty genre from the media store
|
|
||||||
try {
|
|
||||||
context.getContentResolver().delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + " == " + genre.id, null);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
// nothing we can do then
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (cursor.moveToNext());
|
|
||||||
}
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
e.onNext(genres);
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Cursor makeGenreCursor(@NonNull final Context context) {
|
|
||||||
final String[] projection = new String[]{
|
|
||||||
Genres._ID,
|
|
||||||
Genres.NAME
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
return context.getContentResolver().query(
|
|
||||||
Genres.EXTERNAL_CONTENT_URI,
|
|
||||||
projection, null, null, PreferenceUtil.getInstance().getGenreSortOrder());
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
package code.name.monkey.retromusic.loaders
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.BaseColumns
|
||||||
|
import android.provider.MediaStore.Audio.Genres
|
||||||
|
import code.name.monkey.retromusic.Constants.BASE_PROJECTION
|
||||||
|
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
||||||
|
import code.name.monkey.retromusic.model.Genre
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object GenreLoader {
|
||||||
|
|
||||||
|
fun getAllGenres(context: Context): Observable<ArrayList<Genre>> {
|
||||||
|
return getGenresFromCursor(context, makeGenreCursor(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSongs(context: Context, genreId: Int): Observable<ArrayList<Song>> {
|
||||||
|
// The genres table only stores songs that have a genre specified,
|
||||||
|
// so we need to get songs without a genre a different way.
|
||||||
|
return if (genreId == -1) {
|
||||||
|
getSongsWithNoGenre(context)
|
||||||
|
} else SongLoader.getSongs(makeGenreSongCursor(context, genreId))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGenreFromCursor(context: Context, cursor: Cursor): Genre {
|
||||||
|
val id = cursor.getInt(0)
|
||||||
|
val name = cursor.getString(1)
|
||||||
|
val songCount = getSongs(context, id).blockingFirst().size
|
||||||
|
return Genre(id, name, songCount)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSongsWithNoGenre(context: Context): Observable<ArrayList<Song>> {
|
||||||
|
val selection = BaseColumns._ID + " NOT IN " +
|
||||||
|
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)"
|
||||||
|
return SongLoader.getSongs(SongLoader.makeSongCursor(context, selection, null))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasSongsWithNoGenre(context: Context): Boolean {
|
||||||
|
val allSongsCursor = SongLoader.makeSongCursor(context, null, null)
|
||||||
|
val allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context)
|
||||||
|
|
||||||
|
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasSongsWithNoGenre = allSongsCursor.count > allSongsWithGenreCursor.count
|
||||||
|
allSongsCursor.close()
|
||||||
|
allSongsWithGenreCursor.close()
|
||||||
|
return hasSongsWithNoGenre
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeAllSongsWithGenreCursor(context: Context): Cursor? {
|
||||||
|
try {
|
||||||
|
return context.contentResolver.query(
|
||||||
|
Uri.parse("content://media/external/audio/genres/all/members"),
|
||||||
|
arrayOf(Genres.Members.AUDIO_ID), null, null, null)
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeGenreSongCursor(context: Context, genreId: Int): Cursor? {
|
||||||
|
try {
|
||||||
|
return context.contentResolver.query(
|
||||||
|
Genres.Members.getContentUri("external", genreId.toLong()),
|
||||||
|
BASE_PROJECTION, BASE_SELECTION, null, PreferenceUtil.getInstance().songSortOrder)
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGenresFromCursor(context: Context, cursor: Cursor?): Observable<ArrayList<Genre>> {
|
||||||
|
return Observable.create { e ->
|
||||||
|
val genres = ArrayList<Genre>()
|
||||||
|
if (cursor != null) {
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
val genre = getGenreFromCursor(context, cursor)
|
||||||
|
if (genre.songCount > 0) {
|
||||||
|
genres.add(genre)
|
||||||
|
} else {
|
||||||
|
// try to remove the empty genre from the media store
|
||||||
|
try {
|
||||||
|
context.contentResolver.delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + " == " + genre.id, null)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
// nothing we can do then
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (cursor.moveToNext())
|
||||||
|
}
|
||||||
|
cursor.close()
|
||||||
|
}
|
||||||
|
e.onNext(genres)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun makeGenreCursor(context: Context): Cursor? {
|
||||||
|
val projection = arrayOf(Genres._ID, Genres.NAME)
|
||||||
|
|
||||||
|
try {
|
||||||
|
return context.contentResolver.query(
|
||||||
|
Genres.EXTERNAL_CONTENT_URI,
|
||||||
|
projection, null, null, PreferenceUtil.getInstance().genreSortOrder)
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
package code.name.monkey.retromusic.loaders;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.provider.MediaStore.Audio.AudioColumns;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Hemanth S (h4h13).
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class GenreSongsLoader {
|
|
||||||
|
|
||||||
public static Observable<ArrayList<Song>> getGenreSongsList(@NonNull Context context, int genreId) {
|
|
||||||
return Observable.create(e -> {
|
|
||||||
ArrayList<Song> list = new ArrayList<>();
|
|
||||||
Cursor cursor = makeGenreSongCursor(context, genreId);
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
do {
|
|
||||||
list.add(getGenreSongFromCursorImpl(cursor));
|
|
||||||
} while (cursor.moveToNext());
|
|
||||||
}
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
e.onNext((ArrayList<Song>) (List) list);
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static Song getGenreSongFromCursorImpl(@NonNull Cursor cursor) {
|
|
||||||
final int id = cursor.getInt(0);
|
|
||||||
final String title = cursor.getString(1);
|
|
||||||
final int trackNumber = cursor.getInt(2);
|
|
||||||
final int year = cursor.getInt(3);
|
|
||||||
final long duration = cursor.getLong(4);
|
|
||||||
final String data = cursor.getString(5);
|
|
||||||
final int dateModified = cursor.getInt(6);
|
|
||||||
final int albumId = cursor.getInt(7);
|
|
||||||
final String albumName = cursor.getString(8);
|
|
||||||
final int artistId = cursor.getInt(9);
|
|
||||||
final String artistName = cursor.getString(10);
|
|
||||||
return new Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Cursor makeGenreSongCursor(Context context, long genreId) {
|
|
||||||
try {
|
|
||||||
return context.getContentResolver().query(
|
|
||||||
MediaStore.Audio.Genres.Members.getContentUri("external", genreId),
|
|
||||||
new String[]{
|
|
||||||
MediaStore.Audio.Playlists.Members.AUDIO_ID,// 0
|
|
||||||
AudioColumns.TITLE,// 1
|
|
||||||
AudioColumns.TRACK,// 2
|
|
||||||
AudioColumns.YEAR,// 3
|
|
||||||
AudioColumns.DURATION,// 4
|
|
||||||
AudioColumns.DATA,// 5
|
|
||||||
AudioColumns.DATE_MODIFIED,// 6
|
|
||||||
AudioColumns.ALBUM_ID,// 7
|
|
||||||
AudioColumns.ALBUM,// 8
|
|
||||||
AudioColumns.ARTIST_ID,// 9
|
|
||||||
AudioColumns.ARTIST,// 10
|
|
||||||
}, SongLoader.BASE_SELECTION, null,
|
|
||||||
MediaStore.Audio.Genres.Members.DEFAULT_SORT_ORDER);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package code.name.monkey.retromusic.loaders;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist;
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
|
|
||||||
public class HomeLoader {
|
|
||||||
|
|
||||||
public static Observable<ArrayList<AbsSmartPlaylist>> getRecentAndTopThings(
|
|
||||||
@NonNull Context context) {
|
|
||||||
ArrayList<AbsSmartPlaylist> objects = new ArrayList<>();
|
|
||||||
return Observable.create(e -> {
|
|
||||||
|
|
||||||
new HistoryPlaylist(context).getSongs(context).subscribe(songs -> {
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
objects.add(new HistoryPlaylist(context));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
new LastAddedPlaylist(context).getSongs(context).subscribe(songs -> {
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
objects.add(new LastAddedPlaylist(context));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
new MyTopTracksPlaylist(context).getSongs(context).subscribe(songs -> {
|
|
||||||
if (!songs.isEmpty()) {
|
|
||||||
objects.add(new MyTopTracksPlaylist(context));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
e.onNext(objects);
|
|
||||||
e.onComplete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Observable<ArrayList<Playlist>> getHomeLoader(@NonNull Context context) {
|
|
||||||
ArrayList<Playlist> playlists = new ArrayList<>();
|
|
||||||
PlaylistLoader.getAllPlaylists(context)
|
|
||||||
.subscribe(playlists1 -> {
|
|
||||||
if (playlists1.size() > 0) {
|
|
||||||
for (Playlist playlist : playlists1) {
|
|
||||||
PlaylistSongsLoader.getPlaylistSongList(context, playlist)
|
|
||||||
.subscribe(songs -> {
|
|
||||||
if (songs.size() > 0) {
|
|
||||||
playlists.add(playlist);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Observable.just(playlists);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package code.name.monkey.retromusic.loaders
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
import java.util.ArrayList
|
||||||
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
|
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
||||||
|
import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist
|
||||||
|
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
|
||||||
|
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist
|
||||||
|
import io.reactivex.Observable
|
||||||
|
|
||||||
|
object HomeLoader {
|
||||||
|
|
||||||
|
fun getRecentAndTopThings(
|
||||||
|
context: Context): Observable<ArrayList<AbsSmartPlaylist>> {
|
||||||
|
val objects = ArrayList<AbsSmartPlaylist>()
|
||||||
|
return Observable.create { e ->
|
||||||
|
|
||||||
|
HistoryPlaylist(context).getSongs(context).subscribe { songs ->
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
objects.add(HistoryPlaylist(context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LastAddedPlaylist(context).getSongs(context).subscribe { songs ->
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
objects.add(LastAddedPlaylist(context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyTopTracksPlaylist(context).getSongs(context).subscribe { songs ->
|
||||||
|
if (!songs.isEmpty()) {
|
||||||
|
objects.add(MyTopTracksPlaylist(context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.onNext(objects)
|
||||||
|
e.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getHomeLoader(context: Context): Observable<ArrayList<Playlist>> {
|
||||||
|
val playlists = ArrayList<Playlist>()
|
||||||
|
PlaylistLoader.getAllPlaylists(context)
|
||||||
|
.subscribe { playlists1 ->
|
||||||
|
if (playlists1.size > 0) {
|
||||||
|
for (playlist in playlists1) {
|
||||||
|
PlaylistSongsLoader.getPlaylistSongList(context, playlist)
|
||||||
|
.subscribe { songs ->
|
||||||
|
if (songs.size > 0) {
|
||||||
|
playlists.add(playlist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Observable.just(playlists)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue