commit
fbbc1a1ef9
212 changed files with 3963 additions and 1957 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -38,8 +38,4 @@ obj/
|
||||||
captures
|
captures
|
||||||
app/normal/release/
|
app/normal/release/
|
||||||
/models/
|
/models/
|
||||||
|
/app/release/
|
||||||
app/font/
|
|
||||||
app/src/debug/
|
|
||||||
/app/nofont/
|
|
||||||
/crowdin.properties
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ favorite songs. No other music player has this feature.
|
||||||
|
|
||||||
We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features.
|
We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features.
|
||||||
|
|
||||||
### FAQ
|
### ❓ FAQ
|
||||||
Please read the FAQ here: https://del.dog/RetroFaq
|
Please read the FAQ here: https://del.dog/RetroFaq
|
||||||
|
|
||||||
In any case, you find or notice any bugs please report them by
|
In any case, you find or notice any bugs please report them by
|
||||||
|
|
|
@ -34,7 +34,7 @@ android {
|
||||||
}
|
}
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
release {
|
release {
|
||||||
Properties properties = getProperties('/Users/h4h13/Documents/Github/retro.properties')
|
Properties properties = getProperties('/Users/apple/Documents/Github/retro.properties ')
|
||||||
storeFile file(getProperty(properties, 'storeFile'))
|
storeFile file(getProperty(properties, 'storeFile'))
|
||||||
keyAlias getProperty(properties, 'keyAlias')
|
keyAlias getProperty(properties, 'keyAlias')
|
||||||
storePassword getProperty(properties, 'storePassword')
|
storePassword getProperty(properties, 'storePassword')
|
||||||
|
@ -102,68 +102,50 @@ static def getDate() {
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
|
||||||
implementation project(':appthemehelper')
|
implementation project(':appthemehelper')
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01"
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'androidx.annotation:annotation:1.1.0'
|
implementation 'androidx.annotation:annotation:1.1.0'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
implementation 'androidx.core:core-ktx:1.3.1'
|
implementation 'androidx.core:core-ktx:1.3.1'
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
||||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||||
|
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8'
|
def nav_version = "2.3.0"
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||||
|
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||||
|
|
||||||
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
def room_version = "2.2.5"
|
||||||
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
def retrofit_version = '2.9.0'
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
|
||||||
|
|
||||||
def material_dialog_version = "0.9.6.0"
|
|
||||||
implementation "com.afollestad.material-dialogs:core:$material_dialog_version"
|
|
||||||
implementation "com.afollestad.material-dialogs:commons:$material_dialog_version"
|
|
||||||
implementation 'com.afollestad:material-cab:0.1.12'
|
|
||||||
|
|
||||||
implementation 'com.github.bumptech.glide:glide:3.8.0'
|
|
||||||
implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0'
|
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
|
|
||||||
|
|
||||||
implementation('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') {
|
|
||||||
transitive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
def kotlin_coroutines_version = "1.3.8"
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
|
||||||
|
|
||||||
implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r'
|
|
||||||
|
|
||||||
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
|
|
||||||
implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod'
|
|
||||||
|
|
||||||
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
|
|
||||||
|
|
||||||
implementation 'com.anjlab.android.iab.v3:library:1.1.0'
|
|
||||||
implementation 'com.r0adkll:slidableactivity:2.1.0'
|
|
||||||
implementation 'com.heinrichreimersoftware:material-intro:1.6'
|
|
||||||
implementation 'me.zhanghai.android.fastscroll:library:1.1.0'
|
|
||||||
|
|
||||||
def lifecycle_version = "2.2.0"
|
def lifecycle_version = "2.2.0"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||||
|
|
||||||
implementation 'com.google.android.play:core:1.8.0'
|
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
implementation 'me.jorgecastillo:androidcolorx:0.2.0'
|
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
||||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
|
|
||||||
implementation 'com.github.dhaval2404:imagepicker:1.7.1'
|
def retrofit_version = '2.9.0'
|
||||||
|
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||||
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
||||||
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
|
||||||
|
|
||||||
|
def material_dialog_version = "0.9.6.0"
|
||||||
|
implementation "com.afollestad.material-dialogs:core:$material_dialog_version"
|
||||||
|
implementation "com.afollestad.material-dialogs:commons:$material_dialog_version"
|
||||||
|
implementation 'com.afollestad:material-cab:0.1.12'
|
||||||
|
|
||||||
|
def kotlin_coroutines_version = "1.3.8"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10"
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
|
|
||||||
def koin_version = "2.1.5"
|
def koin_version = "2.1.5"
|
||||||
implementation "org.koin:koin-core:$koin_version"
|
implementation "org.koin:koin-core:$koin_version"
|
||||||
|
@ -173,8 +155,22 @@ dependencies {
|
||||||
implementation "org.koin:koin-androidx-fragment:$koin_version"
|
implementation "org.koin:koin-androidx-fragment:$koin_version"
|
||||||
implementation "org.koin:koin-androidx-ext:$koin_version"
|
implementation "org.koin:koin-androidx-ext:$koin_version"
|
||||||
|
|
||||||
def nav_version = "2.3.0"
|
implementation 'com.github.bumptech.glide:glide:3.8.0'
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0'
|
||||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
|
||||||
|
|
||||||
|
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||||
|
|
||||||
|
implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r'
|
||||||
|
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
|
||||||
|
implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod'
|
||||||
|
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
|
||||||
|
implementation 'com.anjlab.android.iab.v3:library:1.1.0'
|
||||||
|
implementation 'com.r0adkll:slidableactivity:2.1.0'
|
||||||
|
implementation 'com.heinrichreimersoftware:material-intro:1.6'
|
||||||
|
implementation 'com.github.dhaval2404:imagepicker:1.7.1'
|
||||||
|
implementation 'org.jsoup:jsoup:1.11.1'
|
||||||
|
implementation 'me.zhanghai.android.fastscroll:library:1.1.0'
|
||||||
|
implementation 'me.jorgecastillo:androidcolorx:0.2.0'
|
||||||
|
implementation 'org.jsoup:jsoup:1.11.1'
|
||||||
|
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
|
||||||
}
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"artifactType": {
|
|
||||||
"type": "APK",
|
|
||||||
"kind": "Directory"
|
|
||||||
},
|
|
||||||
"applicationId": "code.name.monkey.retromusic",
|
|
||||||
"variantName": "release",
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"type": "SINGLE",
|
|
||||||
"filters": [],
|
|
||||||
"properties": [],
|
|
||||||
"versionCode": 10438,
|
|
||||||
"versionName": "3.5.650_0812",
|
|
||||||
"enabled": true,
|
|
||||||
"outputFile": "app-release.apk"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
BIN
app/src/debug/res/font/bold.ttf
Normal file
BIN
app/src/debug/res/font/bold.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/google_sans_bold.ttf
Normal file
BIN
app/src/debug/res/font/google_sans_bold.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/google_sans_medium.ttf
Normal file
BIN
app/src/debug/res/font/google_sans_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/google_sans_regular.ttf
Normal file
BIN
app/src/debug/res/font/google_sans_regular.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/medium.ttf
Normal file
BIN
app/src/debug/res/font/medium.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/regular.ttf
Normal file
BIN
app/src/debug/res/font/regular.ttf
Normal file
Binary file not shown.
12
app/src/debug/res/font/sans.xml
Normal file
12
app/src/debug/res/font/sans.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<font
|
||||||
|
android:font="@font/google_sans_regular"
|
||||||
|
android:fontWeight="400" />
|
||||||
|
<font
|
||||||
|
android:font="@font/google_sans_medium"
|
||||||
|
android:fontWeight="600" />
|
||||||
|
<font
|
||||||
|
android:font="@font/google_sans_bold"
|
||||||
|
android:fontWeight="700" />
|
||||||
|
</font-family>
|
91
app/src/debug/res/values/styles.xml
Normal file
91
app/src/debug/res/values/styles.xml
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="TextViewNormal" parent="">
|
||||||
|
<item name="android:textSize">14sp</item>
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewHeadline4" parent="TextAppearance.MaterialComponents.Headline4">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewHeadline4.Compress" parent="TextAppearance.MaterialComponents.Headline4">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
<item name="android:textSize">32sp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewHeadline5" parent="TextAppearance.MaterialComponents.Headline5">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewCaption" parent="TextAppearance.MaterialComponents.Caption">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewHeadline6" parent="TextAppearance.MaterialComponents.Headline6">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewHeadline3" parent="TextAppearance.MaterialComponents.Headline3">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewHeadline2" parent="TextAppearance.MaterialComponents.Headline2">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewSubtitle1" parent="TextAppearance.MaterialComponents.Subtitle1">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewSubtitle2" parent="TextAppearance.MaterialComponents.Subtitle2">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewBody1" parent="TextAppearance.MaterialComponents.Body1">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewButton" parent="TextAppearance.MaterialComponents.Button">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewBody2" parent="TextAppearance.MaterialComponents.Body2">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextViewOverline" parent="TextAppearance.MaterialComponents.Overline">
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTextAppearance.MaterialAlertDialog.Button" parent="Widget.MaterialComponents.Button.TextButton">
|
||||||
|
<item name="android:textAppearance">@style/TextViewButton</item>
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:padding">0dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTextAppearance.MaterialAlertDialog.Body" parent="MaterialAlertDialog.MaterialComponents.Body.Text">
|
||||||
|
<item name="android:textAppearance">@style/TextViewBody1</item>
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
<item name="android:paddingTop">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTextAppearance.MaterialAlertDialog.Title" parent="MaterialAlertDialog.MaterialComponents.Title.Text">
|
||||||
|
<item name="android:textAppearance">@style/TextViewHeadline6</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
<item name="android:padding">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ToolbarTextAppearanceNormal">
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:textAllCaps">false</item>
|
||||||
|
<item name="android:textAppearance">@style/TextViewHeadline6</item>
|
||||||
|
<item name="fontFamily">@font/sans</item>
|
||||||
|
<item name="android:textSize">20sp</item>
|
||||||
|
<item name="android:letterSpacing">0.0125</item>
|
||||||
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -255,11 +255,9 @@
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.bumptech.glide.integration.okhttp3.OkHttpGlideModule"
|
android:name="com.bumptech.glide.integration.okhttp3.OkHttpGlideModule"
|
||||||
android:value="GlideModule" />
|
android:value="GlideModule" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.android.vending.splits.required"
|
android:name="com.android.vending.splits.required"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
<meta-data
|
|
||||||
android:name="preloaded_fonts"
|
|
||||||
android:resource="@array/preloaded_fonts" />
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 51 KiB |
|
@ -31,7 +31,7 @@ object Constants {
|
||||||
const val APP_TWITTER_LINK = "https://twitter.com/retromusicapp"
|
const val APP_TWITTER_LINK = "https://twitter.com/retromusicapp"
|
||||||
const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
||||||
const val PINTEREST = "https://in.pinterest.com/retromusicapp/"
|
const val PINTEREST = "https://in.pinterest.com/retromusicapp/"
|
||||||
const val BASE_URL = "https://ws.audioscrobbler.com/2.0/"
|
const val AUDIO_SCROBBLER_URL = "https://ws.audioscrobbler.com/2.0/"
|
||||||
|
|
||||||
const val IS_MUSIC =
|
const val IS_MUSIC =
|
||||||
MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
||||||
|
@ -55,9 +55,11 @@ object Constants {
|
||||||
}
|
}
|
||||||
const val EXTRA_GENRE = "extra_genre"
|
const val EXTRA_GENRE = "extra_genre"
|
||||||
const val EXTRA_PLAYLIST = "extra_playlist"
|
const val EXTRA_PLAYLIST = "extra_playlist"
|
||||||
|
const val EXTRA_PLAYLIST_ID = "extra_playlist_id"
|
||||||
const val EXTRA_ALBUM_ID = "extra_album_id"
|
const val EXTRA_ALBUM_ID = "extra_album_id"
|
||||||
const val EXTRA_ARTIST_ID = "extra_artist_id"
|
const val EXTRA_ARTIST_ID = "extra_artist_id"
|
||||||
const val EXTRA_SONG = "extra_songs"
|
const val EXTRA_SONG = "extra_songs"
|
||||||
|
const val EXTRA_PLAYLISTS = "extra_playlists"
|
||||||
const val LIBRARY_CATEGORIES = "library_categories"
|
const val LIBRARY_CATEGORIES = "library_categories"
|
||||||
const val EXTRA_SONG_INFO = "extra_song_info"
|
const val EXTRA_SONG_INFO = "extra_song_info"
|
||||||
const val DESATURATED_COLOR = "desaturated_color"
|
const val DESATURATED_COLOR = "desaturated_color"
|
||||||
|
@ -68,8 +70,8 @@ const val NOW_PLAYING_SCREEN_ID = "now_playing_screen_id"
|
||||||
const val CAROUSEL_EFFECT = "carousel_effect"
|
const val CAROUSEL_EFFECT = "carousel_effect"
|
||||||
const val COLORED_NOTIFICATION = "colored_notification"
|
const val COLORED_NOTIFICATION = "colored_notification"
|
||||||
const val CLASSIC_NOTIFICATION = "classic_notification"
|
const val CLASSIC_NOTIFICATION = "classic_notification"
|
||||||
const val GAPLESS_PLAYBACK = "gapless_playback"
|
const val GAP_LESS_PLAYBACK = "gap_less_playback"
|
||||||
const val ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen"
|
const val ALBUM_ART_ON_LOCK_SCREEN = "album_art_on_lock_screen"
|
||||||
const val BLURRED_ALBUM_ART = "blurred_album_art"
|
const val BLURRED_ALBUM_ART = "blurred_album_art"
|
||||||
const val NEW_BLUR_AMOUNT = "new_blur_amount"
|
const val NEW_BLUR_AMOUNT = "new_blur_amount"
|
||||||
const val TOGGLE_HEADSET = "toggle_headset"
|
const val TOGGLE_HEADSET = "toggle_headset"
|
||||||
|
@ -90,7 +92,6 @@ const val ALBUM_COVER_STYLE = "album_cover_style_id"
|
||||||
const val ALBUM_COVER_TRANSFORM = "album_cover_transform"
|
const val ALBUM_COVER_TRANSFORM = "album_cover_transform"
|
||||||
const val TAB_TEXT_MODE = "tab_text_mode"
|
const val TAB_TEXT_MODE = "tab_text_mode"
|
||||||
const val LANGUAGE_NAME = "language_name"
|
const val LANGUAGE_NAME = "language_name"
|
||||||
const val DIALOG_CORNER = "dialog_corner"
|
|
||||||
const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song"
|
const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song"
|
||||||
const val ALBUM_GRID_STYLE = "album_grid_style_home"
|
const val ALBUM_GRID_STYLE = "album_grid_style_home"
|
||||||
const val ARTIST_GRID_STYLE = "artist_grid_style_home"
|
const val ARTIST_GRID_STYLE = "artist_grid_style_home"
|
||||||
|
|
|
@ -22,4 +22,7 @@ const val TOP_ARTISTS = 0
|
||||||
const val SUGGESTIONS = 5
|
const val SUGGESTIONS = 5
|
||||||
const val FAVOURITES = 4
|
const val FAVOURITES = 4
|
||||||
const val GENRES = 6
|
const val GENRES = 6
|
||||||
const val PLAYLISTS = 7
|
const val PLAYLISTS = 7
|
||||||
|
const val HISTORY_PLAYLIST = 8
|
||||||
|
const val LAST_ADDED_PLAYLIST = 9
|
||||||
|
const val TOP_PLAYED_PLAYLIST = 10
|
|
@ -1,5 +1,12 @@
|
||||||
package code.name.monkey.retromusic
|
package code.name.monkey.retromusic
|
||||||
|
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
import code.name.monkey.retromusic.db.BlackListStoreDao
|
||||||
|
import code.name.monkey.retromusic.db.BlackListStoreEntity
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
|
import code.name.monkey.retromusic.db.RetroDatabase
|
||||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel
|
import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel
|
||||||
import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel
|
import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel
|
||||||
|
@ -7,17 +14,103 @@ import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel
|
||||||
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
|
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
|
||||||
import code.name.monkey.retromusic.fragments.search.SearchViewModel
|
import code.name.monkey.retromusic.fragments.search.SearchViewModel
|
||||||
import code.name.monkey.retromusic.model.Genre
|
import code.name.monkey.retromusic.model.Genre
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.network.*
|
||||||
import code.name.monkey.retromusic.network.networkModule
|
|
||||||
import code.name.monkey.retromusic.repository.*
|
import code.name.monkey.retromusic.repository.*
|
||||||
|
import code.name.monkey.retromusic.util.FilePathUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
import org.koin.dsl.bind
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
val networkModule = module {
|
||||||
|
|
||||||
|
factory {
|
||||||
|
provideDefaultCache()
|
||||||
|
}
|
||||||
|
factory {
|
||||||
|
provideOkHttp(get(), get())
|
||||||
|
}
|
||||||
|
single {
|
||||||
|
provideLastFmRetrofit(get())
|
||||||
|
}
|
||||||
|
single {
|
||||||
|
provideDeezerRest(get())
|
||||||
|
}
|
||||||
|
single {
|
||||||
|
provideLastFmRest(get())
|
||||||
|
}
|
||||||
|
single {
|
||||||
|
provideLyrics(get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val roomModule = module {
|
||||||
|
|
||||||
|
single {
|
||||||
|
Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db")
|
||||||
|
.allowMainThreadQueries()
|
||||||
|
.addCallback(object : RoomDatabase.Callback() {
|
||||||
|
override fun onOpen(db: SupportSQLiteDatabase) {
|
||||||
|
super.onOpen(db)
|
||||||
|
GlobalScope.launch(IO) {
|
||||||
|
FilePathUtil.blacklistFilePaths().map {
|
||||||
|
get<BlackListStoreDao>().insertBlacklistPath(BlackListStoreEntity(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fallbackToDestructiveMigration()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
factory {
|
||||||
|
get<RetroDatabase>().lyricsDao()
|
||||||
|
}
|
||||||
|
|
||||||
|
factory {
|
||||||
|
get<RetroDatabase>().playlistDao()
|
||||||
|
}
|
||||||
|
|
||||||
|
factory {
|
||||||
|
get<RetroDatabase>().blackListStore()
|
||||||
|
}
|
||||||
|
|
||||||
|
factory {
|
||||||
|
get<RetroDatabase>().playCountDao()
|
||||||
|
}
|
||||||
|
|
||||||
|
factory {
|
||||||
|
get<RetroDatabase>().historyDao()
|
||||||
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
RealRoomRepository(get(), get(), get(), get(), get())
|
||||||
|
} bind RoomRepository::class
|
||||||
|
}
|
||||||
|
private val mainModule = module {
|
||||||
|
single {
|
||||||
|
androidContext().contentResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
private val dataModule = module {
|
private val dataModule = module {
|
||||||
single {
|
single {
|
||||||
RealRepository(get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
RealRepository(
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get(),
|
||||||
|
get()
|
||||||
|
)
|
||||||
} bind Repository::class
|
} bind Repository::class
|
||||||
|
|
||||||
single {
|
single {
|
||||||
|
@ -61,10 +154,6 @@ private val dataModule = module {
|
||||||
get()
|
get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
single {
|
|
||||||
androidContext().contentResolver
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val viewModules = module {
|
private val viewModules = module {
|
||||||
|
@ -87,7 +176,7 @@ private val viewModules = module {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (playlist: Playlist) ->
|
viewModel { (playlist: PlaylistWithSongs) ->
|
||||||
PlaylistDetailsViewModel(
|
PlaylistDetailsViewModel(
|
||||||
get(),
|
get(),
|
||||||
playlist
|
playlist
|
||||||
|
@ -106,4 +195,4 @@ private val viewModules = module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val appModules = listOf(dataModule, viewModules, networkModule)
|
val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule)
|
|
@ -218,7 +218,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
|
||||||
.build()
|
.build()
|
||||||
.transform(BlurTransformation.Builder(this).build())
|
.transform(BlurTransformation.Builder(this).build())
|
||||||
.into(object : RetroMusicColoredTarget(image) {
|
.into(object : RetroMusicColoredTarget(image) {
|
||||||
override fun onColorReady(color: MediaNotificationProcessor) {
|
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,30 +3,23 @@ package code.name.monkey.retromusic.activities
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.*
|
import code.name.monkey.retromusic.*
|
||||||
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
||||||
import code.name.monkey.retromusic.extensions.findNavController
|
import code.name.monkey.retromusic.extensions.findNavController
|
||||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playFromUri
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.shuffleMode
|
|
||||||
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
|
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader.getPlaylistSongList
|
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
||||||
import code.name.monkey.retromusic.repository.Repository
|
|
||||||
import code.name.monkey.retromusic.service.MusicService
|
import code.name.monkey.retromusic.service.MusicService
|
||||||
import code.name.monkey.retromusic.util.AppRater.appLaunched
|
import code.name.monkey.retromusic.util.AppRater.appLaunched
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.inject
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
|
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -35,9 +28,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
const val APP_UPDATE_REQUEST_CODE = 9002
|
const val APP_UPDATE_REQUEST_CODE = 9002
|
||||||
}
|
}
|
||||||
|
|
||||||
private val repository by inject<Repository>()
|
|
||||||
private val libraryViewModel by inject<LibraryViewModel>()
|
|
||||||
|
|
||||||
private var blockRequestPermissions = false
|
private var blockRequestPermissions = false
|
||||||
|
|
||||||
override fun createContentView(): View {
|
override fun createContentView(): View {
|
||||||
|
@ -53,7 +43,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
setTaskDescriptionColorAuto()
|
setTaskDescriptionColorAuto()
|
||||||
hideStatusBar()
|
hideStatusBar()
|
||||||
appLaunched(this)
|
appLaunched(this)
|
||||||
addMusicServiceEventListener(libraryViewModel)
|
|
||||||
updateTabs()
|
updateTabs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,61 +88,68 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
|
|
||||||
override fun onServiceConnected() {
|
override fun onServiceConnected() {
|
||||||
super.onServiceConnected()
|
super.onServiceConnected()
|
||||||
handlePlaybackIntent(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handlePlaybackIntent(intent: Intent?) {
|
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val uri = intent.data
|
handlePlaybackIntent(intent)
|
||||||
val mimeType = intent.type
|
}
|
||||||
var handled = false
|
|
||||||
if (intent.action != null && (intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH)
|
private fun handlePlaybackIntent(intent: Intent) {
|
||||||
) {
|
lifecycleScope.launch(IO) {
|
||||||
val songs: List<Song> =
|
val uri: Uri? = intent.data
|
||||||
getSongs(this, intent.extras!!)
|
val mimeType: String? = intent.type
|
||||||
if (shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
|
var handled = false
|
||||||
openAndShuffleQueue(songs, true)
|
if (intent.action != null &&
|
||||||
} else {
|
intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
|
||||||
openQueue(songs, 0, true)
|
) {
|
||||||
}
|
val songs: List<Song> = getSongs(intent.extras!!)
|
||||||
handled = true
|
if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
|
||||||
}
|
MusicPlayerRemote.openAndShuffleQueue(songs, true)
|
||||||
if (uri != null && uri.toString().isNotEmpty()) {
|
} else {
|
||||||
playFromUri(uri)
|
MusicPlayerRemote.openQueue(songs, 0, true)
|
||||||
handled = true
|
}
|
||||||
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
|
|
||||||
val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
|
|
||||||
if (id >= 0) {
|
|
||||||
val position = intent.getIntExtra("position", 0)
|
|
||||||
val songs: List<Song> =
|
|
||||||
ArrayList(getPlaylistSongList(this, id))
|
|
||||||
openQueue(songs, position, true)
|
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
if (uri != null && uri.toString().isNotEmpty()) {
|
||||||
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
MusicPlayerRemote.playFromUri(uri)
|
||||||
if (id >= 0) {
|
handled = true
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
|
||||||
val position = intent.getIntExtra("position", 0)
|
val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
|
||||||
openQueue(repository.albumById(id).songs!!, position, true)
|
if (id >= 0) {
|
||||||
|
val position: Int = intent.getIntExtra("position", 0)
|
||||||
|
val songs: List<Song> =
|
||||||
|
PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
|
||||||
|
MusicPlayerRemote.openQueue(songs, position, true)
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
||||||
|
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
||||||
|
if (id >= 0) {
|
||||||
|
val position: Int = intent.getIntExtra("position", 0)
|
||||||
|
MusicPlayerRemote.openQueue(
|
||||||
|
libraryViewModel.albumById(id).songs!!,
|
||||||
|
position,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
||||||
|
val id: Int = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
||||||
|
if (id >= 0) {
|
||||||
|
val position: Int = intent.getIntExtra("position", 0)
|
||||||
|
MusicPlayerRemote.openQueue(
|
||||||
|
libraryViewModel.artistById(id).songs,
|
||||||
|
position,
|
||||||
|
true
|
||||||
|
)
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
if (handled) {
|
||||||
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
setIntent(Intent())
|
||||||
if (id >= 0) {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val position = intent.getIntExtra("position", 0)
|
|
||||||
openQueue(repository.artistById(id).songs, position, true)
|
|
||||||
handled = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (handled) {
|
|
||||||
setIntent(Intent())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseIdFromIntent(
|
private fun parseIdFromIntent(
|
||||||
|
@ -167,7 +163,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
||||||
try {
|
try {
|
||||||
id = idString.toLong()
|
id = idString.toLong()
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
Log.e(TAG, e.message)
|
println(e.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
val fastScroller = ThemedFastScroller.create(recyclerView)
|
ThemedFastScroller.create(recyclerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForPadding() {
|
private fun checkForPadding() {
|
||||||
|
|
|
@ -108,7 +108,7 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RestorePurchaseAsyncTask internal constructor(purchaseActivity: PurchaseActivity) :
|
private class RestorePurchaseAsyncTask(purchaseActivity: PurchaseActivity) :
|
||||||
AsyncTask<Void, Void, Boolean>() {
|
AsyncTask<Void, Void, Boolean>() {
|
||||||
|
|
||||||
private val buyActivityWeakReference: WeakReference<PurchaseActivity> = WeakReference(
|
private val buyActivityWeakReference: WeakReference<PurchaseActivity> = WeakReference(
|
||||||
|
|
|
@ -110,7 +110,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
|
||||||
}
|
}
|
||||||
if (requestCode == TEZ_REQUEST_CODE) {
|
if (requestCode == TEZ_REQUEST_CODE) {
|
||||||
// Process based on the data in response.
|
// Process based on the data in response.
|
||||||
Log.d("result", data!!.getStringExtra("Status"))
|
//Log.d("result", data!!.getStringExtra("Status"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SkuDetailsLoadAsyncTask internal constructor(supportDevelopmentActivity: SupportDevelopmentActivity) :
|
private class SkuDetailsLoadAsyncTask(supportDevelopmentActivity: SupportDevelopmentActivity) :
|
||||||
AsyncTask<Void, Void, List<SkuDetails>>() {
|
AsyncTask<Void, Void, List<SkuDetails>>() {
|
||||||
|
|
||||||
private val weakReference: WeakReference<SupportDevelopmentActivity> = WeakReference(
|
private val weakReference: WeakReference<SupportDevelopmentActivity> = WeakReference(
|
||||||
|
|
|
@ -160,7 +160,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
||||||
CoroutineScope(Dispatchers.IO).launch() {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val appDir = applicationContext.filesDir
|
val appDir = applicationContext.filesDir
|
||||||
val file = File(appDir, fileName)
|
val file = File(appDir, fileName)
|
||||||
var successful = false
|
var successful = false
|
||||||
|
|
|
@ -4,17 +4,23 @@ import android.Manifest
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.toPlayCount
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.service.MusicService.*
|
import code.name.monkey.retromusic.service.MusicService.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
|
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
|
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
|
||||||
|
private val repository: RealRepository by inject()
|
||||||
private var serviceToken: MusicPlayerRemote.ServiceToken? = null
|
private var serviceToken: MusicPlayerRemote.ServiceToken? = null
|
||||||
private var musicStateReceiver: MusicStateReceiver? = null
|
private var musicStateReceiver: MusicStateReceiver? = null
|
||||||
private var receiverRegistered: Boolean = false
|
private var receiverRegistered: Boolean = false
|
||||||
|
@ -93,6 +99,22 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
|
||||||
for (listener in mMusicServiceEventListeners) {
|
for (listener in mMusicServiceEventListeners) {
|
||||||
listener.onPlayingMetaChanged()
|
listener.onPlayingMetaChanged()
|
||||||
}
|
}
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val entity = repository.songPresentInHistory(MusicPlayerRemote.currentSong)
|
||||||
|
if (entity != null) {
|
||||||
|
repository.updateHistorySong(MusicPlayerRemote.currentSong)
|
||||||
|
} else {
|
||||||
|
repository.addSongToHistory(MusicPlayerRemote.currentSong)
|
||||||
|
}
|
||||||
|
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
|
||||||
|
if (songs.isNotEmpty()) {
|
||||||
|
repository.updateSongInPlayCount(songs.first().apply {
|
||||||
|
playCount += 1
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
repository.insertSongInPlayCount(MusicPlayerRemote.currentSong.toPlayCount())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueueChanged() {
|
override fun onQueueChanged() {
|
||||||
|
|
|
@ -15,7 +15,6 @@ import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.show
|
|
||||||
import code.name.monkey.retromusic.extensions.whichFragment
|
import code.name.monkey.retromusic.extensions.whichFragment
|
||||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
|
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
|
||||||
|
@ -29,12 +28,12 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
companion object {
|
companion object {
|
||||||
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
private val libraryViewModel by viewModel<LibraryViewModel>()
|
protected val libraryViewModel by viewModel<LibraryViewModel>()
|
||||||
private lateinit var behavior: RetroBottomSheetBehavior<FrameLayout>
|
private lateinit var behavior: RetroBottomSheetBehavior<FrameLayout>
|
||||||
private var miniPlayerFragment: MiniPlayerFragment? = null
|
private var miniPlayerFragment: MiniPlayerFragment? = null
|
||||||
private var cps: NowPlayingScreen? = null
|
private var cps: NowPlayingScreen? = null
|
||||||
|
@ -51,8 +50,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
|
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||||
setMiniPlayerAlphaProgress(slideOffset)
|
setMiniPlayerAlphaProgress(slideOffset)
|
||||||
dimBackground.show()
|
|
||||||
dimBackground.alpha = slideOffset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||||
|
@ -62,7 +59,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
}
|
}
|
||||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||||
onPanelCollapsed()
|
onPanelCollapsed()
|
||||||
dimBackground.hide()
|
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|
||||||
|
@ -77,13 +73,9 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
setContentView(createContentView())
|
setContentView(createContentView())
|
||||||
chooseFragmentForTheme()
|
chooseFragmentForTheme()
|
||||||
setupSlidingUpPanel()
|
setupSlidingUpPanel()
|
||||||
addMusicServiceEventListener(libraryViewModel)
|
|
||||||
|
|
||||||
setupBottomSheet()
|
setupBottomSheet()
|
||||||
|
|
||||||
val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
|
|
||||||
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
|
|
||||||
|
|
||||||
libraryViewModel.paletteColorLiveData.observe(this, Observer {
|
libraryViewModel.paletteColorLiveData.observe(this, Observer {
|
||||||
this.paletteColor = it
|
this.paletteColor = it
|
||||||
onPaletteColorChanged()
|
onPaletteColorChanged()
|
||||||
|
|
|
@ -295,7 +295,7 @@ open class BugReportActivity : AbsThemeActivity() {
|
||||||
.setTitle(R.string.bug_report_failed)
|
.setTitle(R.string.bug_report_failed)
|
||||||
.setMessage(R.string.bug_report_failed_unknown)
|
.setMessage(R.string.bug_report_failed_unknown)
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
|
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
|
||||||
.setNegativeButton(android.R.string.cancel) { _, _ -> { tryToFinishActivity() } }
|
.setNegativeButton(android.R.string.cancel) { _, _ -> tryToFinishActivity() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class DeviceInfo {
|
||||||
return "Device info:\n"
|
return "Device info:\n"
|
||||||
+ "---\n"
|
+ "---\n"
|
||||||
+ "<table>\n"
|
+ "<table>\n"
|
||||||
+ "<tr><td>App version</td><td>" + versionName + "</td></tr>\n"
|
+ "<tr><td><b>App version</b></td><td>" + versionName + "</td></tr>\n"
|
||||||
+ "<tr><td>App version code</td><td>" + versionCode + "</td></tr>\n"
|
+ "<tr><td>App version code</td><td>" + versionCode + "</td></tr>\n"
|
||||||
+ "<tr><td>Android build version</td><td>" + buildVersion + "</td></tr>\n"
|
+ "<tr><td>Android build version</td><td>" + buildVersion + "</td></tr>\n"
|
||||||
+ "<tr><td>Android release version</td><td>" + releaseVersion + "</td></tr>\n"
|
+ "<tr><td>Android release version</td><td>" + releaseVersion + "</td></tr>\n"
|
||||||
|
|
|
@ -14,7 +14,6 @@ import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.OvershootInterpolator
|
import android.view.animation.OvershootInterpolator
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
|
@ -182,11 +181,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
saveFab = findViewById(R.id.saveTags)
|
saveFab = findViewById(R.id.saveTags)
|
||||||
getIntentExtras()
|
getIntentExtras()
|
||||||
|
|
||||||
lifecycleScope.launchWhenCreated {
|
songPaths = getSongPaths()
|
||||||
songPaths = getSongPaths()
|
if (songPaths!!.isEmpty()) {
|
||||||
if (songPaths!!.isEmpty()) {
|
finish()
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setUpViews()
|
setUpViews()
|
||||||
}
|
}
|
||||||
|
@ -258,7 +255,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract suspend fun getSongPaths(): List<String>
|
protected abstract fun getSongPaths(): List<String>
|
||||||
|
|
||||||
protected fun searchWebFor(vararg keys: String) {
|
protected fun searchWebFor(vararg keys: String) {
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
|
|
|
@ -44,9 +44,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
window.enterTransition = slide
|
window.enterTransition = slide
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadImageFromFile(selectedFileUri: Uri?) {
|
override fun loadImageFromFile(selectedFile: Uri?) {
|
||||||
|
|
||||||
Glide.with(this@AlbumTagEditorActivity).load(selectedFileUri).asBitmap()
|
Glide.with(this@AlbumTagEditorActivity).load(selectedFile).asBitmap()
|
||||||
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
|
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
||||||
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
|
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
|
||||||
|
@ -167,7 +167,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSongPaths(): List<String> {
|
override fun getSongPaths(): List<String> {
|
||||||
val songs = repository.albumById(id).songs
|
val songs = repository.albumById(id).songs
|
||||||
val paths = ArrayList<String>(songs!!.size)
|
val paths = ArrayList<String>(songs!!.size)
|
||||||
for (song in songs) {
|
for (song in songs) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
writeValuesToFiles(fieldKeyValueMap, null)
|
writeValuesToFiles(fieldKeyValueMap, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSongPaths(): List<String> {
|
override fun getSongPaths(): List<String> {
|
||||||
val paths = ArrayList<String>(1)
|
val paths = ArrayList<String>(1)
|
||||||
paths.add(songRepository.song(id).data)
|
paths.add(songRepository.song(id).data)
|
||||||
return paths
|
return paths
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package code.name.monkey.retromusic.adapter
|
package code.name.monkey.retromusic.adapter
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -22,14 +23,14 @@ class GenreAdapter(
|
||||||
var dataSet: List<Genre>,
|
var dataSet: List<Genre>,
|
||||||
private val mItemLayoutRes: Int
|
private val mItemLayoutRes: Int
|
||||||
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
||||||
|
val colors = listOf<Int>(Color.RED, Color.BLUE)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
|
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val genre = dataSet[position]
|
val genre = dataSet[position]
|
||||||
|
|
||||||
holder.title?.text = genre.name
|
holder.title?.text = genre.name
|
||||||
holder.text?.text = String.format(
|
holder.text?.text = String.format(
|
||||||
Locale.getDefault(),
|
Locale.getDefault(),
|
||||||
|
|
|
@ -40,8 +40,8 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val layout = LayoutInflater.from(activity)
|
val layout =
|
||||||
.inflate(R.layout.section_recycler_view, parent, false)
|
LayoutInflater.from(activity).inflate(R.layout.section_recycler_view, parent, false)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
|
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
|
||||||
GENRES -> GenreViewHolder(layout)
|
GENRES -> GenreViewHolder(layout)
|
||||||
|
@ -64,7 +64,7 @@ class HomeAdapter(
|
||||||
when (getItemViewType(position)) {
|
when (getItemViewType(position)) {
|
||||||
RECENT_ALBUMS -> {
|
RECENT_ALBUMS -> {
|
||||||
val viewHolder = holder as AlbumViewHolder
|
val viewHolder = holder as AlbumViewHolder
|
||||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.recent_albums)
|
viewHolder.bindView(home)
|
||||||
viewHolder.clickableArea.setOnClickListener {
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
activity.findNavController(R.id.fragment_container).navigate(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.detailListFragment,
|
R.id.detailListFragment,
|
||||||
|
@ -74,7 +74,7 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
TOP_ALBUMS -> {
|
TOP_ALBUMS -> {
|
||||||
val viewHolder = holder as AlbumViewHolder
|
val viewHolder = holder as AlbumViewHolder
|
||||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.top_albums)
|
viewHolder.bindView(home)
|
||||||
viewHolder.clickableArea.setOnClickListener {
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
activity.findNavController(R.id.fragment_container).navigate(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.detailListFragment,
|
R.id.detailListFragment,
|
||||||
|
@ -84,7 +84,7 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
RECENT_ARTISTS -> {
|
RECENT_ARTISTS -> {
|
||||||
val viewHolder = holder as ArtistViewHolder
|
val viewHolder = holder as ArtistViewHolder
|
||||||
viewHolder.bindView(home.arrayList, R.string.recent_artists)
|
viewHolder.bindView(home)
|
||||||
viewHolder.clickableArea.setOnClickListener {
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
activity.findNavController(R.id.fragment_container).navigate(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.detailListFragment,
|
R.id.detailListFragment,
|
||||||
|
@ -94,7 +94,7 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
TOP_ARTISTS -> {
|
TOP_ARTISTS -> {
|
||||||
val viewHolder = holder as ArtistViewHolder
|
val viewHolder = holder as ArtistViewHolder
|
||||||
viewHolder.bindView(home.arrayList, R.string.top_artists)
|
viewHolder.bindView(home)
|
||||||
viewHolder.clickableArea.setOnClickListener {
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
activity.findNavController(R.id.fragment_container).navigate(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.detailListFragment,
|
R.id.detailListFragment,
|
||||||
|
@ -104,15 +104,21 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
SUGGESTIONS -> {
|
SUGGESTIONS -> {
|
||||||
val viewHolder = holder as SuggestionsViewHolder
|
val viewHolder = holder as SuggestionsViewHolder
|
||||||
viewHolder.bindView(home.arrayList)
|
viewHolder.bindView(home)
|
||||||
}
|
}
|
||||||
FAVOURITES -> {
|
FAVOURITES -> {
|
||||||
val viewHolder = holder as PlaylistViewHolder
|
val viewHolder = holder as PlaylistViewHolder
|
||||||
viewHolder.bindView(home.arrayList, R.string.favorites)
|
viewHolder.bindView(home)
|
||||||
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.detailListFragment,
|
||||||
|
bundleOf("type" to FAVOURITES)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GENRES -> {
|
GENRES -> {
|
||||||
val viewHolder = holder as GenreViewHolder
|
val viewHolder = holder as GenreViewHolder
|
||||||
viewHolder.bind(home.arrayList, R.string.genres)
|
viewHolder.bind(home)
|
||||||
}
|
}
|
||||||
PLAYLISTS -> {
|
PLAYLISTS -> {
|
||||||
|
|
||||||
|
@ -130,22 +136,22 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
|
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||||
fun bindView(albums: List<Album>, titleRes: Int) {
|
fun bindView(home: Home) {
|
||||||
title.text = activity.getString(titleRes)
|
title.setText(home.titleRes)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
adapter = albumAdapter(albums)
|
adapter = albumAdapter(home.arrayList as List<Album>)
|
||||||
layoutManager = gridLayoutManager()
|
layoutManager = gridLayoutManager()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||||
fun bindView(artists: List<Any>, titleRes: Int) {
|
fun bindView(home: Home) {
|
||||||
|
title.setText(home.titleRes)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
layoutManager = linearLayoutManager()
|
layoutManager = linearLayoutManager()
|
||||||
adapter = artistsAdapter(artists as List<Artist>)
|
adapter = artistsAdapter(home.arrayList as List<Artist>)
|
||||||
}
|
}
|
||||||
title.text = activity.getString(titleRes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +167,7 @@ class HomeAdapter(
|
||||||
R.id.image8
|
R.id.image8
|
||||||
)
|
)
|
||||||
|
|
||||||
fun bindView(songs: List<Any>) {
|
fun bindView(home: Home) {
|
||||||
songs as List<Song>
|
|
||||||
val color = ThemeStore.accentColor(activity)
|
val color = ThemeStore.accentColor(activity)
|
||||||
itemView.findViewById<TextView>(R.id.message).setTextColor(color)
|
itemView.findViewById<TextView>(R.id.message).setTextColor(color)
|
||||||
itemView.findViewById<MaterialCardView>(R.id.card6).apply {
|
itemView.findViewById<MaterialCardView>(R.id.card6).apply {
|
||||||
|
@ -170,9 +175,9 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
images.forEachIndexed { index, id ->
|
images.forEachIndexed { index, id ->
|
||||||
itemView.findViewById<View>(id).setOnClickListener {
|
itemView.findViewById<View>(id).setOnClickListener {
|
||||||
MusicPlayerRemote.playNext(songs[index])
|
MusicPlayerRemote.playNext(home.arrayList[index] as Song)
|
||||||
}
|
}
|
||||||
SongGlideRequest.Builder.from(Glide.with(activity), songs[index])
|
SongGlideRequest.Builder.from(Glide.with(activity), home.arrayList[index] as Song)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.build()
|
.build()
|
||||||
.into(itemView.findViewById(id))
|
.into(itemView.findViewById(id))
|
||||||
|
@ -182,35 +187,37 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||||
fun bindView(songs: List<Any>, titleRes: Int) {
|
fun bindView(home: Home) {
|
||||||
arrow.hide()
|
title.setText(home.titleRes)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
val songAdapter = SongAdapter(
|
val songAdapter = SongAdapter(
|
||||||
activity,
|
activity,
|
||||||
songs as MutableList<Song>,
|
home.arrayList as MutableList<Song>,
|
||||||
R.layout.item_album_card, null
|
R.layout.item_album_card, null
|
||||||
)
|
)
|
||||||
layoutManager = linearLayoutManager()
|
layoutManager = linearLayoutManager()
|
||||||
adapter = songAdapter
|
adapter = songAdapter
|
||||||
}
|
}
|
||||||
title.text = activity.getString(titleRes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class GenreViewHolder(itemView: View) : AbsHomeViewItem(itemView) {
|
private inner class GenreViewHolder(itemView: View) : AbsHomeViewItem(itemView) {
|
||||||
fun bind(genres: List<Any>, titleRes: Int) {
|
fun bind(home: Home) {
|
||||||
arrow.hide()
|
arrow.hide()
|
||||||
title.text = activity.getString(titleRes)
|
title.setText(home.titleRes)
|
||||||
|
val genreAdapter = GenreAdapter(
|
||||||
|
activity,
|
||||||
|
home.arrayList as List<Genre>,
|
||||||
|
R.layout.item_grid_genre
|
||||||
|
)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
|
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
|
||||||
val genreAdapter =
|
|
||||||
GenreAdapter(activity, genres as List<Genre>, R.layout.item_grid_genre)
|
|
||||||
adapter = genreAdapter
|
adapter = genreAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
open class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
|
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
|
||||||
val title: AppCompatTextView = itemView.findViewById(R.id.title)
|
val title: AppCompatTextView = itemView.findViewById(R.id.title)
|
||||||
val arrow: ImageView = itemView.findViewById(R.id.arrow)
|
val arrow: ImageView = itemView.findViewById(R.id.arrow)
|
||||||
|
|
|
@ -60,7 +60,7 @@ class SearchAdapter(
|
||||||
holder.title?.text = album.title
|
holder.title?.text = album.title
|
||||||
holder.text?.text = album.artistName
|
holder.text?.text = album.artistName
|
||||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||||
.checkIgnoreMediaStore(activity).build().into(holder.image)
|
.checkIgnoreMediaStore().build().into(holder.image)
|
||||||
}
|
}
|
||||||
ARTIST -> {
|
ARTIST -> {
|
||||||
val artist = dataSet.get(position) as Artist
|
val artist = dataSet.get(position) as Artist
|
||||||
|
|
|
@ -101,11 +101,10 @@ open class AlbumAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||||
.checkIgnoreMediaStore(activity)
|
.checkIgnoreMediaStore()
|
||||||
.generatePalette(activity)
|
.generatePalette(activity)
|
||||||
.build()
|
.build()
|
||||||
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
||||||
|
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||||
setColors(colors, holder)
|
setColors(colors, holder)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.dialogs.LyricsDialog
|
||||||
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
|
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
|
@ -90,6 +91,7 @@ class AlbumCoverPagerAdapter(
|
||||||
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
||||||
albumCover = view.findViewById(R.id.player_image)
|
albumCover = view.findViewById(R.id.player_image)
|
||||||
albumCover.setOnClickListener {
|
albumCover.setOnClickListener {
|
||||||
|
LyricsDialog().show(childFragmentManager, "LyricsDialog")
|
||||||
showLyricsDialog()
|
showLyricsDialog()
|
||||||
}
|
}
|
||||||
return view
|
return view
|
||||||
|
@ -97,7 +99,7 @@ class AlbumCoverPagerAdapter(
|
||||||
|
|
||||||
private fun showLyricsDialog() {
|
private fun showLyricsDialog() {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val data = MusicUtil.getLyrics(song)
|
val data: String = MusicUtil.getLyrics(song) ?: "No lyrics found"
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
MaterialAlertDialogBuilder(
|
MaterialAlertDialogBuilder(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
|
|
|
@ -3,7 +3,6 @@ package code.name.monkey.retromusic.adapter.album
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
|
||||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||||
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
|
@ -30,14 +29,14 @@ class HorizontalAlbumAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
|
override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
|
||||||
holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
|
//holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
|
||||||
holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
|
//holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadAlbumCover(album: Album, holder: ViewHolder) {
|
override fun loadAlbumCover(album: Album, holder: ViewHolder) {
|
||||||
if (holder.image == null) return
|
if (holder.image == null) return
|
||||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||||
.checkIgnoreMediaStore(activity)
|
.checkIgnoreMediaStore()
|
||||||
.generatePalette(activity)
|
.generatePalette(activity)
|
||||||
.build()
|
.build()
|
||||||
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package code.name.monkey.retromusic.adapter.playlist
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
|
||||||
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
|
||||||
|
class LegacyPlaylistAdapter(
|
||||||
|
private val activity: FragmentActivity,
|
||||||
|
private var list: List<Playlist>,
|
||||||
|
private val layoutRes: Int,
|
||||||
|
private val playlistClickListener: PlaylistClickListener
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<LegacyPlaylistAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
fun swapData(list: List<Playlist>) {
|
||||||
|
this.list = list
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView)
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): ViewHolder {
|
||||||
|
return ViewHolder(
|
||||||
|
LayoutInflater.from(parent.context).inflate(layoutRes, parent, false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val playlist: Playlist = list[position]
|
||||||
|
holder.title?.text = playlist.name
|
||||||
|
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, playlist.getSongs())
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
playlistClickListener.onPlaylistClick(playlist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return list.size
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlaylistClickListener {
|
||||||
|
fun onPlaylistClick(playlist: Playlist)
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,51 +13,50 @@ import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
|
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
|
||||||
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
|
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
|
import code.name.monkey.retromusic.db.toSongs
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
|
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
|
||||||
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
|
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
|
||||||
import code.name.monkey.retromusic.interfaces.CabHolder
|
import code.name.monkey.retromusic.interfaces.CabHolder
|
||||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
|
||||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
||||||
import code.name.monkey.retromusic.util.AutoGeneratedPlaylistBitmap
|
import code.name.monkey.retromusic.util.AutoGeneratedPlaylistBitmap
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class PlaylistAdapter(
|
class PlaylistAdapter(
|
||||||
private val activity: FragmentActivity,
|
private val activity: FragmentActivity,
|
||||||
var dataSet: List<Playlist>,
|
var dataSet: List<PlaylistWithSongs>,
|
||||||
private var itemLayoutRes: Int,
|
private var itemLayoutRes: Int,
|
||||||
cabHolder: CabHolder?
|
cabHolder: CabHolder?
|
||||||
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(
|
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>(
|
||||||
activity,
|
activity,
|
||||||
cabHolder,
|
cabHolder,
|
||||||
R.menu.menu_playlists_selection
|
R.menu.menu_playlists_selection
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setHasStableIds(true)
|
setHasStableIds(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun swapDataSet(dataSet: List<Playlist>) {
|
fun swapDataSet(dataSet: List<PlaylistWithSongs>) {
|
||||||
this.dataSet = dataSet
|
this.dataSet = dataSet
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
override fun getItemId(position: Int): Long {
|
||||||
return dataSet[position].id.toLong()
|
return dataSet[position].playlistEntity.playListId.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -69,20 +68,20 @@ class PlaylistAdapter(
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlaylistTitle(playlist: Playlist): String {
|
private fun getPlaylistTitle(playlist: PlaylistEntity): String {
|
||||||
return if (TextUtils.isEmpty(playlist.name)) "-" else playlist.name
|
return if (TextUtils.isEmpty(playlist.playlistName)) "-" else playlist.playlistName
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlaylistText(playlist: Playlist): String {
|
private fun getPlaylistText(playlist: PlaylistWithSongs): String {
|
||||||
return MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
|
return MusicUtil.getPlaylistInfoString(activity, playlist.songs.toSongs())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val playlist = dataSet[position]
|
val playlist = dataSet[position]
|
||||||
holder.itemView.isActivated = isChecked(playlist)
|
holder.itemView.isActivated = isChecked(playlist)
|
||||||
holder.title?.text = getPlaylistTitle(playlist)
|
holder.title?.text = getPlaylistTitle(playlist.playlistEntity)
|
||||||
holder.text?.text = getPlaylistText(playlist)
|
holder.text?.text = getPlaylistText(playlist)
|
||||||
holder.image?.setImageDrawable(getIconRes(playlist))
|
holder.image?.setImageDrawable(getIconRes())
|
||||||
val isChecked = isChecked(playlist)
|
val isChecked = isChecked(playlist)
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
holder.menu?.hide()
|
holder.menu?.hide()
|
||||||
|
@ -92,37 +91,25 @@ class PlaylistAdapter(
|
||||||
//PlaylistBitmapLoader(this, holder, playlist).execute()
|
//PlaylistBitmapLoader(this, holder, playlist).execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIconRes(playlist: Playlist): Drawable {
|
private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
|
||||||
return if (MusicUtil.isFavoritePlaylist(activity, playlist))
|
activity,
|
||||||
TintHelper.createTintedDrawable(
|
R.drawable.ic_playlist_play,
|
||||||
activity,
|
ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
|
||||||
R.drawable.ic_favorite,
|
)
|
||||||
ThemeStore.accentColor(activity)
|
|
||||||
)
|
|
||||||
else TintHelper.createTintedDrawable(
|
|
||||||
activity,
|
|
||||||
R.drawable.ic_playlist_play,
|
|
||||||
ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
|
||||||
return if (dataSet[position] is AbsSmartPlaylist) SMART_PLAYLIST else DEFAULT_PLAYLIST
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return dataSet.size
|
return dataSet.size
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getIdentifier(position: Int): Playlist? {
|
override fun getIdentifier(position: Int): PlaylistWithSongs? {
|
||||||
return dataSet[position]
|
return dataSet[position]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getName(playlist: Playlist): String {
|
override fun getName(playlist: PlaylistWithSongs): String {
|
||||||
return playlist.name
|
return playlist.playlistEntity.playlistName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Playlist>) {
|
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<PlaylistWithSongs>) {
|
||||||
when (menuItem.itemId) {
|
when (menuItem.itemId) {
|
||||||
else -> SongsMenuHelper.handleMenuClick(
|
else -> SongsMenuHelper.handleMenuClick(
|
||||||
activity,
|
activity,
|
||||||
|
@ -132,37 +119,26 @@ class PlaylistAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSongList(playlists: List<Playlist>): List<Song> {
|
private fun getSongList(playlists: List<PlaylistWithSongs>): List<Song> {
|
||||||
val songs = ArrayList<Song>()
|
val songs = mutableListOf<Song>()
|
||||||
for (playlist in playlists) {
|
playlists.forEach {
|
||||||
if (playlist is AbsCustomPlaylist) {
|
songs.addAll(it.songs.toSongs())
|
||||||
songs.addAll(playlist.songs())
|
|
||||||
} else {
|
|
||||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSongs(playlist: Playlist): List<Song> {
|
private fun getSongs(playlist: PlaylistWithSongs): List<SongEntity> =
|
||||||
val songs = ArrayList<Song>()
|
mutableListOf<SongEntity>().apply {
|
||||||
if (playlist is AbsSmartPlaylist) {
|
addAll(playlist.songs)
|
||||||
songs.addAll(playlist.songs())
|
|
||||||
} else {
|
|
||||||
songs.addAll(playlist.getSongs())
|
|
||||||
}
|
}
|
||||||
return songs
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||||
init {
|
init {
|
||||||
|
|
||||||
image?.apply {
|
image?.apply {
|
||||||
val iconPadding =
|
val iconPadding =
|
||||||
activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
|
activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
|
||||||
setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
|
setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
|
||||||
}
|
}
|
||||||
|
|
||||||
menu?.setOnClickListener { view ->
|
menu?.setOnClickListener { view ->
|
||||||
val popupMenu = PopupMenu(activity, view)
|
val popupMenu = PopupMenu(activity, view)
|
||||||
popupMenu.inflate(R.menu.menu_item_playlist)
|
popupMenu.inflate(R.menu.menu_item_playlist)
|
||||||
|
@ -221,7 +197,5 @@ class PlaylistAdapter(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TAG: String = PlaylistAdapter::class.java.simpleName
|
val TAG: String = PlaylistAdapter::class.java.simpleName
|
||||||
private const val SMART_PLAYLIST = 0
|
|
||||||
private const val DEFAULT_PLAYLIST = 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@ import android.view.View
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.R.menu
|
import code.name.monkey.retromusic.R.menu
|
||||||
import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.toSongs
|
||||||
|
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
|
||||||
import code.name.monkey.retromusic.interfaces.CabHolder
|
import code.name.monkey.retromusic.interfaces.CabHolder
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong
|
import code.name.monkey.retromusic.model.PlaylistSong
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
@ -16,6 +18,7 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
|
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
|
||||||
|
|
||||||
class OrderablePlaylistSongAdapter(
|
class OrderablePlaylistSongAdapter(
|
||||||
|
private val playlist: PlaylistEntity,
|
||||||
activity: FragmentActivity,
|
activity: FragmentActivity,
|
||||||
dataSet: ArrayList<Song>,
|
dataSet: ArrayList<Song>,
|
||||||
itemLayoutRes: Int,
|
itemLayoutRes: Int,
|
||||||
|
@ -54,8 +57,8 @@ class OrderablePlaylistSongAdapter(
|
||||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
||||||
when (menuItem.itemId) {
|
when (menuItem.itemId) {
|
||||||
R.id.action_remove_from_playlist -> {
|
R.id.action_remove_from_playlist -> {
|
||||||
RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>)
|
RemoveSongFromPlaylistDialog.create(selection.toSongs(playlist.playListId))
|
||||||
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +121,7 @@ class OrderablePlaylistSongAdapter(
|
||||||
override fun onSongMenuItemClick(item: MenuItem): Boolean {
|
override fun onSongMenuItemClick(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_remove_from_playlist -> {
|
R.id.action_remove_from_playlist -> {
|
||||||
RemoveFromPlaylistDialog.create(song as PlaylistSong)
|
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId))
|
||||||
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstant
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction
|
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault
|
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
|
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.annotation.SwipeableItemResults
|
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
|
|
||||||
class PlayingQueueAdapter(
|
class PlayingQueueAdapter(
|
||||||
|
@ -153,8 +152,8 @@ class PlayingQueueAdapter(
|
||||||
mDragStateFlags = flags
|
mDragStateFlags = flags
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSwipeableContainerView(): View? {
|
override fun getSwipeableContainerView(): View {
|
||||||
return dummyContainer
|
return dummyContainer!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,18 +164,15 @@ class PlayingQueueAdapter(
|
||||||
private const val UP_NEXT = 2
|
private const val UP_NEXT = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSwipeItem(
|
override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int): SwipeResultAction? {
|
||||||
holder: ViewHolder?,
|
return if (result == SwipeableItemConstants.RESULT_CANCELED) {
|
||||||
position: Int, @SwipeableItemResults result: Int
|
|
||||||
): SwipeResultAction {
|
|
||||||
return if (result === SwipeableItemConstants.RESULT_CANCELED) {
|
|
||||||
SwipeResultActionDefault()
|
SwipeResultActionDefault()
|
||||||
} else {
|
} else {
|
||||||
SwipedResultActionRemoveItem(this, position, activity)
|
SwipedResultActionRemoveItem(this, position, activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetSwipeReactionType(holder: ViewHolder?, position: Int, x: Int, y: Int): Int {
|
override fun onGetSwipeReactionType(holder: ViewHolder, position: Int, x: Int, y: Int): Int {
|
||||||
return if (onCheckCanStartDrag(holder!!, position, x, y)) {
|
return if (onCheckCanStartDrag(holder!!, position, x, y)) {
|
||||||
SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H
|
SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,10 +180,10 @@ class PlayingQueueAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSwipeItemStarted(p0: ViewHolder?, p1: Int) {
|
override fun onSwipeItemStarted(holder: ViewHolder, p1: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSetSwipeBackground(holder: ViewHolder?, position: Int, result: Int) {
|
override fun onSetSwipeBackground(holder: ViewHolder, position: Int, result: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SwipedResultActionRemoveItem(
|
internal class SwipedResultActionRemoveItem(
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface BlackListStoreDao {
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
||||||
|
|
||||||
|
@Query("DELETE FROM BlackListStoreEntity")
|
||||||
|
suspend fun clearBlacklist()
|
||||||
|
|
||||||
|
@Query("SELECT * FROM BlackListStoreEntity")
|
||||||
|
fun blackListPaths(): List<BlackListStoreEntity>
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class BlackListStoreEntity(
|
||||||
|
@PrimaryKey
|
||||||
|
val path: String
|
||||||
|
)
|
|
@ -0,0 +1,26 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.room.*
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface HistoryDao {
|
||||||
|
companion object {
|
||||||
|
private const val HISTORY_LIMIT = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
||||||
|
suspend fun isSongPresentInHistory(songId: Int): HistoryEntity?
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun updateHistorySong(historyEntity: HistoryEntity)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
|
||||||
|
fun historySongs(): List<HistoryEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
|
||||||
|
fun observableHistorySongs(): LiveData<List<HistoryEntity>>
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class HistoryEntity(
|
||||||
|
@PrimaryKey
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
@ColumnInfo(name = "track_number")
|
||||||
|
val trackNumber: Int,
|
||||||
|
val year: Int,
|
||||||
|
val duration: Long,
|
||||||
|
val data: String,
|
||||||
|
@ColumnInfo(name = "date_modified")
|
||||||
|
val dateModified: Long,
|
||||||
|
@ColumnInfo(name = "album_id")
|
||||||
|
val albumId: Int,
|
||||||
|
@ColumnInfo(name = "album_name")
|
||||||
|
val albumName: String,
|
||||||
|
@ColumnInfo(name = "artist_id")
|
||||||
|
val artistId: Int,
|
||||||
|
@ColumnInfo(name = "artist_name")
|
||||||
|
val artistName: String,
|
||||||
|
val composer: String?,
|
||||||
|
@ColumnInfo(name = "album_artist")
|
||||||
|
val albumArtist: String?,
|
||||||
|
@ColumnInfo(name = "time_played")
|
||||||
|
val timePlayed: Long
|
||||||
|
)
|
|
@ -0,0 +1,18 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface LyricsDao {
|
||||||
|
@Query("SELECT * FROM LyricsEntity WHERE songId =:songId LIMIT 1")
|
||||||
|
fun lyricsWithSongId(songId: Int): LyricsEntity?
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertLyrics(lyricsEntity: LyricsEntity)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun deleteLyrics(lyricsEntity: LyricsEntity)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
fun updateLyrics(lyricsEntity: LyricsEntity)
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class LyricsEntity(
|
||||||
|
@PrimaryKey val songId: Int,
|
||||||
|
val lyrics: String
|
||||||
|
)
|
|
@ -0,0 +1,27 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface PlayCountDao {
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
|
||||||
|
fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
|
||||||
|
fun playCountSongs(): List<PlayCountEntity>
|
||||||
|
|
||||||
|
@Query("DELETE FROM SongEntity WHERE id =:songId")
|
||||||
|
fun deleteSong(songId: Int)
|
||||||
|
|
||||||
|
@Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
|
||||||
|
fun updateQuantity(id: Int)
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class PlayCountEntity(
|
||||||
|
@PrimaryKey
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
@ColumnInfo(name = "track_number")
|
||||||
|
val trackNumber: Int,
|
||||||
|
val year: Int,
|
||||||
|
val duration: Long,
|
||||||
|
val data: String,
|
||||||
|
@ColumnInfo(name = "date_modified")
|
||||||
|
val dateModified: Long,
|
||||||
|
@ColumnInfo(name = "album_id")
|
||||||
|
val albumId: Int,
|
||||||
|
@ColumnInfo(name = "album_name")
|
||||||
|
val albumName: String,
|
||||||
|
@ColumnInfo(name = "artist_id")
|
||||||
|
val artistId: Int,
|
||||||
|
@ColumnInfo(name = "artist_name")
|
||||||
|
val artistName: String,
|
||||||
|
val composer: String?,
|
||||||
|
@ColumnInfo(name = "album_artist")
|
||||||
|
val albumArtist: String?,
|
||||||
|
@ColumnInfo(name = "time_played")
|
||||||
|
val timePlayed: Long,
|
||||||
|
@ColumnInfo(name = "play_count")
|
||||||
|
var playCount: Int
|
||||||
|
)
|
|
@ -0,0 +1,56 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.room.*
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface PlaylistDao {
|
||||||
|
@Insert
|
||||||
|
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||||
|
|
||||||
|
@Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId")
|
||||||
|
suspend fun renamePlaylist(playlistId: Int, name: String)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
|
||||||
|
fun isPlaylistExists(name: String): List<PlaylistEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM PlaylistEntity")
|
||||||
|
suspend fun playlists(): List<PlaylistEntity>
|
||||||
|
|
||||||
|
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||||
|
suspend fun deletePlaylistSongs(playlistId: Int)
|
||||||
|
|
||||||
|
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||||
|
suspend fun deleteSongFromPlaylist(playlistId: Int, songId: Int)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM PlaylistEntity")
|
||||||
|
suspend fun playlistsWithSongs(): List<PlaylistWithSongs>
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||||
|
suspend fun isSongExistsInPlaylist(playlistId: Int, songId: Int): List<SongEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||||
|
fun songsFromPlaylist(playlistId: Int): LiveData<List<SongEntity>>
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun deletePlaylists(playlistEntities: List<PlaylistEntity>)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun deletePlaylistSongs(songs: List<SongEntity>)
|
||||||
|
|
||||||
|
|
||||||
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||||
|
fun favoritesSongsLiveData(playlistId: Int): LiveData<List<SongEntity>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||||
|
fun favoritesSongs(playlistId: Int): List<SongEntity>
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Parcelize
|
||||||
|
class PlaylistEntity(
|
||||||
|
@ColumnInfo(name = "playlist_name")
|
||||||
|
val playlistName: String
|
||||||
|
) : Parcelable {
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
@ColumnInfo(name = "playlist_id")
|
||||||
|
var playListId: Int = 0
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class PlaylistWithSongs(
|
||||||
|
@Embedded val playlistEntity: PlaylistEntity,
|
||||||
|
@Relation(
|
||||||
|
parentColumn = "playlist_id",
|
||||||
|
entityColumn = "playlist_creator_id"
|
||||||
|
)
|
||||||
|
val songs: List<SongEntity>
|
||||||
|
) : Parcelable
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
|
||||||
|
@Database(
|
||||||
|
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class, LyricsEntity::class],
|
||||||
|
version = 22,
|
||||||
|
exportSchema = false
|
||||||
|
)
|
||||||
|
abstract class RetroDatabase : RoomDatabase() {
|
||||||
|
abstract fun playlistDao(): PlaylistDao
|
||||||
|
abstract fun blackListStore(): BlackListStoreDao
|
||||||
|
abstract fun playCountDao(): PlayCountDao
|
||||||
|
abstract fun historyDao(): HistoryDao
|
||||||
|
abstract fun lyricsDao(): LyricsDao
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
@Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)])
|
||||||
|
class SongEntity(
|
||||||
|
@ColumnInfo(name = "playlist_creator_id")
|
||||||
|
val playlistCreatorId: Int,
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
@ColumnInfo(name = "track_number")
|
||||||
|
val trackNumber: Int,
|
||||||
|
val year: Int,
|
||||||
|
val duration: Long,
|
||||||
|
val data: String,
|
||||||
|
@ColumnInfo(name = "date_modified")
|
||||||
|
val dateModified: Long,
|
||||||
|
@ColumnInfo(name = "album_id")
|
||||||
|
val albumId: Int,
|
||||||
|
@ColumnInfo(name = "album_name")
|
||||||
|
val albumName: String,
|
||||||
|
@ColumnInfo(name = "artist_id")
|
||||||
|
val artistId: Int,
|
||||||
|
@ColumnInfo(name = "artist_name")
|
||||||
|
val artistName: String,
|
||||||
|
val composer: String?,
|
||||||
|
@ColumnInfo(name = "album_artist")
|
||||||
|
val albumArtist: String?
|
||||||
|
) : Parcelable {
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
@ColumnInfo(name = "song_key")
|
||||||
|
var songPrimaryKey: Long = 0
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package code.name.monkey.retromusic.db
|
||||||
|
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
|
||||||
|
fun List<SongEntity>.toSongs(): List<Song> {
|
||||||
|
return map {
|
||||||
|
it.toSong()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<Song>.toSongs(playlistId: Int): List<SongEntity> {
|
||||||
|
return map {
|
||||||
|
it.toSongEntity(playlistId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SongEntity.toSong(): Song {
|
||||||
|
return Song(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
trackNumber,
|
||||||
|
year,
|
||||||
|
duration,
|
||||||
|
data,
|
||||||
|
dateModified,
|
||||||
|
albumId,
|
||||||
|
albumName,
|
||||||
|
artistId,
|
||||||
|
artistName,
|
||||||
|
composer,
|
||||||
|
albumArtist
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PlayCountEntity.toSong(): Song {
|
||||||
|
return Song(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
trackNumber,
|
||||||
|
year,
|
||||||
|
duration,
|
||||||
|
data,
|
||||||
|
dateModified,
|
||||||
|
albumId,
|
||||||
|
albumName,
|
||||||
|
artistId,
|
||||||
|
artistName,
|
||||||
|
composer,
|
||||||
|
albumArtist
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun HistoryEntity.toSong(): Song {
|
||||||
|
return Song(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
trackNumber,
|
||||||
|
year,
|
||||||
|
duration,
|
||||||
|
data,
|
||||||
|
dateModified,
|
||||||
|
albumId,
|
||||||
|
albumName,
|
||||||
|
artistId,
|
||||||
|
artistName,
|
||||||
|
composer,
|
||||||
|
albumArtist
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Song.toPlayCount(): PlayCountEntity {
|
||||||
|
return PlayCountEntity(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
trackNumber,
|
||||||
|
year,
|
||||||
|
duration,
|
||||||
|
data,
|
||||||
|
dateModified,
|
||||||
|
albumId,
|
||||||
|
albumName,
|
||||||
|
artistId,
|
||||||
|
artistName,
|
||||||
|
composer,
|
||||||
|
albumArtist,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<Song>.toSongsEntity(playlistEntity: PlaylistEntity): List<SongEntity> {
|
||||||
|
return map {
|
||||||
|
it.toSongEntity(playlistEntity.playListId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,77 +1,70 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import code.name.monkey.retromusic.EXTRA_PLAYLISTS
|
||||||
import code.name.monkey.retromusic.EXTRA_SONG
|
import code.name.monkey.retromusic.EXTRA_SONG
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
|
import code.name.monkey.retromusic.db.toSongsEntity
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.extraNotNull
|
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
|
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.repository.PlaylistRepository
|
import kotlinx.coroutines.Dispatchers
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
|
|
||||||
class AddToPlaylistDialog : DialogFragment() {
|
class AddToPlaylistDialog : DialogFragment() {
|
||||||
private val playlistRepository by inject<PlaylistRepository>()
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
override fun onCreateDialog(
|
|
||||||
savedInstanceState: Bundle?
|
companion object {
|
||||||
): Dialog {
|
fun create(playlistEntities: List<PlaylistEntity>, song: Song): AddToPlaylistDialog {
|
||||||
val playlists = playlistRepository.playlists()
|
val list: MutableList<Song> = mutableListOf()
|
||||||
val playlistNames = mutableListOf<String>()
|
list.add(song)
|
||||||
|
return create(playlistEntities, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(playlistEntities: List<PlaylistEntity>, songs: List<Song>): AddToPlaylistDialog {
|
||||||
|
return AddToPlaylistDialog().apply {
|
||||||
|
arguments = bundleOf(
|
||||||
|
EXTRA_SONG to songs,
|
||||||
|
EXTRA_PLAYLISTS to playlistEntities
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val playlistEntities: List<PlaylistEntity> =
|
||||||
|
extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLISTS).value
|
||||||
|
val songs: List<Song> = extraNotNull<List<Song>>(EXTRA_SONG).value
|
||||||
|
val playlistNames: MutableList<String> = mutableListOf()
|
||||||
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
|
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
|
||||||
for (p in playlists) {
|
for (entity: PlaylistEntity in playlistEntities) {
|
||||||
playlistNames.add(p.name)
|
playlistNames.add(entity.playlistName)
|
||||||
}
|
}
|
||||||
return materialDialog(R.string.add_playlist_title)
|
return materialDialog(R.string.add_playlist_title)
|
||||||
.setItems(playlistNames.toTypedArray()) { _, which ->
|
.setItems(playlistNames.toTypedArray()) { _, which ->
|
||||||
val songs = extraNotNull<ArrayList<Song>>(EXTRA_SONG).value
|
|
||||||
if (which == 0) {
|
if (which == 0) {
|
||||||
CreatePlaylistDialog.create(songs)
|
CreatePlaylistDialog.create(songs)
|
||||||
.show(requireActivity().supportFragmentManager, "ADD_TO_PLAYLIST")
|
.show(requireActivity().supportFragmentManager, "Dialog")
|
||||||
} else {
|
} else {
|
||||||
PlaylistsUtil.addToPlaylist(
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
requireContext(),
|
val songEntities: List<SongEntity> =
|
||||||
songs,
|
songs.toSongsEntity(playlistEntities[which - 1])
|
||||||
playlists[which - 1].id,
|
libraryViewModel.insertSongs(songEntities)
|
||||||
true
|
libraryViewModel.forceReload(Playlists)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
.create().colorButtons()
|
.create().colorButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun create(song: Song): AddToPlaylistDialog {
|
|
||||||
val list = ArrayList<Song>()
|
|
||||||
list.add(song)
|
|
||||||
return create(list)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun create(songs: List<Song>): AddToPlaylistDialog {
|
|
||||||
val dialog = AddToPlaylistDialog()
|
|
||||||
val args = Bundle()
|
|
||||||
args.putParcelableArrayList(EXTRA_SONG, ArrayList(songs))
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,88 +1,74 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.retromusic.EXTRA_SONG
|
import code.name.monkey.retromusic.EXTRA_SONG
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.extraNotNull
|
import code.name.monkey.retromusic.extensions.extra
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
|
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import kotlinx.android.synthetic.main.dialog_playlist.view.*
|
import kotlinx.android.synthetic.main.dialog_playlist.view.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class CreatePlaylistDialog : DialogFragment() {
|
class CreatePlaylistDialog : DialogFragment() {
|
||||||
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
companion object {
|
||||||
override fun onCreateDialog(
|
fun create(song: Song): CreatePlaylistDialog {
|
||||||
savedInstanceState: Bundle?
|
val list = mutableListOf<Song>()
|
||||||
): Dialog {
|
list.add(song)
|
||||||
|
return create(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(songs: List<Song>): CreatePlaylistDialog {
|
||||||
|
return CreatePlaylistDialog().apply {
|
||||||
|
arguments = bundleOf(EXTRA_SONG to songs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null)
|
val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null)
|
||||||
|
val songs: List<Song> = extra<List<Song>>(EXTRA_SONG).value ?: emptyList()
|
||||||
val playlistView: TextInputEditText = view.actionNewPlaylist
|
val playlistView: TextInputEditText = view.actionNewPlaylist
|
||||||
val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer
|
val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer
|
||||||
MaterialUtil.setTint(playlistContainer, false)
|
|
||||||
|
|
||||||
return materialDialog(R.string.new_playlist_title)
|
return materialDialog(R.string.new_playlist_title)
|
||||||
.setView(view)
|
.setView(view)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.setPositiveButton(
|
.setPositiveButton(
|
||||||
R.string.create_action
|
R.string.create_action
|
||||||
) { _, _ ->
|
) { _, _ ->
|
||||||
val extra = extraNotNull<ArrayList<Song>>(EXTRA_SONG)
|
|
||||||
val playlistName = playlistView.text.toString()
|
val playlistName = playlistView.text.toString()
|
||||||
if (!TextUtils.isEmpty(playlistName)) {
|
if (!TextUtils.isEmpty(playlistName)) {
|
||||||
val playlistId = PlaylistsUtil.createPlaylist(
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
requireContext(),
|
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
|
||||||
playlistView.text.toString()
|
val playlistId: Long =
|
||||||
)
|
libraryViewModel.createPlaylist(PlaylistEntity(playlistName))
|
||||||
if (playlistId != -1) {
|
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) })
|
||||||
PlaylistsUtil.addToPlaylist(requireContext(), extra.value, playlistId, true)
|
libraryViewModel.forceReload(Playlists)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
playlistContainer.error = "Playlist is can't be empty"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.create()
|
.create()
|
||||||
.colorButtons()
|
.colorButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmOverloads
|
|
||||||
@JvmStatic
|
|
||||||
fun create(song: Song? = null): CreatePlaylistDialog {
|
|
||||||
val list = ArrayList<Song>()
|
|
||||||
if (song != null) {
|
|
||||||
list.add(song)
|
|
||||||
}
|
|
||||||
return create(list)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun create(songs: ArrayList<Song>): CreatePlaylistDialog {
|
|
||||||
val dialog = CreatePlaylistDialog()
|
|
||||||
val args = Bundle()
|
|
||||||
args.putParcelableArrayList(EXTRA_SONG, songs)
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,35 +1,41 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.extraNotNull
|
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class DeletePlaylistDialog : DialogFragment() {
|
class DeletePlaylistDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun create(playlist: PlaylistEntity): DeletePlaylistDialog {
|
||||||
|
val list = mutableListOf<PlaylistEntity>()
|
||||||
|
list.add(playlist)
|
||||||
|
return create(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(playlists: List<PlaylistEntity>): DeletePlaylistDialog {
|
||||||
|
return DeletePlaylistDialog().apply {
|
||||||
|
arguments = bundleOf(EXTRA_PLAYLIST to playlists)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val playlists = extraNotNull<List<Playlist>>(EXTRA_PLAYLIST).value
|
val playlists = extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLIST).value
|
||||||
val title: Int
|
val title: Int
|
||||||
val message: CharSequence
|
val message: CharSequence
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
@ -42,7 +48,7 @@ class DeletePlaylistDialog : DialogFragment() {
|
||||||
} else {
|
} else {
|
||||||
title = R.string.delete_playlist_title
|
title = R.string.delete_playlist_title
|
||||||
message = HtmlCompat.fromHtml(
|
message = HtmlCompat.fromHtml(
|
||||||
String.format(getString(R.string.delete_playlist_x), playlists[0].name),
|
String.format(getString(R.string.delete_playlist_x), playlists[0].playlistName),
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -52,26 +58,12 @@ class DeletePlaylistDialog : DialogFragment() {
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.setPositiveButton(R.string.action_delete) { _, _ ->
|
.setPositiveButton(R.string.action_delete) { _, _ ->
|
||||||
PlaylistsUtil.deletePlaylists(requireContext(), playlists)
|
libraryViewModel.deleteSongsFromPlaylist(playlists)
|
||||||
|
libraryViewModel.deleteRoomPlaylist(playlists)
|
||||||
|
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||||
}
|
}
|
||||||
.create()
|
.create()
|
||||||
.colorButtons()
|
.colorButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
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(EXTRA_PLAYLIST, playlist)
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
|
||||||
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity;
|
|
||||||
import code.name.monkey.retromusic.misc.DialogAsyncTask;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
import code.name.monkey.retromusic.util.SAFUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by hemanths on 2019-07-31.
|
|
||||||
*/
|
|
||||||
public class DeleteSongsAsyncTask extends DialogAsyncTask<DeleteSongsAsyncTask.LoadingInfo, Integer, Void> {
|
|
||||||
|
|
||||||
private WeakReference<FragmentActivity> activityWeakReference;
|
|
||||||
private WeakReference<DeleteSongsDialog> dialogReference;
|
|
||||||
|
|
||||||
public DeleteSongsAsyncTask(@NonNull DeleteSongsDialog dialog) {
|
|
||||||
super(dialog.getActivity());
|
|
||||||
this.dialogReference = new WeakReference<>(dialog);
|
|
||||||
this.activityWeakReference = new WeakReference<>(dialog.getActivity());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected Dialog createDialog(@NonNull Context context) {
|
|
||||||
return new MaterialAlertDialogBuilder(context,
|
|
||||||
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert)
|
|
||||||
.setTitle(R.string.deleting_songs)
|
|
||||||
.setView(R.layout.loading)
|
|
||||||
.setCancelable(false)
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(@NonNull LoadingInfo... loadingInfos) {
|
|
||||||
try {
|
|
||||||
LoadingInfo info = loadingInfos[0];
|
|
||||||
DeleteSongsDialog dialog = this.dialogReference.get();
|
|
||||||
FragmentActivity fragmentActivity = this.activityWeakReference.get();
|
|
||||||
|
|
||||||
if (dialog == null || fragmentActivity == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.isIntent) {
|
|
||||||
if (!SAFUtil.isSAFRequiredForSongs(info.songs)) {
|
|
||||||
dialog.deleteSongs(info.songs, null);
|
|
||||||
} else {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
if (SAFUtil.isSDCardAccessGranted(fragmentActivity)) {
|
|
||||||
dialog.deleteSongs(info.songs, null);
|
|
||||||
} else {
|
|
||||||
dialog.startActivityForResult(new Intent(fragmentActivity, SAFGuideActivity.class),
|
|
||||||
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i("Hmm", "doInBackground: kitkat delete songs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (info.requestCode) {
|
|
||||||
case SAFUtil.REQUEST_SAF_PICK_TREE:
|
|
||||||
if (info.resultCode == Activity.RESULT_OK) {
|
|
||||||
SAFUtil.saveTreeUri(fragmentActivity, info.intent);
|
|
||||||
if (dialog.songsToRemove != null) {
|
|
||||||
dialog.deleteSongs(dialog.songsToRemove, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SAFUtil.REQUEST_SAF_PICK_FILE:
|
|
||||||
if (info.resultCode == Activity.RESULT_OK) {
|
|
||||||
dialog.deleteSongs(Collections.singletonList(dialog.currentSong),
|
|
||||||
Collections.singletonList(info.intent.getData()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LoadingInfo {
|
|
||||||
|
|
||||||
public Intent intent;
|
|
||||||
|
|
||||||
public boolean isIntent;
|
|
||||||
|
|
||||||
public int requestCode;
|
|
||||||
|
|
||||||
public int resultCode;
|
|
||||||
|
|
||||||
public List<Uri> safUris;
|
|
||||||
|
|
||||||
public List<Song> songs;
|
|
||||||
|
|
||||||
public LoadingInfo(List<Song> songs, List<Uri> safUris) {
|
|
||||||
this.isIntent = false;
|
|
||||||
this.songs = songs;
|
|
||||||
this.safUris = safUris;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoadingInfo(int requestCode, int resultCode, Intent intent) {
|
|
||||||
this.isIntent = true;
|
|
||||||
this.requestCode = requestCode;
|
|
||||||
this.resultCode = resultCode;
|
|
||||||
this.intent = intent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +1,24 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import code.name.monkey.retromusic.EXTRA_SONG
|
import code.name.monkey.retromusic.EXTRA_SONG
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
|
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.extraNotNull
|
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.SAFUtil
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class DeleteSongsDialog : DialogFragment() {
|
class DeleteSongsDialog : DialogFragment() {
|
||||||
@JvmField
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
var currentSong: Song? = null
|
|
||||||
|
|
||||||
@JvmField
|
|
||||||
var songsToRemove: List<Song>? = null
|
|
||||||
|
|
||||||
private var deleteSongsAsyncTask: DeleteSongsAsyncTask? = null
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
|
|
||||||
var title = 0
|
|
||||||
var message: CharSequence = ""
|
|
||||||
if (songs.size > 1) {
|
|
||||||
title = R.string.delete_songs_title
|
|
||||||
message = HtmlCompat.fromHtml(
|
|
||||||
String.format(getString(R.string.delete_x_songs), songs.size),
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
title = R.string.delete_song_title
|
|
||||||
message = HtmlCompat.fromHtml(
|
|
||||||
String.format(getString(R.string.delete_song_x), songs[0].title),
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return materialDialog(title)
|
|
||||||
.setMessage(message)
|
|
||||||
.setCancelable(false)
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.action_delete) { _, _ ->
|
|
||||||
if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) {
|
|
||||||
MusicPlayerRemote.playNextSong()
|
|
||||||
}
|
|
||||||
songsToRemove = songs
|
|
||||||
deleteSongsAsyncTask = DeleteSongsAsyncTask(this@DeleteSongsDialog)
|
|
||||||
deleteSongsAsyncTask?.execute(DeleteSongsAsyncTask.LoadingInfo(songs, null))
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
.colorButtons()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
when (requestCode) {
|
|
||||||
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
|
|
||||||
SAFUtil.openTreePicker(this)
|
|
||||||
}
|
|
||||||
SAFUtil.REQUEST_SAF_PICK_TREE,
|
|
||||||
SAFUtil.REQUEST_SAF_PICK_FILE -> {
|
|
||||||
if (deleteSongsAsyncTask != null) {
|
|
||||||
deleteSongsAsyncTask?.cancel(true)
|
|
||||||
}
|
|
||||||
deleteSongsAsyncTask = DeleteSongsAsyncTask(this)
|
|
||||||
deleteSongsAsyncTask?.execute(
|
|
||||||
DeleteSongsAsyncTask.LoadingInfo(
|
|
||||||
requestCode,
|
|
||||||
resultCode,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun deleteSongs(songs: List<Song>, safUris: List<Uri>?) {
|
|
||||||
MusicUtil.deleteTracks(requireActivity(), songs, safUris, Runnable {
|
|
||||||
dismiss()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun create(song: Song): DeleteSongsDialog {
|
fun create(song: Song): DeleteSongsDialog {
|
||||||
val list = ArrayList<Song>()
|
val list = ArrayList<Song>()
|
||||||
list.add(song)
|
list.add(song)
|
||||||
|
@ -119,5 +33,38 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
|
||||||
|
val pair = if (songs.size > 1) {
|
||||||
|
Pair(
|
||||||
|
R.string.delete_songs_title,
|
||||||
|
HtmlCompat.fromHtml(
|
||||||
|
String.format(getString(R.string.delete_x_songs), songs.size),
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Pair(
|
||||||
|
R.string.delete_song_title,
|
||||||
|
HtmlCompat.fromHtml(
|
||||||
|
String.format(getString(R.string.delete_song_x), songs[0].title),
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return materialDialog(pair.first)
|
||||||
|
.setMessage(pair.second)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(R.string.action_delete) { _, _ ->
|
||||||
|
if (songs.isNotEmpty() and (songs.size == 1) and MusicPlayerRemote.isPlaying(songs.first())) {
|
||||||
|
MusicPlayerRemote.playNextSong()
|
||||||
|
}
|
||||||
|
MusicUtil.deleteTracks(requireActivity(), songs)
|
||||||
|
libraryViewModel.deleteTracks(songs)
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
.colorButtons()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
|
class ImportPlaylistDialog : DialogFragment() {
|
||||||
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
return materialDialog(R.string.import_playlist)
|
||||||
|
.setMessage(R.string.import_playlist_message)
|
||||||
|
.setPositiveButton(R.string.import_label) { _, _ ->
|
||||||
|
libraryViewModel.importPlaylists()
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
.colorButtons()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.extensions.accentTextColor
|
||||||
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
|
import code.name.monkey.retromusic.repository.Repository
|
||||||
|
import kotlinx.android.synthetic.main.lyrics_dialog.*
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class LyricsDialog : DialogFragment() {
|
||||||
|
override fun getTheme(): Int {
|
||||||
|
return R.style.MaterialAlertDialogTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
private val repository by inject<Repository>()
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return inflater.inflate(R.layout.lyrics_dialog, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val song = MusicPlayerRemote.currentSong
|
||||||
|
dialogTitle.text = song.title
|
||||||
|
syncedLyrics.accentTextColor()
|
||||||
|
lifecycleScope.launch(IO) {
|
||||||
|
val result: Result<String> = repository.lyrics(
|
||||||
|
song.artistName,
|
||||||
|
song.title
|
||||||
|
)
|
||||||
|
withContext(Main) {
|
||||||
|
|
||||||
|
when (result) {
|
||||||
|
is Result.Error -> progressBar.hide()
|
||||||
|
is Result.Loading -> println("Loading")
|
||||||
|
is Result.Success -> {
|
||||||
|
progressBar.hide()
|
||||||
|
lyricsText.text = result.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,84 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.core.text.HtmlCompat
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import code.name.monkey.retromusic.EXTRA_SONG
|
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
import code.name.monkey.retromusic.R.string
|
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong
|
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
|
||||||
|
|
||||||
class RemoveFromPlaylistDialog : DialogFragment() {
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
val songs = requireArguments().getParcelableArrayList<PlaylistSong>(EXTRA_SONG)
|
|
||||||
|
|
||||||
var title = 0
|
|
||||||
var message: CharSequence = ""
|
|
||||||
if (songs != null) {
|
|
||||||
if (songs.size > 1) {
|
|
||||||
title = R.string.remove_songs_from_playlist_title
|
|
||||||
message = HtmlCompat.fromHtml(
|
|
||||||
String.format(getString(string.remove_x_songs_from_playlist), songs.size),
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
title = R.string.remove_song_from_playlist_title
|
|
||||||
message = HtmlCompat.fromHtml(
|
|
||||||
String.format(
|
|
||||||
getString(string.remove_song_x_from_playlist),
|
|
||||||
songs[0].title
|
|
||||||
),
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return materialDialog(title)
|
|
||||||
.setMessage(message)
|
|
||||||
.setPositiveButton(R.string.remove_action) { _, _ ->
|
|
||||||
PlaylistsUtil.removeFromPlaylist(
|
|
||||||
requireContext(),
|
|
||||||
songs as MutableList<PlaylistSong>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.create()
|
|
||||||
.colorButtons()
|
|
||||||
}
|
|
||||||
|
|
||||||
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(EXTRA_SONG, songs)
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import code.name.monkey.retromusic.EXTRA_SONG
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
|
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||||
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
|
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
|
class RemoveSongFromPlaylistDialog : DialogFragment() {
|
||||||
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(song: SongEntity): RemoveSongFromPlaylistDialog {
|
||||||
|
val list = mutableListOf<SongEntity>()
|
||||||
|
list.add(song)
|
||||||
|
return create(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(songs: List<SongEntity>): RemoveSongFromPlaylistDialog {
|
||||||
|
return RemoveSongFromPlaylistDialog().apply {
|
||||||
|
arguments = bundleOf(
|
||||||
|
EXTRA_SONG to songs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val songs = extraNotNull<List<SongEntity>>(EXTRA_SONG).value
|
||||||
|
val pair = if (songs.size > 1) {
|
||||||
|
Pair(
|
||||||
|
R.string.remove_songs_from_playlist_title,
|
||||||
|
HtmlCompat.fromHtml(
|
||||||
|
String.format(getString(R.string.remove_x_songs_from_playlist), songs.size),
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Pair(
|
||||||
|
R.string.remove_song_from_playlist_title,
|
||||||
|
HtmlCompat.fromHtml(
|
||||||
|
String.format(
|
||||||
|
getString(R.string.remove_song_x_from_playlist),
|
||||||
|
songs[0].title
|
||||||
|
),
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return materialDialog(pair.first)
|
||||||
|
.setMessage(pair.second)
|
||||||
|
.setPositiveButton(R.string.remove_action) { _, _ ->
|
||||||
|
libraryViewModel.deleteSongsInPlaylist(songs)
|
||||||
|
libraryViewModel.forceReload(Playlists)
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.create()
|
||||||
|
.colorButtons()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,73 +1,57 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.dialogs
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore.Audio.Playlists.Members.PLAYLIST_ID
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.extensions.accentColor
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.extraNotNull
|
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class RenamePlaylistDialog : DialogFragment() {
|
class RenamePlaylistDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
companion object {
|
||||||
override fun onCreateDialog(
|
fun create(playlistEntity: PlaylistEntity): RenamePlaylistDialog {
|
||||||
savedInstanceState: Bundle?
|
return RenamePlaylistDialog().apply {
|
||||||
): Dialog {
|
arguments = bundleOf(
|
||||||
val layout = LayoutInflater.from(requireContext())
|
EXTRA_PLAYLIST_ID to playlistEntity
|
||||||
.inflate(R.layout.dialog_playlist, null)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val playlistEntity = extraNotNull<PlaylistEntity>(EXTRA_PLAYLIST_ID).value
|
||||||
|
val layout = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_playlist, null)
|
||||||
val inputEditText: TextInputEditText = layout.findViewById(R.id.actionNewPlaylist)
|
val inputEditText: TextInputEditText = layout.findViewById(R.id.actionNewPlaylist)
|
||||||
val nameContainer: TextInputLayout =
|
val nameContainer: TextInputLayout = layout.findViewById(R.id.actionNewPlaylistContainer)
|
||||||
layout.findViewById(R.id.actionNewPlaylistContainer)
|
nameContainer.accentColor()
|
||||||
MaterialUtil.setTint(nameContainer, false)
|
inputEditText.setText(playlistEntity.playlistName)
|
||||||
|
|
||||||
return materialDialog(R.string.rename_playlist_title)
|
return materialDialog(R.string.rename_playlist_title)
|
||||||
.setView(layout)
|
.setView(layout)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.setPositiveButton(R.string.action_rename) { _, _ ->
|
.setPositiveButton(R.string.action_rename) { _, _ ->
|
||||||
val name = inputEditText.text.toString()
|
val name = inputEditText.text.toString()
|
||||||
if (name.isNotEmpty()) {
|
if (name.isNotEmpty()) {
|
||||||
PlaylistsUtil.renamePlaylist(
|
libraryViewModel.renameRoomPlaylist(playlistEntity.playListId, name)
|
||||||
requireContext(),
|
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||||
extraNotNull<Long>(PLAYLIST_ID).value,
|
} else {
|
||||||
name
|
nameContainer.error = "Playlist name should'nt be empty"
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.create()
|
.create()
|
||||||
.colorButtons()
|
.colorButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun create(playlistId: Long): RenamePlaylistDialog {
|
|
||||||
val dialog = RenamePlaylistDialog()
|
|
||||||
val args = Bundle()
|
|
||||||
args.putLong(PLAYLIST_ID, playlistId)
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
package code.name.monkey.retromusic.dialogs
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
|
|
||||||
class RetroSingleCheckedListAdapter(
|
|
||||||
context: Context,
|
|
||||||
resource: Int = R.layout.dialog_list_item,
|
|
||||||
objects: MutableList<String>
|
|
||||||
) : ArrayAdapter<String>(context, resource, objects) {
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package code.name.monkey.retromusic.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import code.name.monkey.retromusic.App
|
||||||
|
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
|
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||||
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
|
class SavePlaylistDialog : DialogFragment() {
|
||||||
|
companion object {
|
||||||
|
fun create(playlistWithSongs: PlaylistWithSongs): SavePlaylistDialog {
|
||||||
|
return SavePlaylistDialog().apply {
|
||||||
|
arguments = bundleOf(
|
||||||
|
EXTRA_PLAYLIST to playlistWithSongs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val playlistWithSongs: PlaylistWithSongs =
|
||||||
|
extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value
|
||||||
|
val file = PlaylistsUtil.savePlaylistWithSongs(requireContext(), playlistWithSongs)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(
|
||||||
|
requireContext(),
|
||||||
|
String.format(App.getContext().getString(R.string.saved_playlist_to), file),
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
return materialDialog(R.string.save_playlist_title)
|
||||||
|
.setView(R.layout.loading)
|
||||||
|
.create().colorButtons()
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,8 +53,8 @@ class SleepTimerDialog : DialogFragment() {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
timerUpdater = TimerUpdater()
|
timerUpdater = TimerUpdater()
|
||||||
val layout = LayoutInflater.from(requireContext())
|
val layout =
|
||||||
.inflate(R.layout.dialog_sleep_timer, null)
|
LayoutInflater.from(requireContext()).inflate(R.layout.dialog_sleep_timer, null)
|
||||||
shouldFinishLastSong = layout.findViewById(R.id.shouldFinishLastSong)
|
shouldFinishLastSong = layout.findViewById(R.id.shouldFinishLastSong)
|
||||||
seekBar = layout.findViewById(R.id.seekBar)
|
seekBar = layout.findViewById(R.id.seekBar)
|
||||||
timerDisplay = layout.findViewById(R.id.timerDisplay)
|
timerDisplay = layout.findViewById(R.id.timerDisplay)
|
||||||
|
@ -158,7 +158,7 @@ class SleepTimerDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class TimerUpdater internal constructor() :
|
private inner class TimerUpdater() :
|
||||||
CountDownTimer(
|
CountDownTimer(
|
||||||
PreferenceUtil.nextSleepTimerElapsedRealTime - SystemClock.elapsedRealtime(),
|
PreferenceUtil.nextSleepTimerElapsedRealTime - SystemClock.elapsedRealtime(),
|
||||||
1000
|
1000
|
||||||
|
|
|
@ -21,8 +21,6 @@ import android.os.Bundle
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
|
@ -41,12 +39,6 @@ import org.jaudiotagger.tag.TagException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
inline fun ViewGroup.forEach(action: (View) -> Unit) {
|
|
||||||
for (i in 0 until childCount) {
|
|
||||||
action(getChildAt(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SongDetailDialog : DialogFragment() {
|
class SongDetailDialog : DialogFragment() {
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
|
|
|
@ -15,13 +15,8 @@
|
||||||
package code.name.monkey.retromusic.extensions
|
package code.name.monkey.retromusic.extensions
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import androidx.annotation.IdRes
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import androidx.fragment.app.FragmentTransaction
|
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
|
||||||
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
||||||
|
@ -30,41 +25,6 @@ fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FragmentActivity?.addFragment(
|
|
||||||
@IdRes idRes: Int = R.id.container,
|
|
||||||
fragment: Fragment,
|
|
||||||
tag: String? = null,
|
|
||||||
addToBackStack: Boolean = false
|
|
||||||
) {
|
|
||||||
val compatActivity = this as? AppCompatActivity ?: return
|
|
||||||
compatActivity.supportFragmentManager.beginTransaction()
|
|
||||||
.apply {
|
|
||||||
add(fragment, tag)
|
|
||||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
|
||||||
if (addToBackStack) {
|
|
||||||
addToBackStack(null)
|
|
||||||
}
|
|
||||||
commitNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun AppCompatActivity.replaceFragment(
|
|
||||||
@IdRes id: Int = R.id.container,
|
|
||||||
fragment: Fragment,
|
|
||||||
tag: String? = null,
|
|
||||||
addToBackStack: Boolean = false
|
|
||||||
) {
|
|
||||||
val compatActivity = this ?: return
|
|
||||||
compatActivity.supportFragmentManager.beginTransaction()
|
|
||||||
.apply {
|
|
||||||
replace(id, fragment, tag)
|
|
||||||
if (addToBackStack) {
|
|
||||||
addToBackStack(null)
|
|
||||||
}
|
|
||||||
commit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> Activity.extra(key: String, default: T? = null) = lazy {
|
inline fun <reified T : Any> Activity.extra(key: String, default: T? = null) = lazy {
|
||||||
val value = intent?.extras?.get(key)
|
val value = intent?.extras?.get(key)
|
||||||
if (value is T) value else default
|
if (value is T) value else default
|
||||||
|
|
|
@ -18,12 +18,18 @@ import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.CheckResult
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
|
@ -33,6 +39,8 @@ import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import com.google.android.material.progressindicator.ProgressIndicator
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
|
||||||
|
@ -91,6 +99,10 @@ fun Button.accentTextColor() {
|
||||||
setTextColor(ThemeStore.accentColor(App.getContext()))
|
setTextColor(ThemeStore.accentColor(App.getContext()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MaterialButton.accentTextColor() {
|
||||||
|
setTextColor(ThemeStore.accentColor(App.getContext()))
|
||||||
|
}
|
||||||
|
|
||||||
fun SeekBar.applyColor(@ColorInt color: Int) {
|
fun SeekBar.applyColor(@ColorInt color: Int) {
|
||||||
thumbTintList = ColorStateList.valueOf(color)
|
thumbTintList = ColorStateList.valueOf(color)
|
||||||
progressTintList = ColorStateList.valueOf(color)
|
progressTintList = ColorStateList.valueOf(color)
|
||||||
|
@ -107,6 +119,15 @@ fun ExtendedFloatingActionButton.accentColor() {
|
||||||
iconTint = textColorStateList
|
iconTint = textColorStateList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FloatingActionButton.accentColor() {
|
||||||
|
val color = ThemeStore.accentColor(context)
|
||||||
|
val textColor = MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color))
|
||||||
|
val colorStateList = ColorStateList.valueOf(color)
|
||||||
|
val textColorStateList = ColorStateList.valueOf(textColor)
|
||||||
|
backgroundTintList = colorStateList
|
||||||
|
imageTintList = textColorStateList
|
||||||
|
}
|
||||||
|
|
||||||
fun MaterialButton.applyColor(color: Int) {
|
fun MaterialButton.applyColor(color: Int) {
|
||||||
val backgroundColorStateList = ColorStateList.valueOf(color)
|
val backgroundColorStateList = ColorStateList.valueOf(color)
|
||||||
val textColorColorStateList = ColorStateList.valueOf(
|
val textColorColorStateList = ColorStateList.valueOf(
|
||||||
|
@ -120,6 +141,12 @@ fun MaterialButton.applyColor(color: Int) {
|
||||||
iconTint = textColorColorStateList
|
iconTint = textColorColorStateList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MaterialButton.applyOutlineColor(color: Int) {
|
||||||
|
val textColorColorStateList = ColorStateList.valueOf(color)
|
||||||
|
setTextColor(textColorColorStateList)
|
||||||
|
iconTint = textColorColorStateList
|
||||||
|
}
|
||||||
|
|
||||||
fun TextInputLayout.accentColor() {
|
fun TextInputLayout.accentColor() {
|
||||||
val accentColor = ThemeStore.accentColor(context)
|
val accentColor = ThemeStore.accentColor(context)
|
||||||
val colorState = ColorStateList.valueOf(accentColor)
|
val colorState = ColorStateList.valueOf(accentColor)
|
||||||
|
@ -128,6 +155,39 @@ fun TextInputLayout.accentColor() {
|
||||||
isHintAnimationEnabled = true
|
isHintAnimationEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ProgressIndicator.accentColor() {
|
||||||
|
val accentColor = ThemeStore.accentColor(context)
|
||||||
|
indicatorColors = intArrayOf(accentColor)
|
||||||
|
trackColor = ColorUtil.withAlpha(accentColor, 0.2f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ProgressIndicator.applyColor(color: Int) {
|
||||||
|
indicatorColors = intArrayOf(color)
|
||||||
|
trackColor = ColorUtil.withAlpha(color, 0.2f)
|
||||||
|
}
|
||||||
|
|
||||||
fun TextInputEditText.accentColor() {
|
fun TextInputEditText.accentColor() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun AppCompatImageView.accentColor(): Int {
|
||||||
|
return ThemeStore.accentColor(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckResult
|
||||||
|
fun Drawable.tint(@ColorInt color: Int): Drawable {
|
||||||
|
val tintedDrawable = DrawableCompat.wrap(this).mutate()
|
||||||
|
DrawableCompat.setTint(this, color)
|
||||||
|
return tintedDrawable
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckResult
|
||||||
|
fun Drawable.tint(context: Context, @ColorRes color: Int): Drawable {
|
||||||
|
return tint(context.getColorCompat(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
fun Context.getColorCompat(@ColorRes colorRes: Int): Int {
|
||||||
|
return ContextCompat.getColor(this, colorRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
fun DialogFragment.materialDialog(title: Int): MaterialAlertDialogBuilder {
|
fun DialogFragment.materialDialog(title: Int): MaterialAlertDialogBuilder {
|
||||||
return MaterialAlertDialogBuilder(
|
return MaterialAlertDialogBuilder(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
|
R.style.MaterialAlertDialogTheme
|
||||||
).setTitle(title)
|
).setTitle(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,15 @@ package code.name.monkey.retromusic.extensions
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
import androidx.annotation.IntegerRes
|
import androidx.annotation.IntegerRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
@ -51,7 +54,8 @@ val FragmentManager.currentNavigationFragment: Fragment?
|
||||||
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
|
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
|
||||||
|
|
||||||
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
||||||
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
val navHostFragment: NavHostFragment =
|
||||||
|
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||||
navHostFragment.targetFragment
|
navHostFragment.targetFragment
|
||||||
return navHostFragment.childFragmentManager.fragments.first()
|
return navHostFragment.childFragmentManager.fragments.first()
|
||||||
}
|
}
|
||||||
|
@ -72,4 +76,12 @@ fun Fragment.showToast(@StringRes stringRes: Int) {
|
||||||
|
|
||||||
fun Fragment.showToast(message: String) {
|
fun Fragment.showToast(message: String) {
|
||||||
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getDrawableCompat(@DrawableRes drawableRes: Int): Drawable {
|
||||||
|
return AppCompatResources.getDrawable(this, drawableRes)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.getDrawableCompat(@DrawableRes drawableRes: Int): Drawable {
|
||||||
|
return AppCompatResources.getDrawable(requireContext(), drawableRes)!!
|
||||||
}
|
}
|
|
@ -14,13 +14,10 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.extensions
|
package code.name.monkey.retromusic.extensions
|
||||||
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.SeekBar
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package code.name.monkey.retromusic.fragments
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
open class CoroutineViewModel(
|
||||||
|
private val mainDispatcher: CoroutineDispatcher
|
||||||
|
) : ViewModel() {
|
||||||
|
private val job = Job()
|
||||||
|
protected val scope = CoroutineScope(job + mainDispatcher)
|
||||||
|
|
||||||
|
protected fun launch(
|
||||||
|
context: CoroutineContext = mainDispatcher,
|
||||||
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
|
block: suspend CoroutineScope.() -> Unit
|
||||||
|
) = scope.launch(context, start, block)
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ package code.name.monkey.retromusic.fragments
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
@ -10,15 +12,14 @@ import code.name.monkey.retromusic.*
|
||||||
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
||||||
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
||||||
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
||||||
|
import code.name.monkey.retromusic.db.toSong
|
||||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||||
import code.name.monkey.retromusic.fragments.artists.ArtistClickListener
|
import code.name.monkey.retromusic.fragments.artists.ArtistClickListener
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import code.name.monkey.retromusic.model.Album
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
import code.name.monkey.retromusic.model.Song
|
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
|
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -34,6 +35,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
mainActivity.setSupportActionBar(toolbar)
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
mainActivity.hideBottomBarVisibility(false)
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
|
progressIndicator.hide()
|
||||||
when (args.type) {
|
when (args.type) {
|
||||||
TOP_ARTISTS -> {
|
TOP_ARTISTS -> {
|
||||||
loadArtists(R.string.top_artists, TOP_ARTISTS)
|
loadArtists(R.string.top_artists, TOP_ARTISTS)
|
||||||
|
@ -47,32 +49,88 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
RECENT_ALBUMS -> {
|
RECENT_ALBUMS -> {
|
||||||
loadAlbums(R.string.recent_albums, RECENT_ALBUMS)
|
loadAlbums(R.string.recent_albums, RECENT_ALBUMS)
|
||||||
}
|
}
|
||||||
FAVOURITES -> {
|
FAVOURITES -> loadFavorite()
|
||||||
loadFavorite()
|
HISTORY_PLAYLIST -> loadHistory()
|
||||||
}
|
LAST_ADDED_PLAYLIST -> lastAddedSongs()
|
||||||
|
TOP_PLAYED_PLAYLIST -> topPlayed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun lastAddedSongs() {
|
||||||
|
toolbar.setTitle(R.string.last_added)
|
||||||
|
val songAdapter = SongAdapter(
|
||||||
|
requireActivity(),
|
||||||
|
mutableListOf(),
|
||||||
|
R.layout.item_list, null
|
||||||
|
)
|
||||||
|
recyclerView.apply {
|
||||||
|
adapter = songAdapter
|
||||||
|
layoutManager = linearLayoutManager()
|
||||||
|
}
|
||||||
|
lifecycleScope.launch(IO) {
|
||||||
|
val songs = repository.recentSongs()
|
||||||
|
withContext(Main) { songAdapter.swapDataSet(songs) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun topPlayed() {
|
||||||
|
toolbar.setTitle(R.string.my_top_tracks)
|
||||||
|
val songAdapter = SongAdapter(
|
||||||
|
requireActivity(),
|
||||||
|
mutableListOf(),
|
||||||
|
R.layout.item_list, null
|
||||||
|
)
|
||||||
|
recyclerView.apply {
|
||||||
|
adapter = songAdapter
|
||||||
|
layoutManager = linearLayoutManager()
|
||||||
|
}
|
||||||
|
lifecycleScope.launch(IO) {
|
||||||
|
val songs = repository.playCountSongs().map {
|
||||||
|
it.toSong()
|
||||||
|
}
|
||||||
|
withContext(Main) { songAdapter.swapDataSet(songs) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadHistory() {
|
||||||
|
toolbar.setTitle(R.string.history)
|
||||||
|
|
||||||
|
val songAdapter = SongAdapter(
|
||||||
|
requireActivity(),
|
||||||
|
mutableListOf(),
|
||||||
|
R.layout.item_list, null
|
||||||
|
)
|
||||||
|
recyclerView.apply {
|
||||||
|
adapter = songAdapter
|
||||||
|
layoutManager = linearLayoutManager()
|
||||||
|
}
|
||||||
|
repository.observableHistorySongs().observe(viewLifecycleOwner, Observer {
|
||||||
|
val songs = it.map { historyEntity -> historyEntity.toSong() }
|
||||||
|
songAdapter.swapDataSet(songs)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadFavorite() {
|
private fun loadFavorite() {
|
||||||
toolbar.setTitle(R.string.favorites)
|
toolbar.setTitle(R.string.favorites)
|
||||||
CoroutineScope(IO).launch {
|
val songAdapter = SongAdapter(
|
||||||
val songs = repository.favoritePlaylistHome()
|
requireActivity(),
|
||||||
withContext(Main) {
|
mutableListOf(),
|
||||||
recyclerView.apply {
|
R.layout.item_list, null
|
||||||
adapter = SongAdapter(
|
)
|
||||||
requireActivity(),
|
recyclerView.apply {
|
||||||
songs.arrayList as MutableList<Song>,
|
adapter = songAdapter
|
||||||
R.layout.item_list, null
|
layoutManager = linearLayoutManager()
|
||||||
)
|
|
||||||
layoutManager = linearLayoutManager()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
repository.favorites().observe(viewLifecycleOwner, Observer {
|
||||||
|
println(it.size)
|
||||||
|
val songs = it.map { songEntity -> songEntity.toSong() }
|
||||||
|
songAdapter.swapDataSet(songs)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadArtists(title: Int, type: Int) {
|
private fun loadArtists(title: Int, type: Int) {
|
||||||
toolbar.setTitle(title)
|
toolbar.setTitle(title)
|
||||||
CoroutineScope(IO).launch {
|
lifecycleScope.launch(IO) {
|
||||||
val artists =
|
val artists =
|
||||||
if (type == TOP_ARTISTS) repository.topArtists() else repository.recentArtists()
|
if (type == TOP_ARTISTS) repository.topArtists() else repository.recentArtists()
|
||||||
withContext(Main) {
|
withContext(Main) {
|
||||||
|
@ -86,7 +144,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
||||||
|
|
||||||
private fun loadAlbums(title: Int, type: Int) {
|
private fun loadAlbums(title: Int, type: Int) {
|
||||||
toolbar.setTitle(title)
|
toolbar.setTitle(title)
|
||||||
CoroutineScope(IO).launch {
|
lifecycleScope.launch(IO) {
|
||||||
val albums =
|
val albums =
|
||||||
if (type == TOP_ALBUMS) repository.topAlbums() else repository.recentAlbums()
|
if (type == TOP_ALBUMS) repository.topAlbums() else repository.recentAlbums()
|
||||||
withContext(Main) {
|
withContext(Main) {
|
||||||
|
|
|
@ -4,83 +4,129 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType.*
|
import code.name.monkey.retromusic.fragments.ReloadType.*
|
||||||
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
import code.name.monkey.retromusic.model.*
|
import code.name.monkey.retromusic.model.*
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LibraryViewModel(
|
class LibraryViewModel(
|
||||||
private val realRepository: RealRepository
|
private val repository: RealRepository
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val paletteColor = MutableLiveData<Int>()
|
private val paletteColor = MutableLiveData<Int>()
|
||||||
private val albums = MutableLiveData<List<Album>>()
|
private val albums = MutableLiveData<List<Album>>()
|
||||||
private val songs = MutableLiveData<List<Song>>()
|
private val songs = MutableLiveData<List<Song>>()
|
||||||
private val artists = MutableLiveData<List<Artist>>()
|
private val artists = MutableLiveData<List<Artist>>()
|
||||||
private val playlists = MutableLiveData<List<Playlist>>()
|
private val playlists = MutableLiveData<List<PlaylistWithSongs>>()
|
||||||
|
private val legacyPlaylists = MutableLiveData<List<Playlist>>()
|
||||||
private val genres = MutableLiveData<List<Genre>>()
|
private val genres = MutableLiveData<List<Genre>>()
|
||||||
private val home = MutableLiveData<List<Home>>()
|
private val home = MutableLiveData<List<Home>>()
|
||||||
|
|
||||||
val paletteColorLiveData: LiveData<Int> = paletteColor
|
val paletteColorLiveData: LiveData<Int> = paletteColor
|
||||||
val homeLiveData: LiveData<List<Home>> = home
|
|
||||||
val albumsLiveData: LiveData<List<Album>> = albums
|
|
||||||
val songsLiveData: LiveData<List<Song>> = songs
|
|
||||||
val artistsLiveData: LiveData<List<Artist>> = artists
|
|
||||||
val playlisitsLiveData: LiveData<List<Playlist>> = playlists
|
|
||||||
val genresLiveData: LiveData<List<Genre>> = genres
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
fetchHomeSections()
|
||||||
loadLibraryContent()
|
}
|
||||||
|
|
||||||
|
private fun loadLibraryContent() = viewModelScope.launch(IO) {
|
||||||
|
fetchHomeSections()
|
||||||
|
fetchSongs()
|
||||||
|
fetchAlbums()
|
||||||
|
fetchArtists()
|
||||||
|
fetchGenres()
|
||||||
|
fetchPlaylists()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSongs(): LiveData<List<Song>> {
|
||||||
|
fetchSongs()
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlbums(): LiveData<List<Album>> {
|
||||||
|
fetchAlbums()
|
||||||
|
return albums
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getArtists(): LiveData<List<Artist>> {
|
||||||
|
fetchArtists()
|
||||||
|
return artists
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPlaylists(): LiveData<List<PlaylistWithSongs>> {
|
||||||
|
fetchPlaylists()
|
||||||
|
return playlists
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLegacyPlaylist(): LiveData<List<Playlist>> {
|
||||||
|
fetchLegacyPlaylist()
|
||||||
|
return legacyPlaylists
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getGenre(): LiveData<List<Genre>> {
|
||||||
|
fetchGenres()
|
||||||
|
return genres
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getHome(): LiveData<List<Home>> {
|
||||||
|
return home
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchSongs() {
|
||||||
|
viewModelScope.launch(IO) {
|
||||||
|
songs.postValue(repository.allSongs())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadLibraryContent() = viewModelScope.launch {
|
private fun fetchAlbums() {
|
||||||
songs.value = loadSongs.await()
|
viewModelScope.launch(IO) {
|
||||||
albums.value = loadAlbums.await()
|
albums.postValue(repository.fetchAlbums())
|
||||||
artists.value = loadArtists.await()
|
}
|
||||||
playlists.value = loadPlaylists.await()
|
|
||||||
genres.value = loadGenres.await()
|
|
||||||
home.value = loadHome.await()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loadHome: Deferred<List<Home>>
|
private fun fetchArtists() {
|
||||||
get() = viewModelScope.async { realRepository.homeSections() }
|
viewModelScope.launch(IO) {
|
||||||
|
artists.postValue(repository.fetchArtists())
|
||||||
private val loadSongs: Deferred<List<Song>>
|
|
||||||
get() = viewModelScope.async(IO) { realRepository.allSongs() }
|
|
||||||
|
|
||||||
private val loadAlbums: Deferred<List<Album>>
|
|
||||||
get() = viewModelScope.async(IO) {
|
|
||||||
realRepository.allAlbums()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val loadArtists: Deferred<List<Artist>>
|
private fun fetchPlaylists() {
|
||||||
get() = viewModelScope.async(IO) {
|
viewModelScope.launch(IO) {
|
||||||
realRepository.albumArtists()
|
playlists.postValue(repository.fetchPlaylistWithSongs())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val loadPlaylists: Deferred<List<Playlist>>
|
private fun fetchLegacyPlaylist() {
|
||||||
get() = viewModelScope.async(IO) {
|
viewModelScope.launch(IO) {
|
||||||
realRepository.allPlaylists()
|
legacyPlaylists.postValue(repository.fetchLegacyPlaylist())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val loadGenres: Deferred<List<Genre>>
|
private fun fetchGenres() {
|
||||||
get() = viewModelScope.async(IO) {
|
viewModelScope.launch(IO) {
|
||||||
realRepository.allGenres()
|
genres.postValue(repository.fetchGenres())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchHomeSections() {
|
||||||
|
viewModelScope.launch(IO) {
|
||||||
|
home.postValue(repository.homeSections())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
|
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
|
||||||
when (reloadType) {
|
when (reloadType) {
|
||||||
Songs -> songs.value = loadSongs.await()
|
Songs -> fetchSongs()
|
||||||
Albums -> albums.value = loadAlbums.await()
|
Albums -> fetchAlbums()
|
||||||
Artists -> artists.value = loadArtists.await()
|
Artists -> fetchArtists()
|
||||||
HomeSections -> songs.value = loadSongs.await()
|
HomeSections -> fetchHomeSections()
|
||||||
|
Playlists -> fetchPlaylists()
|
||||||
|
Genres -> fetchGenres()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +135,10 @@ class LibraryViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
loadLibraryContent()
|
|
||||||
println("onMediaStoreChanged")
|
println("onMediaStoreChanged")
|
||||||
|
loadLibraryContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onServiceConnected() {
|
override fun onServiceConnected() {
|
||||||
println("onServiceConnected")
|
println("onServiceConnected")
|
||||||
}
|
}
|
||||||
|
@ -108,6 +153,7 @@ class LibraryViewModel(
|
||||||
|
|
||||||
override fun onPlayingMetaChanged() {
|
override fun onPlayingMetaChanged() {
|
||||||
println("onPlayingMetaChanged")
|
println("onPlayingMetaChanged")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlayStateChanged() {
|
override fun onPlayStateChanged() {
|
||||||
|
@ -122,11 +168,76 @@ class LibraryViewModel(
|
||||||
println("onShuffleModeChanged")
|
println("onShuffleModeChanged")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun shuffleSongs() = viewModelScope.launch(IO) {
|
||||||
|
val songs = repository.allSongs()
|
||||||
|
MusicPlayerRemote.openAndShuffleQueue(
|
||||||
|
songs,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renameRoomPlaylist(playListId: Int, name: String) = viewModelScope.launch(IO) {
|
||||||
|
repository.renameRoomPlaylist(playListId, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteSongsInPlaylist(songs: List<SongEntity>) = viewModelScope.launch(IO) {
|
||||||
|
repository.deleteSongsInPlaylist(songs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) = viewModelScope.launch(IO) {
|
||||||
|
repository.deletePlaylistSongs(playlists)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) = viewModelScope.launch(IO) {
|
||||||
|
repository.deleteRoomPlaylist(playlists)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun albumById(id: Int) = repository.albumById(id)
|
||||||
|
suspend fun artistById(id: Int) = repository.artistById(id)
|
||||||
|
suspend fun favoritePlaylist() = repository.favoritePlaylist()
|
||||||
|
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
||||||
|
suspend fun insertSongs(songs: List<SongEntity>) = repository.insertSongs(songs)
|
||||||
|
suspend fun removeSongFromPlaylist(songEntity: SongEntity) =
|
||||||
|
repository.removeSongFromPlaylist(songEntity)
|
||||||
|
|
||||||
|
suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity> =
|
||||||
|
repository.checkPlaylistExists(playlistName)
|
||||||
|
|
||||||
|
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
|
||||||
|
repository.createPlaylist(playlistEntity)
|
||||||
|
|
||||||
|
fun importPlaylists() = viewModelScope.launch(IO) {
|
||||||
|
val playlists = repository.fetchLegacyPlaylist()
|
||||||
|
playlists.forEach { playlist ->
|
||||||
|
val playlistEntity = repository.checkPlaylistExists(playlist.name).firstOrNull()
|
||||||
|
if (playlistEntity != null) {
|
||||||
|
val songEntities = playlist.getSongs().map {
|
||||||
|
it.toSongEntity(playlistEntity.playListId)
|
||||||
|
}
|
||||||
|
repository.insertSongs(songEntities)
|
||||||
|
} else {
|
||||||
|
val playListId = createPlaylist(PlaylistEntity(playlist.name))
|
||||||
|
val songEntities = playlist.getSongs().map {
|
||||||
|
it.toSongEntity(playListId.toInt())
|
||||||
|
}
|
||||||
|
repository.insertSongs(songEntities)
|
||||||
|
}
|
||||||
|
forceReload(Playlists)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteTracks(songs: List<Song>) = viewModelScope.launch(IO) {
|
||||||
|
repository.deleteSongs(songs)
|
||||||
|
fetchPlaylists()
|
||||||
|
loadLibraryContent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ReloadType {
|
enum class ReloadType {
|
||||||
Songs,
|
Songs,
|
||||||
Albums,
|
Albums,
|
||||||
Artists,
|
Artists,
|
||||||
HomeSections
|
HomeSections,
|
||||||
|
Playlists,
|
||||||
|
Genres,
|
||||||
}
|
}
|
|
@ -11,18 +11,14 @@ import android.view.GestureDetector
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.*
|
||||||
import code.name.monkey.retromusic.extensions.textColorPrimary
|
|
||||||
import code.name.monkey.retromusic.extensions.textColorSecondary
|
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||||
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import code.name.monkey.retromusic.util.ViewUtil
|
|
||||||
import kotlinx.android.synthetic.main.fragment_mini_player.*
|
import kotlinx.android.synthetic.main.fragment_mini_player.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
@ -67,7 +63,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
|
||||||
|
|
||||||
private fun setUpMiniPlayer() {
|
private fun setUpMiniPlayer() {
|
||||||
setUpPlayPauseButton()
|
setUpPlayPauseButton()
|
||||||
ViewUtil.setProgressDrawable(progressBar, ThemeStore.accentColor(requireContext()))
|
progressBar.accentColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpPlayPauseButton() {
|
private fun setUpPlayPauseButton() {
|
||||||
|
@ -129,6 +125,10 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateProgressBar(paletteColor: Int) {
|
||||||
|
progressBar.applyColor(paletteColor)
|
||||||
|
}
|
||||||
|
|
||||||
class FlingPlayBackController(context: Context) : View.OnTouchListener {
|
class FlingPlayBackController(context: Context) : View.OnTouchListener {
|
||||||
|
|
||||||
private var flingPlayBackController: GestureDetector
|
private var flingPlayBackController: GestureDetector
|
||||||
|
|
|
@ -24,7 +24,6 @@ enum class NowPlayingScreen constructor(
|
||||||
Gradient(R.string.gradient, R.drawable.np_gradient, 17),
|
Gradient(R.string.gradient, R.drawable.np_gradient, 17),
|
||||||
Material(R.string.material, R.drawable.np_material, 11),
|
Material(R.string.material, R.drawable.np_material, 11),
|
||||||
Normal(R.string.normal, R.drawable.np_normal, 0),
|
Normal(R.string.normal, R.drawable.np_normal, 0),
|
||||||
|
|
||||||
//Peak(R.string.peak, R.drawable.np_peak, 14),
|
//Peak(R.string.peak, R.drawable.np_peak, 14),
|
||||||
Plain(R.string.plain, R.drawable.np_plain, 3),
|
Plain(R.string.plain, R.drawable.np_plain, 3),
|
||||||
Simple(R.string.simple, R.drawable.np_simple, 8),
|
Simple(R.string.simple, R.drawable.np_simple, 8),
|
||||||
|
|
|
@ -6,7 +6,9 @@ import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
@ -25,16 +27,20 @@ import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
||||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
||||||
import code.name.monkey.retromusic.extensions.applyColor
|
import code.name.monkey.retromusic.extensions.applyColor
|
||||||
|
import code.name.monkey.retromusic.extensions.applyOutlineColor
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.ArtistGlideRequest
|
import code.name.monkey.retromusic.glide.ArtistGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
|
import code.name.monkey.retromusic.glide.SingleColorTarget
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.SortOrder
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
import code.name.monkey.retromusic.model.Album
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
||||||
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
@ -42,6 +48,10 @@ import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import kotlinx.android.synthetic.main.fragment_album_content.*
|
import kotlinx.android.synthetic.main.fragment_album_content.*
|
||||||
import kotlinx.android.synthetic.main.fragment_album_details.*
|
import kotlinx.android.synthetic.main.fragment_album_details.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koin.core.parameter.parametersOf
|
import org.koin.core.parameter.parametersOf
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -66,23 +76,13 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
mainActivity.hideBottomBarVisibility(false)
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||||
mainActivity.setSupportActionBar(toolbar)
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
|
toolbar.title = " "
|
||||||
toolbar.title = null
|
|
||||||
|
|
||||||
postponeEnterTransition()
|
postponeEnterTransition()
|
||||||
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
|
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
|
||||||
showAlbum(it)
|
|
||||||
startPostponedEnterTransition()
|
startPostponedEnterTransition()
|
||||||
|
showAlbum(it)
|
||||||
})
|
})
|
||||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
|
||||||
loadArtistImage(it)
|
|
||||||
})
|
|
||||||
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
|
|
||||||
moreAlbums(it)
|
|
||||||
})
|
|
||||||
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, Observer {
|
|
||||||
aboutAlbum(it)
|
|
||||||
})
|
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
artistImage.setOnClickListener {
|
artistImage.setOnClickListener {
|
||||||
requireActivity().findNavController(R.id.fragment_container)
|
requireActivity().findNavController(R.id.fragment_container)
|
||||||
|
@ -140,14 +140,12 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
this.album = album
|
this.album = album
|
||||||
|
|
||||||
albumTitle.text = album.title
|
albumTitle.text = album.title
|
||||||
val songText =
|
val songText = resources.getQuantityString(
|
||||||
resources.getQuantityString(
|
R.plurals.albumSongs,
|
||||||
R.plurals.albumSongs,
|
album.songCount,
|
||||||
album.songCount,
|
album.songCount
|
||||||
album.songCount
|
)
|
||||||
)
|
|
||||||
songTitle.text = songText
|
songTitle.text = songText
|
||||||
|
|
||||||
if (MusicUtil.getYearString(album.year) == "-") {
|
if (MusicUtil.getYearString(album.year) == "-") {
|
||||||
albumText.text = String.format(
|
albumText.text = String.format(
|
||||||
"%s • %s",
|
"%s • %s",
|
||||||
|
@ -162,10 +160,25 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
|
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
loadAlbumCover()
|
loadAlbumCover(album)
|
||||||
simpleSongAdapter.swapDataSet(album.songs)
|
simpleSongAdapter.swapDataSet(album.songs)
|
||||||
detailsViewModel.loadArtist(album.artistId)
|
detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer {
|
||||||
detailsViewModel.loadAlbumInfo(album)
|
loadArtistImage(it)
|
||||||
|
})
|
||||||
|
|
||||||
|
detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner, Observer { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> {
|
||||||
|
println("Loading")
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
println("Error")
|
||||||
|
}
|
||||||
|
is Result.Success -> {
|
||||||
|
aboutAlbum(result.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moreAlbums(albums: List<Album>) {
|
private fun moreAlbums(albums: List<Album>) {
|
||||||
|
@ -191,7 +204,10 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
aboutAlbumTitle.show()
|
aboutAlbumTitle.show()
|
||||||
aboutAlbumTitle.text =
|
aboutAlbumTitle.text =
|
||||||
String.format(getString(R.string.about_album_label), lastFmAlbum.album.name)
|
String.format(getString(R.string.about_album_label), lastFmAlbum.album.name)
|
||||||
aboutAlbumText.text = lastFmAlbum.album.wiki.content
|
aboutAlbumText.text = HtmlCompat.fromHtml(
|
||||||
|
lastFmAlbum.album.wiki.content,
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (lastFmAlbum.album.listeners.isNotEmpty()) {
|
if (lastFmAlbum.album.listeners.isNotEmpty()) {
|
||||||
listeners.show()
|
listeners.show()
|
||||||
|
@ -206,7 +222,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadArtistImage(artist: Artist) {
|
private fun loadArtistImage(artist: Artist) {
|
||||||
|
detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner, Observer {
|
||||||
|
moreAlbums(it)
|
||||||
|
})
|
||||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||||
|
.forceDownload(PreferenceUtil.isAllowedToDownloadMetadata())
|
||||||
.generatePalette(requireContext())
|
.generatePalette(requireContext())
|
||||||
.build()
|
.build()
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
|
@ -217,24 +237,21 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAlbumCover() {
|
private fun loadAlbumCover(album: Album) {
|
||||||
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), album.safeGetFirstSong())
|
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), album.safeGetFirstSong())
|
||||||
.checkIgnoreMediaStore(requireContext())
|
.checkIgnoreMediaStore()
|
||||||
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
|
|
||||||
.generatePalette(requireContext())
|
.generatePalette(requireContext())
|
||||||
.build()
|
.build()
|
||||||
.dontAnimate()
|
.into(object : SingleColorTarget(image) {
|
||||||
.dontTransform()
|
override fun onColorReady(color: Int) {
|
||||||
.into(object : RetroMusicColoredTarget(image) {
|
setColors(color)
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
|
||||||
setColors(colors)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setColors(color: MediaNotificationProcessor) {
|
private fun setColors(color: Int) {
|
||||||
shuffleAction.applyColor(color.backgroundColor)
|
shuffleAction.applyColor(color)
|
||||||
playAction.applyColor(color.backgroundColor)
|
playAction.applyOutlineColor(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Int, view: View) {
|
||||||
|
@ -275,7 +292,13 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_playlist -> {
|
R.id.action_add_to_playlist -> {
|
||||||
AddToPlaylistDialog.create(songs).show(childFragmentManager, "ADD_PLAYLIST")
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val playlists = get<RealRepository>().fetchPlaylists()
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
AddToPlaylistDialog.create(playlists, songs)
|
||||||
|
.show(childFragmentManager, "ADD_PLAYLIST")
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_delete_from_device -> {
|
R.id.action_delete_from_device -> {
|
||||||
|
|
|
@ -1,64 +1,44 @@
|
||||||
package code.name.monkey.retromusic.fragments.albums
|
package code.name.monkey.retromusic.fragments.albums
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.liveData
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
import code.name.monkey.retromusic.model.Album
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class AlbumDetailsViewModel(
|
class AlbumDetailsViewModel(
|
||||||
private val realRepository: RealRepository,
|
private val realRepository: RealRepository,
|
||||||
private val albumId: Int
|
private val albumId: Int
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val _album = MutableLiveData<Album>()
|
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
||||||
private val _artist = MutableLiveData<Artist>()
|
val album = realRepository.albumByIdAsync(albumId)
|
||||||
private val _lastFmAlbum = MutableLiveData<LastFmAlbum>()
|
emit(album)
|
||||||
private val _moreAlbums = MutableLiveData<List<Album>>()
|
|
||||||
|
|
||||||
fun getAlbum(): LiveData<Album> = _album
|
|
||||||
fun getArtist(): LiveData<Artist> = _artist
|
|
||||||
fun getAlbumInfo(): LiveData<LastFmAlbum> = _lastFmAlbum
|
|
||||||
fun getMoreAlbums(): LiveData<List<Album>> = _moreAlbums;
|
|
||||||
|
|
||||||
init {
|
|
||||||
loadAlbumDetails()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAlbumDetails() = viewModelScope.launch {
|
fun getArtist(artistId: Int): LiveData<Artist> = liveData(IO) {
|
||||||
val album = loadAlbumAsync.await() ?: throw NullPointerException("Album couldn't found")
|
|
||||||
_album.postValue(album)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
val lastFmAlbum = realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-")
|
|
||||||
_lastFmAlbum.postValue(lastFmAlbum)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
val artist = realRepository.artistById(artistId)
|
val artist = realRepository.artistById(artistId)
|
||||||
_artist.postValue(artist)
|
emit(artist)
|
||||||
|
|
||||||
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
|
||||||
if (albums.isNotEmpty()) _moreAlbums.postValue(albums)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loadAlbumAsync: Deferred<Album?>
|
fun getAlbumInfo(album: Album): LiveData<Result<LastFmAlbum>> = liveData {
|
||||||
get() = viewModelScope.async(Dispatchers.IO) {
|
emit(Result.Loading)
|
||||||
realRepository.albumById(albumId)
|
emit( realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMoreAlbums(artist: Artist): LiveData<List<Album>> = liveData(IO) {
|
||||||
|
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
||||||
|
if (albums.isNotEmpty()) emit(albums)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
loadAlbumDetails()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {}
|
override fun onServiceConnected() {}
|
||||||
|
|
|
@ -1,26 +1,29 @@
|
||||||
package code.name.monkey.retromusic.fragments.albums
|
package code.name.monkey.retromusic.fragments.albums
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.*
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.navigation.findNavController
|
|
||||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
||||||
|
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
|
||||||
class AlbumsFragment :
|
|
||||||
AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||||
AlbumClickListener {
|
AlbumClickListener {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.albumsLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.getAlbums().observe(viewLifecycleOwner, Observer {
|
||||||
if (it.isNotEmpty())
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(it)
|
adapter?.swapDataSet(it)
|
||||||
else
|
else
|
||||||
|
@ -95,8 +98,7 @@ class AlbumsFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Int, view: View) {
|
||||||
val controller = requireActivity().findNavController(R.id.fragment_container)
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
controller.navigate(
|
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||||
null,
|
null,
|
||||||
|
@ -105,6 +107,181 @@ class AlbumsFragment :
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
|
||||||
|
if (RetroUtil.isLandscape()) {
|
||||||
|
gridSizeItem.setTitle(R.string.action_grid_size_land)
|
||||||
|
}
|
||||||
|
setUpGridSizeMenu(gridSizeItem.subMenu)
|
||||||
|
val layoutItem = menu.findItem(R.id.action_layout_type)
|
||||||
|
setupLayoutMenu(layoutItem.subMenu)
|
||||||
|
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpSortOrderMenu(
|
||||||
|
sortOrderMenu: SubMenu
|
||||||
|
) {
|
||||||
|
val currentSortOrder: String? = getSortOrder()
|
||||||
|
sortOrderMenu.clear()
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_asc,
|
||||||
|
0,
|
||||||
|
R.string.sort_order_a_z
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_A_Z)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_desc,
|
||||||
|
1,
|
||||||
|
R.string.sort_order_z_a
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_Z_A)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_artist,
|
||||||
|
2,
|
||||||
|
R.string.sort_order_artist
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_ARTIST)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_year,
|
||||||
|
3,
|
||||||
|
R.string.sort_order_year
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_YEAR)
|
||||||
|
|
||||||
|
sortOrderMenu.setGroupCheckable(0, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLayoutMenu(
|
||||||
|
subMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (itemLayoutRes()) {
|
||||||
|
R.layout.item_card -> subMenu.findItem(R.id.action_layout_card).isChecked = true
|
||||||
|
R.layout.item_grid -> subMenu.findItem(R.id.action_layout_normal).isChecked = true
|
||||||
|
R.layout.item_card_color ->
|
||||||
|
subMenu.findItem(R.id.action_layout_colored_card).isChecked = true
|
||||||
|
R.layout.item_grid_circle ->
|
||||||
|
subMenu.findItem(R.id.action_layout_circular).isChecked = true
|
||||||
|
R.layout.image -> subMenu.findItem(R.id.action_layout_image).isChecked = true
|
||||||
|
R.layout.item_image_gradient ->
|
||||||
|
subMenu.findItem(R.id.action_layout_gradient_image).isChecked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpGridSizeMenu(
|
||||||
|
gridSizeMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (getGridSize()) {
|
||||||
|
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked =
|
||||||
|
true
|
||||||
|
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
|
||||||
|
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
|
||||||
|
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
|
||||||
|
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
|
||||||
|
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
|
||||||
|
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
|
||||||
|
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
|
||||||
|
}
|
||||||
|
val gridSize: Int = maxGridSize
|
||||||
|
if (gridSize < 8) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 7) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 6) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 5) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 4) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 3) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (handleGridSizeMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleLayoutResType(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleSortOrderMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSortOrderMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var sortOrder: String? = null
|
||||||
|
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_album_sort_order_asc -> sortOrder = AlbumSortOrder.ALBUM_A_Z
|
||||||
|
R.id.action_album_sort_order_desc -> sortOrder = AlbumSortOrder.ALBUM_Z_A
|
||||||
|
R.id.action_album_sort_order_artist -> sortOrder = AlbumSortOrder.ALBUM_ARTIST
|
||||||
|
R.id.action_album_sort_order_year -> sortOrder = AlbumSortOrder.ALBUM_YEAR
|
||||||
|
}
|
||||||
|
if (sortOrder != null) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveSortOrder(sortOrder)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLayoutResType(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var layoutRes = -1
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_layout_normal -> layoutRes = R.layout.item_grid
|
||||||
|
R.id.action_layout_card -> layoutRes = R.layout.item_card
|
||||||
|
R.id.action_layout_colored_card -> layoutRes = R.layout.item_card_color
|
||||||
|
R.id.action_layout_circular -> layoutRes = R.layout.item_grid_circle
|
||||||
|
R.id.action_layout_image -> layoutRes = R.layout.image
|
||||||
|
R.id.action_layout_gradient_image -> layoutRes = R.layout.item_image_gradient
|
||||||
|
}
|
||||||
|
if (layoutRes != -1) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveLayoutRes(layoutRes)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleGridSizeMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var gridSize = 0
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_grid_size_1 -> gridSize = 1
|
||||||
|
R.id.action_grid_size_2 -> gridSize = 2
|
||||||
|
R.id.action_grid_size_3 -> gridSize = 3
|
||||||
|
R.id.action_grid_size_4 -> gridSize = 4
|
||||||
|
R.id.action_grid_size_5 -> gridSize = 5
|
||||||
|
R.id.action_grid_size_6 -> gridSize = 6
|
||||||
|
R.id.action_grid_size_7 -> gridSize = 7
|
||||||
|
R.id.action_grid_size_8 -> gridSize = 8
|
||||||
|
}
|
||||||
|
if (gridSize > 0) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveGridSize(gridSize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AlbumClickListener {
|
interface AlbumClickListener {
|
||||||
|
|
|
@ -10,33 +10,43 @@ import android.view.View
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
|
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
|
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
|
||||||
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
||||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||||
import code.name.monkey.retromusic.extensions.applyColor
|
import code.name.monkey.retromusic.extensions.applyColor
|
||||||
|
import code.name.monkey.retromusic.extensions.applyOutlineColor
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.extensions.showToast
|
import code.name.monkey.retromusic.extensions.showToast
|
||||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import code.name.monkey.retromusic.glide.ArtistGlideRequest
|
import code.name.monkey.retromusic.glide.ArtistGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.SingleColorTarget
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||||
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
||||||
import kotlinx.android.synthetic.main.fragment_artist_details.*
|
import kotlinx.android.synthetic.main.fragment_artist_details.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koin.core.parameter.parametersOf
|
import org.koin.core.parameter.parametersOf
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -66,13 +76,10 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
postponeEnterTransition()
|
postponeEnterTransition()
|
||||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||||
|
|
||||||
showArtist(it)
|
showArtist(it)
|
||||||
startPostponedEnterTransition()
|
startPostponedEnterTransition()
|
||||||
})
|
})
|
||||||
detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
|
|
||||||
artistInfo(it)
|
|
||||||
})
|
|
||||||
|
|
||||||
playAction.apply {
|
playAction.apply {
|
||||||
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
||||||
|
@ -133,6 +140,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
albumTitle.text = albumText
|
albumTitle.text = albumText
|
||||||
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
||||||
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadBiography(
|
private fun loadBiography(
|
||||||
|
@ -141,7 +149,14 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
) {
|
) {
|
||||||
biography = null
|
biography = null
|
||||||
this.lang = lang
|
this.lang = lang
|
||||||
detailsViewModel.loadBiography(name, lang, null)
|
detailsViewModel.getArtistInfo(name, lang, null)
|
||||||
|
.observe(viewLifecycleOwner, Observer { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> println("Loading")
|
||||||
|
is Result.Error -> println("Error")
|
||||||
|
is Result.Success -> artistInfo(result.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun artistInfo(lastFmArtist: LastFmArtist?) {
|
private fun artistInfo(lastFmArtist: LastFmArtist?) {
|
||||||
|
@ -175,23 +190,26 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
private fun loadArtistImage(artist: Artist) {
|
private fun loadArtistImage(artist: Artist) {
|
||||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||||
.generatePalette(requireContext()).build()
|
.generatePalette(requireContext()).build()
|
||||||
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
|
.dontAnimate()
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
.into(object : SingleColorTarget(image) {
|
||||||
startPostponedEnterTransition()
|
override fun onColorReady(color: Int) {
|
||||||
setColors(colors)
|
setColors(color)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setColors(color: MediaNotificationProcessor) {
|
private fun setColors(color: Int) {
|
||||||
shuffleAction.applyColor(color.backgroundColor)
|
val finalColor = if (PreferenceUtil.isAdaptiveColor) color
|
||||||
playAction.applyColor(color.backgroundColor)
|
else ThemeStore.accentColor(requireContext())
|
||||||
|
shuffleAction.applyColor(finalColor)
|
||||||
|
playAction.applyOutlineColor(finalColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onAlbumClick(albumId: Int, view: View) {
|
override fun onAlbumClick(albumId: Int, view: View) {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf("extra_album_id" to albumId),
|
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||||
null,
|
null,
|
||||||
FragmentNavigatorExtras(
|
FragmentNavigatorExtras(
|
||||||
view to getString(R.string.transition_album_art)
|
view to getString(R.string.transition_album_art)
|
||||||
|
@ -216,7 +234,13 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_playlist -> {
|
R.id.action_add_to_playlist -> {
|
||||||
AddToPlaylistDialog.create(songs).show(childFragmentManager, "ADD_PLAYLIST")
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val playlists = get<RealRepository>().fetchPlaylists()
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
AddToPlaylistDialog.create(playlists, songs)
|
||||||
|
.show(childFragmentManager, "ADD_PLAYLIST")
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_set_artist_image -> {
|
R.id.action_set_artist_image -> {
|
||||||
|
|
|
@ -1,51 +1,37 @@
|
||||||
package code.name.monkey.retromusic.fragments.artists
|
package code.name.monkey.retromusic.fragments.artists
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.liveData
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||||
import kotlinx.coroutines.Deferred
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class ArtistDetailsViewModel(
|
class ArtistDetailsViewModel(
|
||||||
private val realRepository: RealRepository,
|
private val realRepository: RealRepository,
|
||||||
private val artistId: Int
|
private val artistId: Int
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val loadArtistDetailsAsync: Deferred<Artist?>
|
fun getArtist(): LiveData<Artist> = liveData(IO) {
|
||||||
get() = viewModelScope.async(Dispatchers.IO) {
|
val artist = realRepository.artistById(artistId)
|
||||||
realRepository.artistById(artistId)
|
emit(artist)
|
||||||
}
|
|
||||||
|
|
||||||
private val _artist = MutableLiveData<Artist>()
|
|
||||||
private val _lastFmArtist = MutableLiveData<LastFmArtist>()
|
|
||||||
|
|
||||||
fun getArtist(): LiveData<Artist> = _artist
|
|
||||||
fun getArtistInfo(): LiveData<LastFmArtist> = _lastFmArtist
|
|
||||||
|
|
||||||
init {
|
|
||||||
loadArtistDetails()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadArtistDetails() = viewModelScope.launch {
|
fun getArtistInfo(
|
||||||
val artist =
|
name: String,
|
||||||
loadArtistDetailsAsync.await() ?: throw NullPointerException("Album couldn't found")
|
lang: String?,
|
||||||
_artist.postValue(artist)
|
cache: String?
|
||||||
}
|
): LiveData<Result<LastFmArtist>> = liveData(IO) {
|
||||||
|
emit(Result.Loading)
|
||||||
fun loadBiography(name: String, lang: String?, cache: String?) = viewModelScope.launch {
|
|
||||||
val info = realRepository.artistInfo(name, lang, cache)
|
val info = realRepository.artistInfo(name, lang, cache)
|
||||||
_lastFmArtist.postValue(info)
|
emit(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
loadArtistDetails()
|
getArtist()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {}
|
override fun onServiceConnected() {}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package code.name.monkey.retromusic.fragments.artists
|
package code.name.monkey.retromusic.fragments.artists
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.*
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
@ -12,21 +12,17 @@ import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
||||||
import code.name.monkey.retromusic.extensions.findActivityNavController
|
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
|
||||||
class ArtistsFragment :
|
|
||||||
AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
|
||||||
MainActivityFragmentCallbacks, ArtistClickListener {
|
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||||
|
ArtistClickListener {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.artistsLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.getArtists().observe(viewLifecycleOwner, Observer {
|
||||||
if (it.isNotEmpty())
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(it)
|
adapter?.swapDataSet(it)
|
||||||
else
|
else
|
||||||
|
@ -104,6 +100,161 @@ class ArtistsFragment :
|
||||||
val controller = findActivityNavController(R.id.fragment_container)
|
val controller = findActivityNavController(R.id.fragment_container)
|
||||||
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
|
||||||
|
if (RetroUtil.isLandscape()) {
|
||||||
|
gridSizeItem.setTitle(R.string.action_grid_size_land)
|
||||||
|
}
|
||||||
|
setUpGridSizeMenu(gridSizeItem.subMenu)
|
||||||
|
val layoutItem = menu.findItem(R.id.action_layout_type)
|
||||||
|
setupLayoutMenu(layoutItem.subMenu)
|
||||||
|
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpSortOrderMenu(
|
||||||
|
sortOrderMenu: SubMenu
|
||||||
|
) {
|
||||||
|
val currentSortOrder: String? = getSortOrder()
|
||||||
|
sortOrderMenu.clear()
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_artist_sort_order_asc,
|
||||||
|
0,
|
||||||
|
R.string.sort_order_a_z
|
||||||
|
).isChecked = currentSortOrder.equals(ArtistSortOrder.ARTIST_A_Z)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_artist_sort_order_desc,
|
||||||
|
1,
|
||||||
|
R.string.sort_order_z_a
|
||||||
|
).isChecked = currentSortOrder.equals(ArtistSortOrder.ARTIST_Z_A)
|
||||||
|
sortOrderMenu.setGroupCheckable(0, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLayoutMenu(
|
||||||
|
subMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (itemLayoutRes()) {
|
||||||
|
R.layout.item_card -> subMenu.findItem(R.id.action_layout_card).isChecked = true
|
||||||
|
R.layout.item_grid -> subMenu.findItem(R.id.action_layout_normal).isChecked = true
|
||||||
|
R.layout.item_card_color ->
|
||||||
|
subMenu.findItem(R.id.action_layout_colored_card).isChecked = true
|
||||||
|
R.layout.item_grid_circle ->
|
||||||
|
subMenu.findItem(R.id.action_layout_circular).isChecked = true
|
||||||
|
R.layout.image -> subMenu.findItem(R.id.action_layout_image).isChecked = true
|
||||||
|
R.layout.item_image_gradient ->
|
||||||
|
subMenu.findItem(R.id.action_layout_gradient_image).isChecked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpGridSizeMenu(
|
||||||
|
gridSizeMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (getGridSize()) {
|
||||||
|
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked =
|
||||||
|
true
|
||||||
|
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
|
||||||
|
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
|
||||||
|
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
|
||||||
|
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
|
||||||
|
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
|
||||||
|
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
|
||||||
|
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
|
||||||
|
}
|
||||||
|
val gridSize: Int = maxGridSize
|
||||||
|
if (gridSize < 8) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 7) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 6) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 5) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 4) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 3) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (handleGridSizeMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleLayoutResType(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleSortOrderMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSortOrderMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var sortOrder: String? = null
|
||||||
|
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_artist_sort_order_asc -> sortOrder = ArtistSortOrder.ARTIST_A_Z
|
||||||
|
R.id.action_artist_sort_order_desc -> sortOrder = ArtistSortOrder.ARTIST_Z_A
|
||||||
|
}
|
||||||
|
if (sortOrder != null) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveSortOrder(sortOrder)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLayoutResType(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var layoutRes = -1
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_layout_normal -> layoutRes = R.layout.item_grid
|
||||||
|
R.id.action_layout_card -> layoutRes = R.layout.item_card
|
||||||
|
R.id.action_layout_colored_card -> layoutRes = R.layout.item_card_color
|
||||||
|
R.id.action_layout_circular -> layoutRes = R.layout.item_grid_circle
|
||||||
|
R.id.action_layout_image -> layoutRes = R.layout.image
|
||||||
|
R.id.action_layout_gradient_image -> layoutRes = R.layout.item_image_gradient
|
||||||
|
}
|
||||||
|
if (layoutRes != -1) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveLayoutRes(layoutRes)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleGridSizeMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var gridSize = 0
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_grid_size_1 -> gridSize = 1
|
||||||
|
R.id.action_grid_size_2 -> gridSize = 2
|
||||||
|
R.id.action_grid_size_3 -> gridSize = 3
|
||||||
|
R.id.action_grid_size_4 -> gridSize = 4
|
||||||
|
R.id.action_grid_size_5 -> gridSize = 5
|
||||||
|
R.id.action_grid_size_6 -> gridSize = 6
|
||||||
|
R.id.action_grid_size_7 -> gridSize = 7
|
||||||
|
R.id.action_grid_size_8 -> gridSize = 8
|
||||||
|
}
|
||||||
|
if (gridSize > 0) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveGridSize(gridSize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ArtistClickListener {
|
interface ArtistClickListener {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package code.name.monkey.retromusic.fragments.base
|
package code.name.monkey.retromusic.fragments.base
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.os.AsyncTask
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
|
@ -15,30 +14,40 @@ import android.widget.Toast
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||||
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
||||||
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
import code.name.monkey.retromusic.dialogs.*
|
import code.name.monkey.retromusic.dialogs.*
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
|
import code.name.monkey.retromusic.extensions.whichFragment
|
||||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
|
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.model.lyrics.Lyrics
|
import code.name.monkey.retromusic.model.lyrics.Lyrics
|
||||||
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
|
import code.name.monkey.retromusic.service.MusicService
|
||||||
import code.name.monkey.retromusic.util.*
|
import code.name.monkey.retromusic.util.*
|
||||||
import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
|
import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
|
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
|
||||||
Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
|
Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
|
||||||
|
|
||||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
|
||||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
|
||||||
private var playerAlbumCoverFragment: PlayerAlbumCoverFragment? = null
|
private var playerAlbumCoverFragment: PlayerAlbumCoverFragment? = null
|
||||||
protected val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
protected val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||||
|
|
||||||
|
@ -64,7 +73,13 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_playlist -> {
|
R.id.action_add_to_playlist -> {
|
||||||
AddToPlaylistDialog.create(song).show(childFragmentManager, "ADD_PLAYLIST")
|
lifecycleScope.launch(IO) {
|
||||||
|
val playlists = get<RealRepository>().fetchPlaylists()
|
||||||
|
withContext(Main) {
|
||||||
|
AddToPlaylistDialog.create(playlists, song)
|
||||||
|
.show(childFragmentManager, "ADD_PLAYLIST")
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_clear_playing_queue -> {
|
R.id.action_clear_playing_queue -> {
|
||||||
|
@ -146,9 +161,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun toggleFavorite(song: Song) {
|
|
||||||
MusicUtil.toggleFavorite(requireActivity(), song)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun playerToolbar(): Toolbar?
|
abstract fun playerToolbar(): Toolbar?
|
||||||
|
|
||||||
|
@ -170,79 +182,70 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
updateLyrics()
|
updateLyrics()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
protected open fun toggleFavorite(song: Song) {
|
||||||
if (updateIsFavoriteTask != null && !updateIsFavoriteTask!!.isCancelled) {
|
lifecycleScope.launch(IO) {
|
||||||
updateIsFavoriteTask!!.cancel(true)
|
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||||
}
|
if (playlist != null) {
|
||||||
if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) {
|
val songEntity = song.toSongEntity(playlist.playListId)
|
||||||
updateLyricsAsyncTask!!.cancel(true)
|
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
||||||
}
|
if (isFavorite) {
|
||||||
super.onDestroyView()
|
libraryViewModel.removeSongFromPlaylist(songEntity)
|
||||||
}
|
} else {
|
||||||
|
libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
fun updateIsFavorite() {
|
|
||||||
if (updateIsFavoriteTask != null) {
|
|
||||||
updateIsFavoriteTask!!.cancel(false)
|
|
||||||
}
|
|
||||||
updateIsFavoriteTask = object : AsyncTask<Song, Void, Boolean>() {
|
|
||||||
override fun doInBackground(vararg params: Song): Boolean {
|
|
||||||
return MusicUtil.isFavorite(requireActivity(), params[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostExecute(isFavorite: Boolean) {
|
|
||||||
val res = if (isFavorite)
|
|
||||||
R.drawable.ic_favorite
|
|
||||||
else
|
|
||||||
R.drawable.ic_favorite_border
|
|
||||||
|
|
||||||
val drawable =
|
|
||||||
RetroUtil.getTintedVectorDrawable(requireContext(), res, toolbarIconColor())
|
|
||||||
if (playerToolbar() != null && playerToolbar()!!.menu.findItem(R.id.action_toggle_favorite) != null)
|
|
||||||
playerToolbar()!!.menu.findItem(R.id.action_toggle_favorite).setIcon(drawable)
|
|
||||||
.title =
|
|
||||||
if (isFavorite) getString(R.string.action_remove_from_favorites) else getString(
|
|
||||||
R.string.action_add_to_favorites
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}.execute(MusicPlayerRemote.currentSong)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private fun updateLyrics() {
|
|
||||||
if (updateLyricsAsyncTask != null) updateLyricsAsyncTask!!.cancel(false)
|
|
||||||
|
|
||||||
updateLyricsAsyncTask = object : AsyncTask<Song, Void, Lyrics>() {
|
|
||||||
override fun onPreExecute() {
|
|
||||||
super.onPreExecute()
|
|
||||||
setLyrics(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Song): Lyrics? {
|
|
||||||
try {
|
|
||||||
var data: String? =
|
|
||||||
LyricUtil.getStringFromFile(params[0].title, params[0].artistName)
|
|
||||||
return if (TextUtils.isEmpty(data)) {
|
|
||||||
data = MusicUtil.getLyrics(params[0])
|
|
||||||
return if (TextUtils.isEmpty(data)) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
Lyrics.parse(params[0], data)
|
|
||||||
}
|
|
||||||
} else Lyrics.parse(params[0], data!!)
|
|
||||||
} catch (err: FileNotFoundException) {
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||||
|
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPostExecute(l: Lyrics?) {
|
fun updateIsFavorite() {
|
||||||
setLyrics(l)
|
lifecycleScope.launch(IO) {
|
||||||
|
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||||
|
if (playlist != null) {
|
||||||
|
val song: SongEntity =
|
||||||
|
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||||
|
val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty()
|
||||||
|
withContext(Main) {
|
||||||
|
val icon =
|
||||||
|
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
||||||
|
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
|
||||||
|
requireContext(),
|
||||||
|
icon,
|
||||||
|
toolbarIconColor()
|
||||||
|
)
|
||||||
|
if (playerToolbar() != null) {
|
||||||
|
playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite)
|
||||||
|
?.setIcon(drawable)?.title =
|
||||||
|
if (isFavorite) getString(R.string.action_remove_from_favorites)
|
||||||
|
else getString(R.string.action_add_to_favorites)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCancelled(s: Lyrics?) {
|
private fun updateLyrics() {
|
||||||
onPostExecute(null)
|
setLyrics(null)
|
||||||
|
lifecycleScope.launch(IO) {
|
||||||
|
val song = MusicPlayerRemote.currentSong
|
||||||
|
val lyrics = try {
|
||||||
|
var data: String? = LyricUtil.getStringFromFile(song.title, song.artistName)
|
||||||
|
if (TextUtils.isEmpty(data)) {
|
||||||
|
data = MusicUtil.getLyrics(song)
|
||||||
|
if (TextUtils.isEmpty(data)) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
Lyrics.parse(song, data)
|
||||||
|
}
|
||||||
|
} else Lyrics.parse(song, data!!)
|
||||||
|
} catch (err: FileNotFoundException) {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
}.execute(MusicPlayerRemote.currentSong)
|
withContext(Main) {
|
||||||
|
setLyrics(lyrics)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setLyrics(l: Lyrics?) {
|
open fun setLyrics(l: Lyrics?) {
|
||||||
|
@ -255,8 +258,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
) {
|
) {
|
||||||
view.findViewById<View>(R.id.status_bar).visibility = View.GONE
|
view.findViewById<View>(R.id.status_bar).visibility = View.GONE
|
||||||
}
|
}
|
||||||
playerAlbumCoverFragment =
|
playerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
||||||
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment?
|
|
||||||
playerAlbumCoverFragment?.setCallbacks(this)
|
playerAlbumCoverFragment?.setCallbacks(this)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
|
|
|
@ -290,7 +290,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startIndex > -1) {
|
if (startIndex > -1) {
|
||||||
MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true);
|
MusicPlayerRemote.openQueue(songs, startIndex, true);
|
||||||
} else {
|
} else {
|
||||||
final File finalFile = file1;
|
final File finalFile = file1;
|
||||||
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
||||||
|
|
|
@ -36,7 +36,7 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
|
||||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||||
mainActivity.setSupportActionBar(toolbar)
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
mainActivity.hideBottomBarVisibility(false)
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
|
progressIndicator.hide()
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
detailsViewModel.getSongs().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
detailsViewModel.getSongs().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||||
songs(it)
|
songs(it)
|
||||||
|
|
|
@ -21,18 +21,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.GenreAdapter
|
import code.name.monkey.retromusic.adapter.GenreAdapter
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
|
||||||
|
|
||||||
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
|
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>() {
|
||||||
MainActivityFragmentCallbacks {
|
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.genresLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.getGenre().observe(viewLifecycleOwner, Observer {
|
||||||
if (it.isNotEmpty())
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(it)
|
adapter?.swapDataSet(it)
|
||||||
else
|
else
|
||||||
|
|
|
@ -16,50 +16,36 @@ package code.name.monkey.retromusic.fragments.home
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
import android.app.ActivityOptions
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.findNavController
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
import code.name.monkey.retromusic.HISTORY_PLAYLIST
|
||||||
|
import code.name.monkey.retromusic.LAST_ADDED_PLAYLIST
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.TOP_PLAYED_PLAYLIST
|
||||||
import code.name.monkey.retromusic.adapter.HomeAdapter
|
import code.name.monkey.retromusic.adapter.HomeAdapter
|
||||||
import code.name.monkey.retromusic.extensions.findActivityNavController
|
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest
|
import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.UserProfileGlideRequest
|
import code.name.monkey.retromusic.glide.UserProfileGlideRequest
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
|
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.TopTracksPlaylist
|
|
||||||
import code.name.monkey.retromusic.repository.Repository
|
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import kotlinx.android.synthetic.main.abs_playlists.*
|
import kotlinx.android.synthetic.main.abs_playlists.*
|
||||||
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
||||||
import kotlinx.android.synthetic.main.home_content.*
|
import kotlinx.android.synthetic.main.home_content.*
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.android.ext.android.inject
|
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class HomeFragment :
|
class HomeFragment :
|
||||||
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
|
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
|
||||||
|
|
||||||
private val repository by inject<Repository>()
|
|
||||||
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||||
|
|
||||||
private val displayMetrics: DisplayMetrics
|
|
||||||
get() {
|
|
||||||
val display = mainActivity.windowManager.defaultDisplay
|
|
||||||
val metrics = DisplayMetrics()
|
|
||||||
display.getMetrics(metrics)
|
|
||||||
return metrics
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setStatusBarColorAuto(view)
|
setStatusBarColorAuto(view)
|
||||||
|
@ -74,31 +60,26 @@ class HomeFragment :
|
||||||
|
|
||||||
lastAdded.setOnClickListener {
|
lastAdded.setOnClickListener {
|
||||||
findActivityNavController(R.id.fragment_container).navigate(
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
R.id.playlistDetailsFragment,
|
R.id.detailListFragment,
|
||||||
bundleOf(EXTRA_PLAYLIST to LastAddedPlaylist())
|
bundleOf("type" to LAST_ADDED_PLAYLIST)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
topPlayed.setOnClickListener {
|
topPlayed.setOnClickListener {
|
||||||
findActivityNavController(R.id.fragment_container).navigate(
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
R.id.playlistDetailsFragment,
|
R.id.detailListFragment,
|
||||||
bundleOf(EXTRA_PLAYLIST to TopTracksPlaylist())
|
bundleOf("type" to TOP_PLAYED_PLAYLIST)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
actionShuffle.setOnClickListener {
|
actionShuffle.setOnClickListener {
|
||||||
lifecycleScope.launch {
|
libraryViewModel.shuffleSongs()
|
||||||
MusicPlayerRemote.openAndShuffleQueue(
|
|
||||||
repository.allSongs(),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
history.setOnClickListener {
|
history.setOnClickListener {
|
||||||
requireActivity().findNavController(R.id.fragment_container).navigate(
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
R.id.playlistDetailsFragment,
|
R.id.detailListFragment,
|
||||||
bundleOf(EXTRA_PLAYLIST to HistoryPlaylist())
|
bundleOf("type" to HISTORY_PLAYLIST)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +99,7 @@ class HomeFragment :
|
||||||
adapter = homeAdapter
|
adapter = homeAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryViewModel.homeLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.getHome().observe(viewLifecycleOwner, Observer {
|
||||||
homeAdapter.swapData(it)
|
homeAdapter.swapData(it)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -138,6 +119,14 @@ class HomeFragment :
|
||||||
).build().into(userImage)
|
).build().into(userImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
menu.removeItem(R.id.action_grid_size)
|
||||||
|
menu.removeItem(R.id.action_layout_type)
|
||||||
|
menu.removeItem(R.id.action_sort_order)
|
||||||
|
menu.findItem(R.id.action_settings).setShowAsAction(SHOW_AS_ACTION_IF_ROOM)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val TAG: String = "BannerHomeFragment"
|
const val TAG: String = "BannerHomeFragment"
|
||||||
|
|
|
@ -4,21 +4,26 @@ import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.ui.NavigationUI
|
import androidx.navigation.ui.NavigationUI
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
|
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
|
||||||
|
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
|
||||||
import code.name.monkey.retromusic.extensions.findNavController
|
import code.name.monkey.retromusic.extensions.findNavController
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
|
||||||
import kotlinx.android.synthetic.main.fragment_library.*
|
import kotlinx.android.synthetic.main.fragment_library.*
|
||||||
|
import java.lang.String
|
||||||
|
|
||||||
class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
|
retainInstance = true
|
||||||
mainActivity.hideBottomBarVisibility(true)
|
mainActivity.hideBottomBarVisibility(true)
|
||||||
mainActivity.setSupportActionBar(toolbar)
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
mainActivity.supportActionBar?.title = null
|
mainActivity.supportActionBar?.title = null
|
||||||
|
@ -30,6 +35,17 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
setupNavigationController()
|
setupNavigationController()
|
||||||
|
setupTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupTitle() {
|
||||||
|
val color = ThemeStore.accentColor(requireContext())
|
||||||
|
val hexColor = String.format("#%06X", 0xFFFFFF and color)
|
||||||
|
val appName = HtmlCompat.fromHtml(
|
||||||
|
"Retro <span style='color:$hexColor';>Music</span>",
|
||||||
|
HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||||
|
)
|
||||||
|
appNameText.text = appName
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupNavigationController() {
|
private fun setupNavigationController() {
|
||||||
|
@ -60,19 +76,15 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
||||||
null,
|
null,
|
||||||
navOptions
|
navOptions
|
||||||
)
|
)
|
||||||
|
R.id.action_import_playlist -> ImportPlaylistDialog().show(
|
||||||
|
childFragmentManager,
|
||||||
|
"ImportPlaylist"
|
||||||
|
)
|
||||||
|
R.id.action_add_to_playlist -> CreatePlaylistDialog.create(emptyList()).show(
|
||||||
|
childFragmentManager,
|
||||||
|
"ShowCreatePlaylistDialog"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addOnAppBarOffsetChangedListener(changedListener: AppBarLayout.OnOffsetChangedListener) {
|
|
||||||
appBarLayout.addOnOffsetChangedListener(changedListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeOnAppBarOffsetChangedListener(changedListener: AppBarLayout.OnOffsetChangedListener) {
|
|
||||||
appBarLayout.removeOnOffsetChangedListener(changedListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTotalAppBarScrollingRange(): Int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -20,7 +20,6 @@ import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||||
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
|
||||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
|
@ -69,9 +68,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
|
||||||
|
|
||||||
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
.setAllowDragging(false)
|
|
||||||
|
|
||||||
playerQueueSheet.setContentPadding(
|
playerQueueSheet.setContentPadding(
|
||||||
playerQueueSheet.contentPaddingLeft,
|
playerQueueSheet.contentPaddingLeft,
|
||||||
(slideOffset * status_bar.height).toInt(),
|
(slideOffset * status_bar.height).toInt(),
|
||||||
|
@ -83,18 +80,17 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||||
val activity = requireActivity() as AbsSlidingMusicPanelActivity
|
|
||||||
when (newState) {
|
when (newState) {
|
||||||
BottomSheetBehavior.STATE_EXPANDED,
|
BottomSheetBehavior.STATE_EXPANDED,
|
||||||
BottomSheetBehavior.STATE_DRAGGING -> {
|
BottomSheetBehavior.STATE_DRAGGING -> {
|
||||||
activity.getBottomSheetBehavior().setAllowDragging(false)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
}
|
}
|
||||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||||
resetToCurrentPosition()
|
resetToCurrentPosition()
|
||||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,8 +128,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
|
||||||
playerQueueSheet.background = shapeDrawable
|
playerQueueSheet.background = shapeDrawable
|
||||||
|
|
||||||
playerQueueSheet.setOnTouchListener { _, _ ->
|
playerQueueSheet.setOnTouchListener { _, _ ->
|
||||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
.setAllowDragging(false)
|
|
||||||
getQueuePanel().setAllowDragging(true)
|
getQueuePanel().setAllowDragging(true)
|
||||||
return@setOnTouchListener false
|
return@setOnTouchListener false
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@ package code.name.monkey.retromusic.fragments.player.fit
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.animation.AccelerateInterpolator
|
import android.view.animation.AccelerateInterpolator
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
|
@ -26,7 +24,6 @@ import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
||||||
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
|
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
|
||||||
import code.name.monkey.retromusic.service.MusicService
|
import code.name.monkey.retromusic.service.MusicService
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import kotlinx.android.synthetic.main.fragment_fit_playback_controls.*
|
import kotlinx.android.synthetic.main.fragment_fit_playback_controls.*
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.annotation.SuppressLint
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.os.AsyncTask
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.LinearInterpolator
|
import android.view.animation.LinearInterpolator
|
||||||
|
@ -18,10 +17,8 @@ import androidx.core.view.ViewCompat
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||||
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
|
||||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.ripAlpha
|
import code.name.monkey.retromusic.extensions.ripAlpha
|
||||||
|
@ -62,14 +59,11 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
|
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
|
||||||
private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
|
private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
|
||||||
private var playingQueueAdapter: PlayingQueueAdapter? = null
|
private var playingQueueAdapter: PlayingQueueAdapter? = null
|
||||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
|
||||||
private lateinit var linearLayoutManager: LinearLayoutManager
|
private lateinit var linearLayoutManager: LinearLayoutManager
|
||||||
|
|
||||||
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
.setAllowDragging(false)
|
|
||||||
|
|
||||||
playerQueueSheet.setPadding(
|
playerQueueSheet.setPadding(
|
||||||
playerQueueSheet.paddingLeft,
|
playerQueueSheet.paddingLeft,
|
||||||
(slideOffset * status_bar.height).toInt(),
|
(slideOffset * status_bar.height).toInt(),
|
||||||
|
@ -79,18 +73,17 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||||
val activity = requireActivity() as AbsSlidingMusicPanelActivity
|
|
||||||
when (newState) {
|
when (newState) {
|
||||||
BottomSheetBehavior.STATE_EXPANDED,
|
BottomSheetBehavior.STATE_EXPANDED,
|
||||||
BottomSheetBehavior.STATE_DRAGGING -> {
|
BottomSheetBehavior.STATE_DRAGGING -> {
|
||||||
activity.getBottomSheetBehavior().setAllowDragging(false)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
}
|
}
|
||||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||||
resetToCurrentPosition()
|
resetToCurrentPosition()
|
||||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,8 +132,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
private fun setupSheet() {
|
private fun setupSheet() {
|
||||||
getQueuePanel().addBottomSheetCallback(bottomSheetCallbackList)
|
getQueuePanel().addBottomSheetCallback(bottomSheetCallbackList)
|
||||||
playerQueueSheet.setOnTouchListener { _, _ ->
|
playerQueueSheet.setOnTouchListener { _, _ ->
|
||||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||||
.setAllowDragging(false)
|
|
||||||
getQueuePanel().setAllowDragging(true)
|
getQueuePanel().setAllowDragging(true)
|
||||||
return@setOnTouchListener false
|
return@setOnTouchListener false
|
||||||
}
|
}
|
||||||
|
@ -159,7 +151,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
recyclerViewDragDropManager?.cancelDrag()
|
recyclerViewDragDropManager?.cancelDrag()
|
||||||
super.onPause()
|
super.onPause()
|
||||||
progressViewUpdateHelper.stop()
|
progressViewUpdateHelper.stop()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playerToolbar(): Toolbar? {
|
override fun playerToolbar(): Toolbar? {
|
||||||
|
@ -224,9 +215,8 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
|
|
||||||
override fun toggleFavorite(song: Song) {
|
override fun toggleFavorite(song: Song) {
|
||||||
super.toggleFavorite(song)
|
super.toggleFavorite(song)
|
||||||
MusicUtil.toggleFavorite(requireContext(), song)
|
|
||||||
if (song.id == MusicPlayerRemote.currentSong.id) {
|
if (song.id == MusicPlayerRemote.currentSong.id) {
|
||||||
updateFavorite()
|
updateIsFavorite()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +264,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
override fun onQueueChanged() {
|
override fun onQueueChanged() {
|
||||||
super.onQueueChanged()
|
super.onQueueChanged()
|
||||||
updateLabel()
|
updateLabel()
|
||||||
|
playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSong() {
|
private fun updateSong() {
|
||||||
|
@ -372,7 +363,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
} else {
|
} else {
|
||||||
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
|
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
|
||||||
nextSong.apply {
|
nextSong.apply {
|
||||||
text = "Next: $title"
|
text = title
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,36 +469,4 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
|
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
|
||||||
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
|
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private fun updateFavorite() {
|
|
||||||
if (updateIsFavoriteTask != null) {
|
|
||||||
updateIsFavoriteTask?.cancel(false)
|
|
||||||
}
|
|
||||||
updateIsFavoriteTask =
|
|
||||||
object : AsyncTask<Song, Void, Boolean>() {
|
|
||||||
override fun doInBackground(vararg params: Song): Boolean? {
|
|
||||||
val activity = activity
|
|
||||||
return if (activity != null) {
|
|
||||||
MusicUtil.isFavorite(requireActivity(), params[0])
|
|
||||||
} else {
|
|
||||||
cancel(false)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostExecute(isFavorite: Boolean?) {
|
|
||||||
val activity = activity
|
|
||||||
if (activity != null) {
|
|
||||||
val res = if (isFavorite!!)
|
|
||||||
R.drawable.ic_favorite
|
|
||||||
else
|
|
||||||
R.drawable.ic_favorite_border
|
|
||||||
|
|
||||||
val drawable = TintHelper.createTintedDrawable(activity, res, Color.WHITE)
|
|
||||||
songFavourite?.setImageDrawable(drawable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute(MusicPlayerRemote.currentSong)
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package code.name.monkey.retromusic.fragments.playlists
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.adapter.playlist.LegacyPlaylistAdapter
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||||
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class ImportPlaylistFragment :
|
||||||
|
AbsRecyclerViewFragment<LegacyPlaylistAdapter, LinearLayoutManager>(),
|
||||||
|
LegacyPlaylistAdapter.PlaylistClickListener {
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
libraryViewModel.getLegacyPlaylist().observe(viewLifecycleOwner, Observer {
|
||||||
|
if (it.isNotEmpty())
|
||||||
|
adapter?.swapData(it)
|
||||||
|
else
|
||||||
|
adapter?.swapData(listOf())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createLayoutManager(): LinearLayoutManager {
|
||||||
|
return LinearLayoutManager(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createAdapter(): LegacyPlaylistAdapter {
|
||||||
|
return LegacyPlaylistAdapter(
|
||||||
|
requireActivity(),
|
||||||
|
ArrayList(),
|
||||||
|
R.layout.item_list_no_image,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlaylistClick(playlist: Playlist) {
|
||||||
|
Toast.makeText(requireContext(), "Importing ${playlist.name}", Toast.LENGTH_LONG).show()
|
||||||
|
lifecycleScope.launch(IO) {
|
||||||
|
if (playlist.name.isNotEmpty()) {
|
||||||
|
if (libraryViewModel.checkPlaylistExists(playlist.name).isEmpty()) {
|
||||||
|
val playlistId: Long =
|
||||||
|
libraryViewModel.createPlaylist(PlaylistEntity(playlist.name))
|
||||||
|
libraryViewModel.insertSongs(playlist.getSongs().map {
|
||||||
|
it.toSongEntity(playlistId.toInt())
|
||||||
|
})
|
||||||
|
libraryViewModel.forceReload(Playlists)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
menu.removeItem(R.id.action_grid_size)
|
||||||
|
menu.removeItem(R.id.action_layout_type)
|
||||||
|
menu.removeItem(R.id.action_sort_order)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,18 +5,17 @@ import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
|
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
|
||||||
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
||||||
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
|
import code.name.monkey.retromusic.db.toSongs
|
||||||
import code.name.monkey.retromusic.extensions.dipToPix
|
import code.name.monkey.retromusic.extensions.dipToPix
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
|
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
|
||||||
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.model.Song
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
|
import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
|
||||||
|
@ -32,7 +31,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
parametersOf(arguments.extraPlaylist)
|
parametersOf(arguments.extraPlaylist)
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var playlist: Playlist
|
private lateinit var playlist: PlaylistWithSongs
|
||||||
private lateinit var adapter: SongAdapter
|
private lateinit var adapter: SongAdapter
|
||||||
|
|
||||||
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
|
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
|
||||||
|
@ -46,28 +45,23 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
mainActivity.hideBottomBarVisibility(false)
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
|
|
||||||
playlist = arguments.extraPlaylist
|
playlist = arguments.extraPlaylist
|
||||||
|
toolbar.title = playlist.playlistEntity.playlistName
|
||||||
|
|
||||||
setUpRecyclerView()
|
setUpRecyclerView()
|
||||||
|
|
||||||
viewModel.getSongs().observe(viewLifecycleOwner, Observer {
|
viewModel.getSongs().observe(viewLifecycleOwner, {
|
||||||
songs(it)
|
songs(it.toSongs())
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.getPlaylist().observe(viewLifecycleOwner, Observer {
|
|
||||||
playlist = it
|
|
||||||
toolbar.title = it.name
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpRecyclerView() {
|
private fun setUpRecyclerView() {
|
||||||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
if (playlist is AbsCustomPlaylist) {
|
recyclerViewDragDropManager = RecyclerViewDragDropManager()
|
||||||
adapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null)
|
val animator = RefactoredDefaultItemAnimator()
|
||||||
recyclerView.adapter = adapter
|
adapter =
|
||||||
} else {
|
OrderablePlaylistSongAdapter(
|
||||||
recyclerViewDragDropManager = RecyclerViewDragDropManager()
|
playlist.playlistEntity,
|
||||||
val animator = RefactoredDefaultItemAnimator()
|
requireActivity(),
|
||||||
adapter = OrderablePlaylistSongAdapter(requireActivity(),
|
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
R.layout.item_list,
|
R.layout.item_list,
|
||||||
null,
|
null,
|
||||||
|
@ -75,7 +69,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
|
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
|
||||||
if (PlaylistsUtil.moveItem(
|
if (PlaylistsUtil.moveItem(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
playlist.id,
|
playlist.playlistEntity.playListId,
|
||||||
fromPosition,
|
fromPosition,
|
||||||
toPosition
|
toPosition
|
||||||
)
|
)
|
||||||
|
@ -86,13 +80,13 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter)
|
wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter)
|
||||||
|
|
||||||
recyclerView.adapter = wrappedAdapter
|
recyclerView.adapter = wrappedAdapter
|
||||||
recyclerView.itemAnimator = animator
|
recyclerView.itemAnimator = animator
|
||||||
|
|
||||||
|
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
|
||||||
|
|
||||||
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
|
|
||||||
}
|
|
||||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||||
override fun onChanged() {
|
override fun onChanged() {
|
||||||
super.onChanged()
|
super.onChanged()
|
||||||
|
@ -103,9 +97,9 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
val menuRes = if (playlist is AbsCustomPlaylist)
|
val menuRes =/* if (playlist is AbsCustomPlaylist)
|
||||||
R.menu.menu_smart_playlist_detail
|
R.menu.menu_smart_playlist_detail
|
||||||
else R.menu.menu_playlist_detail
|
else*/ R.menu.menu_playlist_detail
|
||||||
inflater.inflate(menuRes, menu)
|
inflater.inflate(menuRes, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +123,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
return String(Character.toChars(unicode))
|
return String(Character.toChars(unicode))
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onPause() {
|
override fun onPause() {
|
||||||
if (recyclerViewDragDropManager != null) {
|
if (recyclerViewDragDropManager != null) {
|
||||||
recyclerViewDragDropManager!!.cancelDrag()
|
recyclerViewDragDropManager!!.cancelDrag()
|
||||||
}
|
}
|
||||||
|
@ -160,11 +154,11 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
||||||
}
|
}
|
||||||
|
|
||||||
fun songs(songs: List<Song>) {
|
fun songs(songs: List<Song>) {
|
||||||
|
progressIndicator.hide()
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
adapter.swapDataSet(songs)
|
adapter.swapDataSet(songs)
|
||||||
} else {
|
} else {
|
||||||
showEmptyView()
|
showEmptyView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,42 +3,29 @@ package code.name.monkey.retromusic.fragments.playlists
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
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.model.Song
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
class PlaylistDetailsViewModel(
|
class PlaylistDetailsViewModel(
|
||||||
private val realRepository: RealRepository,
|
private val realRepository: RealRepository,
|
||||||
private var playlist: Playlist
|
private var playlist: PlaylistWithSongs
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val _playListSongs = MutableLiveData<List<Song>>()
|
private val _playListSongs = MutableLiveData<List<Song>>()
|
||||||
private val _playlist = MutableLiveData<Playlist>().apply {
|
private val _playlist = MutableLiveData<PlaylistWithSongs>().apply {
|
||||||
postValue(playlist)
|
postValue(playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPlaylist(): LiveData<Playlist> = _playlist
|
fun getPlaylist(): LiveData<PlaylistWithSongs> = _playlist
|
||||||
|
|
||||||
fun getSongs(): LiveData<List<Song>> = _playListSongs
|
fun getSongs(): LiveData<List<SongEntity>> = realRepository.playlistSongs(playlist.playlistEntity)
|
||||||
|
|
||||||
init {
|
|
||||||
loadPlaylistSongs(playlist)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadPlaylistSongs(playlist: Playlist) = viewModelScope.launch {
|
|
||||||
val songs = realRepository.getPlaylistSongs(playlist)
|
|
||||||
withContext(Main) { _playListSongs.postValue(songs) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
if (playlist !is AbsCustomPlaylist) {
|
/*if (playlist !is AbsCustomPlaylist) {
|
||||||
// Playlist deleted
|
// Playlist deleted
|
||||||
if (!PlaylistsUtil.doesPlaylistExist(App.getContext(), playlist.id)) {
|
if (!PlaylistsUtil.doesPlaylistExist(App.getContext(), playlist.id)) {
|
||||||
//TODO Finish the page
|
//TODO Finish the page
|
||||||
|
@ -54,7 +41,7 @@ class PlaylistDetailsViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadPlaylistSongs(playlist)
|
loadPlaylistSongs(playlist)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {}
|
override fun onServiceConnected() {}
|
||||||
|
@ -64,4 +51,4 @@ class PlaylistDetailsViewModel(
|
||||||
override fun onPlayStateChanged() {}
|
override fun onPlayStateChanged() {}
|
||||||
override fun onRepeatModeChanged() {}
|
override fun onRepeatModeChanged() {}
|
||||||
override fun onShuffleModeChanged() {}
|
override fun onShuffleModeChanged() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
package code.name.monkey.retromusic.fragments.playlists
|
package code.name.monkey.retromusic.fragments.playlists
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
|
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
import kotlinx.android.synthetic.main.fragment_library.*
|
||||||
|
|
||||||
class PlaylistsFragment :
|
class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager>() {
|
||||||
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>(),
|
|
||||||
MainActivityFragmentCallbacks {
|
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.getPlaylists().observe(viewLifecycleOwner, Observer {
|
||||||
if (it.isNotEmpty())
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(it)
|
adapter?.swapDataSet(it)
|
||||||
else
|
else
|
||||||
|
@ -30,8 +28,8 @@ class PlaylistsFragment :
|
||||||
override val emptyMessage: Int
|
override val emptyMessage: Int
|
||||||
get() = R.string.no_playlists
|
get() = R.string.no_playlists
|
||||||
|
|
||||||
override fun createLayoutManager(): GridLayoutManager {
|
override fun createLayoutManager(): LinearLayoutManager {
|
||||||
return GridLayoutManager(requireContext(), 1)
|
return LinearLayoutManager(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAdapter(): PlaylistAdapter {
|
override fun createAdapter(): PlaylistAdapter {
|
||||||
|
@ -43,9 +41,18 @@ class PlaylistsFragment :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
fun newInstance(): PlaylistsFragment {
|
super.onPrepareOptionsMenu(menu)
|
||||||
return PlaylistsFragment()
|
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
menu.removeItem(R.id.action_grid_size)
|
||||||
|
menu.removeItem(R.id.action_layout_type)
|
||||||
|
menu.removeItem(R.id.action_sort_order)
|
||||||
|
menu.add(0, R.id.action_add_to_playlist, 0, R.string.new_playlist_title)
|
||||||
|
menu.add(0, R.id.action_import_playlist, 0, R.string.import_playlist)
|
||||||
|
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
|
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
|
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
|
||||||
|
@ -33,13 +32,7 @@ import kotlinx.android.synthetic.main.activity_playing_queue.*
|
||||||
/**
|
/**
|
||||||
* Created by hemanths on 2019-12-08.
|
* Created by hemanths on 2019-12-08.
|
||||||
*/
|
*/
|
||||||
class PlayingQueueFragment :
|
class PlayingQueueFragment : AbsRecyclerViewFragment<PlayingQueueAdapter, LinearLayoutManager>() {
|
||||||
AbsRecyclerViewFragment<PlayingQueueAdapter, LinearLayoutManager>(),
|
|
||||||
MainActivityFragmentCallbacks {
|
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var wrappedAdapter: RecyclerView.Adapter<*>
|
private lateinit var wrappedAdapter: RecyclerView.Adapter<*>
|
||||||
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
|
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
|
||||||
|
|
|
@ -6,9 +6,7 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
class SearchViewModel(private val realRepository: RealRepository) : ViewModel() {
|
class SearchViewModel(private val realRepository: RealRepository) : ViewModel() {
|
||||||
private val results = MutableLiveData<MutableList<Any>>()
|
private val results = MutableLiveData<MutableList<Any>>()
|
||||||
|
@ -17,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel()
|
||||||
|
|
||||||
fun search(query: String?) = viewModelScope.launch(IO) {
|
fun search(query: String?) = viewModelScope.launch(IO) {
|
||||||
val result = realRepository.search(query)
|
val result = realRepository.search(query)
|
||||||
withContext(Main) { results.postValue(result) }
|
results.value = result
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -63,7 +63,7 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
|
||||||
aboutSettings.setOnClickListener(this)
|
aboutSettings.setOnClickListener(this)
|
||||||
|
|
||||||
buyProContainer.apply {
|
buyProContainer.apply {
|
||||||
if (!App.isProVersion()) show() else hide()
|
if (App.isProVersion()) hide() else show()
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
NavigationUtil.goToProVersion(requireContext())
|
NavigationUtil.goToProVersion(requireContext())
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue