commit
fbbc1a1ef9
212 changed files with 3963 additions and 1957 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -38,8 +38,4 @@ obj/
|
|||
captures
|
||||
app/normal/release/
|
||||
/models/
|
||||
|
||||
app/font/
|
||||
app/src/debug/
|
||||
/app/nofont/
|
||||
/crowdin.properties
|
||||
/app/release/
|
||||
|
|
|
@ -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.
|
||||
|
||||
### FAQ
|
||||
### ❓ FAQ
|
||||
Please read the FAQ here: https://del.dog/RetroFaq
|
||||
|
||||
In any case, you find or notice any bugs please report them by
|
||||
|
|
|
@ -34,7 +34,7 @@ android {
|
|||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
Properties properties = getProperties('/Users/h4h13/Documents/Github/retro.properties')
|
||||
Properties properties = getProperties('/Users/apple/Documents/Github/retro.properties ')
|
||||
storeFile file(getProperty(properties, 'storeFile'))
|
||||
keyAlias getProperty(properties, 'keyAlias')
|
||||
storePassword getProperty(properties, 'storePassword')
|
||||
|
@ -102,68 +102,50 @@ static def getDate() {
|
|||
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation project(':appthemehelper')
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
||||
implementation "androidx.gridlayout:gridlayout: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.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.core:core-ktx:1.3.1'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
def nav_version = "2.3.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 retrofit_version = '2.9.0'
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_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 room_version = "2.2.5"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
|
||||
def lifecycle_version = "2.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
|
||||
implementation 'com.google.android.play:core:1.8.0'
|
||||
implementation 'me.jorgecastillo:androidcolorx:0.2.0'
|
||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
|
||||
implementation 'com.github.dhaval2404:imagepicker:1.7.1'
|
||||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
||||
|
||||
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"
|
||||
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-ext:$koin_version"
|
||||
|
||||
def nav_version = "2.3.0"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
implementation 'com.github.bumptech.glide:glide:3.8.0'
|
||||
implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0'
|
||||
|
||||
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
|
||||
android:name="com.bumptech.glide.integration.okhttp3.OkHttpGlideModule"
|
||||
android:value="GlideModule" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.android.vending.splits.required"
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
</application>
|
||||
</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 FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
||||
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 =
|
||||
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_PLAYLIST = "extra_playlist"
|
||||
const val EXTRA_PLAYLIST_ID = "extra_playlist_id"
|
||||
const val EXTRA_ALBUM_ID = "extra_album_id"
|
||||
const val EXTRA_ARTIST_ID = "extra_artist_id"
|
||||
const val EXTRA_SONG = "extra_songs"
|
||||
const val EXTRA_PLAYLISTS = "extra_playlists"
|
||||
const val LIBRARY_CATEGORIES = "library_categories"
|
||||
const val EXTRA_SONG_INFO = "extra_song_info"
|
||||
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 COLORED_NOTIFICATION = "colored_notification"
|
||||
const val CLASSIC_NOTIFICATION = "classic_notification"
|
||||
const val GAPLESS_PLAYBACK = "gapless_playback"
|
||||
const val ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen"
|
||||
const val GAP_LESS_PLAYBACK = "gap_less_playback"
|
||||
const val ALBUM_ART_ON_LOCK_SCREEN = "album_art_on_lock_screen"
|
||||
const val BLURRED_ALBUM_ART = "blurred_album_art"
|
||||
const val NEW_BLUR_AMOUNT = "new_blur_amount"
|
||||
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 TAB_TEXT_MODE = "tab_text_mode"
|
||||
const val LANGUAGE_NAME = "language_name"
|
||||
const val DIALOG_CORNER = "dialog_corner"
|
||||
const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song"
|
||||
const val ALBUM_GRID_STYLE = "album_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 FAVOURITES = 4
|
||||
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
|
||||
|
||||
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.albums.AlbumDetailsViewModel
|
||||
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.search.SearchViewModel
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.network.networkModule
|
||||
import code.name.monkey.retromusic.network.*
|
||||
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.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.bind
|
||||
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 {
|
||||
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
|
||||
|
||||
single {
|
||||
|
@ -61,10 +154,6 @@ private val dataModule = module {
|
|||
get()
|
||||
)
|
||||
}
|
||||
|
||||
single {
|
||||
androidContext().contentResolver
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModules = module {
|
||||
|
@ -87,7 +176,7 @@ private val viewModules = module {
|
|||
)
|
||||
}
|
||||
|
||||
viewModel { (playlist: Playlist) ->
|
||||
viewModel { (playlist: PlaylistWithSongs) ->
|
||||
PlaylistDetailsViewModel(
|
||||
get(),
|
||||
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()
|
||||
.transform(BlurTransformation.Builder(this).build())
|
||||
.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.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.retromusic.*
|
||||
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
||||
import code.name.monkey.retromusic.extensions.findNavController
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
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.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader.getPlaylistSongList
|
||||
import code.name.monkey.retromusic.repository.Repository
|
||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.util.AppRater.appLaunched
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.*
|
||||
|
||||
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
|
||||
companion object {
|
||||
|
@ -35,9 +28,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
const val APP_UPDATE_REQUEST_CODE = 9002
|
||||
}
|
||||
|
||||
private val repository by inject<Repository>()
|
||||
private val libraryViewModel by inject<LibraryViewModel>()
|
||||
|
||||
private var blockRequestPermissions = false
|
||||
|
||||
override fun createContentView(): View {
|
||||
|
@ -53,7 +43,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
setTaskDescriptionColorAuto()
|
||||
hideStatusBar()
|
||||
appLaunched(this)
|
||||
addMusicServiceEventListener(libraryViewModel)
|
||||
updateTabs()
|
||||
}
|
||||
|
||||
|
@ -99,61 +88,68 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
|
||||
override fun onServiceConnected() {
|
||||
super.onServiceConnected()
|
||||
handlePlaybackIntent(intent)
|
||||
}
|
||||
|
||||
private fun handlePlaybackIntent(intent: Intent?) {
|
||||
if (intent == null) {
|
||||
return
|
||||
}
|
||||
val uri = intent.data
|
||||
val mimeType = intent.type
|
||||
var handled = false
|
||||
if (intent.action != null && (intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH)
|
||||
) {
|
||||
val songs: List<Song> =
|
||||
getSongs(this, intent.extras!!)
|
||||
if (shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
|
||||
openAndShuffleQueue(songs, true)
|
||||
} else {
|
||||
openQueue(songs, 0, true)
|
||||
}
|
||||
handled = true
|
||||
}
|
||||
if (uri != null && uri.toString().isNotEmpty()) {
|
||||
playFromUri(uri)
|
||||
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)
|
||||
handlePlaybackIntent(intent)
|
||||
}
|
||||
|
||||
private fun handlePlaybackIntent(intent: Intent) {
|
||||
lifecycleScope.launch(IO) {
|
||||
val uri: Uri? = intent.data
|
||||
val mimeType: String? = intent.type
|
||||
var handled = false
|
||||
if (intent.action != null &&
|
||||
intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
|
||||
) {
|
||||
val songs: List<Song> = getSongs(intent.extras!!)
|
||||
if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
|
||||
MusicPlayerRemote.openAndShuffleQueue(songs, true)
|
||||
} else {
|
||||
MusicPlayerRemote.openQueue(songs, 0, true)
|
||||
}
|
||||
handled = true
|
||||
}
|
||||
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
||||
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
||||
if (id >= 0) {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
val position = intent.getIntExtra("position", 0)
|
||||
openQueue(repository.albumById(id).songs!!, position, true)
|
||||
if (uri != null && uri.toString().isNotEmpty()) {
|
||||
MusicPlayerRemote.playFromUri(uri)
|
||||
handled = true
|
||||
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
|
||||
val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
|
||||
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
|
||||
}
|
||||
}
|
||||
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
||||
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
||||
if (id >= 0) {
|
||||
lifecycleScope.launch {
|
||||
val position = intent.getIntExtra("position", 0)
|
||||
openQueue(repository.artistById(id).songs, position, true)
|
||||
handled = true
|
||||
}
|
||||
if (handled) {
|
||||
setIntent(Intent())
|
||||
}
|
||||
}
|
||||
if (handled) {
|
||||
setIntent(Intent())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun parseIdFromIntent(
|
||||
|
@ -167,7 +163,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
try {
|
||||
id = idString.toLong()
|
||||
} 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() {
|
||||
|
|
|
@ -108,7 +108,7 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
private class RestorePurchaseAsyncTask internal constructor(purchaseActivity: PurchaseActivity) :
|
||||
private class RestorePurchaseAsyncTask(purchaseActivity: PurchaseActivity) :
|
||||
AsyncTask<Void, Void, Boolean>() {
|
||||
|
||||
private val buyActivityWeakReference: WeakReference<PurchaseActivity> = WeakReference(
|
||||
|
|
|
@ -110,7 +110,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
|
|||
}
|
||||
if (requestCode == TEZ_REQUEST_CODE) {
|
||||
// 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>>() {
|
||||
|
||||
private val weakReference: WeakReference<SupportDevelopmentActivity> = WeakReference(
|
||||
|
|
|
@ -160,7 +160,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
|||
}
|
||||
|
||||
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val appDir = applicationContext.filesDir
|
||||
val file = File(appDir, fileName)
|
||||
var successful = false
|
||||
|
|
|
@ -4,17 +4,23 @@ import android.Manifest
|
|||
import android.content.*
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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.interfaces.MusicServiceEventListener
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
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.util.*
|
||||
|
||||
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
|
||||
|
||||
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
|
||||
|
||||
private val repository: RealRepository by inject()
|
||||
private var serviceToken: MusicPlayerRemote.ServiceToken? = null
|
||||
private var musicStateReceiver: MusicStateReceiver? = null
|
||||
private var receiverRegistered: Boolean = false
|
||||
|
@ -93,6 +99,22 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
|
|||
for (listener in mMusicServiceEventListeners) {
|
||||
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() {
|
||||
|
|
|
@ -15,7 +15,6 @@ import code.name.monkey.appthemehelper.util.ColorUtil
|
|||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.RetroBottomSheetBehavior
|
||||
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.fragments.LibraryViewModel
|
||||
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 org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||
companion object {
|
||||
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 var miniPlayerFragment: MiniPlayerFragment? = null
|
||||
private var cps: NowPlayingScreen? = null
|
||||
|
@ -51,8 +50,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||
setMiniPlayerAlphaProgress(slideOffset)
|
||||
dimBackground.show()
|
||||
dimBackground.alpha = slideOffset
|
||||
}
|
||||
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
|
@ -62,7 +59,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
}
|
||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||
onPanelCollapsed()
|
||||
dimBackground.hide()
|
||||
}
|
||||
else -> {
|
||||
|
||||
|
@ -77,13 +73,9 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
setContentView(createContentView())
|
||||
chooseFragmentForTheme()
|
||||
setupSlidingUpPanel()
|
||||
addMusicServiceEventListener(libraryViewModel)
|
||||
|
||||
setupBottomSheet()
|
||||
|
||||
val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
|
||||
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
|
||||
|
||||
libraryViewModel.paletteColorLiveData.observe(this, Observer {
|
||||
this.paletteColor = it
|
||||
onPaletteColorChanged()
|
||||
|
|
|
@ -295,7 +295,7 @@ open class BugReportActivity : AbsThemeActivity() {
|
|||
.setTitle(R.string.bug_report_failed)
|
||||
.setMessage(R.string.bug_report_failed_unknown)
|
||||
.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"
|
||||
+ "---\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>Android build version</td><td>" + buildVersion + "</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.animation.OvershootInterpolator
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
|
@ -182,11 +181,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
saveFab = findViewById(R.id.saveTags)
|
||||
getIntentExtras()
|
||||
|
||||
lifecycleScope.launchWhenCreated {
|
||||
songPaths = getSongPaths()
|
||||
if (songPaths!!.isEmpty()) {
|
||||
finish()
|
||||
}
|
||||
songPaths = getSongPaths()
|
||||
if (songPaths!!.isEmpty()) {
|
||||
finish()
|
||||
}
|
||||
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) {
|
||||
val stringBuilder = StringBuilder()
|
||||
|
|
|
@ -44,9 +44,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
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)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
||||
.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 paths = ArrayList<String>(songs!!.size)
|
||||
for (song in songs) {
|
||||
|
|
|
@ -88,7 +88,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
writeValuesToFiles(fieldKeyValueMap, null)
|
||||
}
|
||||
|
||||
override suspend fun getSongPaths(): List<String> {
|
||||
override fun getSongPaths(): List<String> {
|
||||
val paths = ArrayList<String>(1)
|
||||
paths.add(songRepository.song(id).data)
|
||||
return paths
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package code.name.monkey.retromusic.adapter
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -22,14 +23,14 @@ class GenreAdapter(
|
|||
var dataSet: List<Genre>,
|
||||
private val mItemLayoutRes: Int
|
||||
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
||||
|
||||
|
||||
val colors = listOf<Int>(Color.RED, Color.BLUE)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val genre = dataSet[position]
|
||||
|
||||
holder.title?.text = genre.name
|
||||
holder.text?.text = String.format(
|
||||
Locale.getDefault(),
|
||||
|
|
|
@ -40,8 +40,8 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val layout = LayoutInflater.from(activity)
|
||||
.inflate(R.layout.section_recycler_view, parent, false)
|
||||
val layout =
|
||||
LayoutInflater.from(activity).inflate(R.layout.section_recycler_view, parent, false)
|
||||
return when (viewType) {
|
||||
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
|
||||
GENRES -> GenreViewHolder(layout)
|
||||
|
@ -64,7 +64,7 @@ class HomeAdapter(
|
|||
when (getItemViewType(position)) {
|
||||
RECENT_ALBUMS -> {
|
||||
val viewHolder = holder as AlbumViewHolder
|
||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.recent_albums)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -74,7 +74,7 @@ class HomeAdapter(
|
|||
}
|
||||
TOP_ALBUMS -> {
|
||||
val viewHolder = holder as AlbumViewHolder
|
||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.top_albums)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -84,7 +84,7 @@ class HomeAdapter(
|
|||
}
|
||||
RECENT_ARTISTS -> {
|
||||
val viewHolder = holder as ArtistViewHolder
|
||||
viewHolder.bindView(home.arrayList, R.string.recent_artists)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -94,7 +94,7 @@ class HomeAdapter(
|
|||
}
|
||||
TOP_ARTISTS -> {
|
||||
val viewHolder = holder as ArtistViewHolder
|
||||
viewHolder.bindView(home.arrayList, R.string.top_artists)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -104,15 +104,21 @@ class HomeAdapter(
|
|||
}
|
||||
SUGGESTIONS -> {
|
||||
val viewHolder = holder as SuggestionsViewHolder
|
||||
viewHolder.bindView(home.arrayList)
|
||||
viewHolder.bindView(home)
|
||||
}
|
||||
FAVOURITES -> {
|
||||
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 -> {
|
||||
val viewHolder = holder as GenreViewHolder
|
||||
viewHolder.bind(home.arrayList, R.string.genres)
|
||||
viewHolder.bind(home)
|
||||
}
|
||||
PLAYLISTS -> {
|
||||
|
||||
|
@ -130,22 +136,22 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(albums: List<Album>, titleRes: Int) {
|
||||
title.text = activity.getString(titleRes)
|
||||
fun bindView(home: Home) {
|
||||
title.setText(home.titleRes)
|
||||
recyclerView.apply {
|
||||
adapter = albumAdapter(albums)
|
||||
adapter = albumAdapter(home.arrayList as List<Album>)
|
||||
layoutManager = gridLayoutManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
)
|
||||
|
||||
fun bindView(songs: List<Any>) {
|
||||
songs as List<Song>
|
||||
fun bindView(home: Home) {
|
||||
val color = ThemeStore.accentColor(activity)
|
||||
itemView.findViewById<TextView>(R.id.message).setTextColor(color)
|
||||
itemView.findViewById<MaterialCardView>(R.id.card6).apply {
|
||||
|
@ -170,9 +175,9 @@ class HomeAdapter(
|
|||
}
|
||||
images.forEachIndexed { index, id ->
|
||||
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()
|
||||
.build()
|
||||
.into(itemView.findViewById(id))
|
||||
|
@ -182,35 +187,37 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(songs: List<Any>, titleRes: Int) {
|
||||
arrow.hide()
|
||||
fun bindView(home: Home) {
|
||||
title.setText(home.titleRes)
|
||||
recyclerView.apply {
|
||||
val songAdapter = SongAdapter(
|
||||
activity,
|
||||
songs as MutableList<Song>,
|
||||
home.arrayList as MutableList<Song>,
|
||||
R.layout.item_album_card, null
|
||||
)
|
||||
layoutManager = linearLayoutManager()
|
||||
adapter = songAdapter
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class GenreViewHolder(itemView: View) : AbsHomeViewItem(itemView) {
|
||||
fun bind(genres: List<Any>, titleRes: Int) {
|
||||
fun bind(home: Home) {
|
||||
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 {
|
||||
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
|
||||
val genreAdapter =
|
||||
GenreAdapter(activity, genres as List<Genre>, R.layout.item_grid_genre)
|
||||
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 title: AppCompatTextView = itemView.findViewById(R.id.title)
|
||||
val arrow: ImageView = itemView.findViewById(R.id.arrow)
|
||||
|
|
|
@ -60,7 +60,7 @@ class SearchAdapter(
|
|||
holder.title?.text = album.title
|
||||
holder.text?.text = album.artistName
|
||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||
.checkIgnoreMediaStore(activity).build().into(holder.image)
|
||||
.checkIgnoreMediaStore().build().into(holder.image)
|
||||
}
|
||||
ARTIST -> {
|
||||
val artist = dataSet.get(position) as Artist
|
||||
|
|
|
@ -101,11 +101,10 @@ open class AlbumAdapter(
|
|||
}
|
||||
|
||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||
.checkIgnoreMediaStore(activity)
|
||||
.checkIgnoreMediaStore()
|
||||
.generatePalette(activity)
|
||||
.build()
|
||||
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
||||
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
setColors(colors, holder)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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.NowPlayingScreen.*
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
|
@ -90,6 +91,7 @@ class AlbumCoverPagerAdapter(
|
|||
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
||||
albumCover = view.findViewById(R.id.player_image)
|
||||
albumCover.setOnClickListener {
|
||||
LyricsDialog().show(childFragmentManager, "LyricsDialog")
|
||||
showLyricsDialog()
|
||||
}
|
||||
return view
|
||||
|
@ -97,7 +99,7 @@ class AlbumCoverPagerAdapter(
|
|||
|
||||
private fun showLyricsDialog() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val data = MusicUtil.getLyrics(song)
|
||||
val data: String = MusicUtil.getLyrics(song) ?: "No lyrics found"
|
||||
withContext(Dispatchers.Main) {
|
||||
MaterialAlertDialogBuilder(
|
||||
requireContext(),
|
||||
|
|
|
@ -3,7 +3,6 @@ package code.name.monkey.retromusic.adapter.album
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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.glide.AlbumGlideRequest
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
|
@ -30,14 +29,14 @@ class HorizontalAlbumAdapter(
|
|||
}
|
||||
|
||||
override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
|
||||
holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
|
||||
holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
|
||||
//holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
|
||||
//holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
|
||||
}
|
||||
|
||||
override fun loadAlbumCover(album: Album, holder: ViewHolder) {
|
||||
if (holder.image == null) return
|
||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||
.checkIgnoreMediaStore(activity)
|
||||
.checkIgnoreMediaStore()
|
||||
.generatePalette(activity)
|
||||
.build()
|
||||
.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.fragment.app.FragmentActivity
|
||||
import androidx.navigation.findNavController
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
|
||||
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.show
|
||||
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
|
||||
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
|
||||
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.Song
|
||||
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
|
||||
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
|
||||
import code.name.monkey.retromusic.util.AutoGeneratedPlaylistBitmap
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||
import java.util.*
|
||||
|
||||
class PlaylistAdapter(
|
||||
private val activity: FragmentActivity,
|
||||
var dataSet: List<Playlist>,
|
||||
var dataSet: List<PlaylistWithSongs>,
|
||||
private var itemLayoutRes: Int,
|
||||
cabHolder: CabHolder?
|
||||
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(
|
||||
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, PlaylistWithSongs>(
|
||||
activity,
|
||||
cabHolder,
|
||||
R.menu.menu_playlists_selection
|
||||
) {
|
||||
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
}
|
||||
|
||||
fun swapDataSet(dataSet: List<Playlist>) {
|
||||
fun swapDataSet(dataSet: List<PlaylistWithSongs>) {
|
||||
this.dataSet = dataSet
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -69,20 +68,20 @@ class PlaylistAdapter(
|
|||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
private fun getPlaylistTitle(playlist: Playlist): String {
|
||||
return if (TextUtils.isEmpty(playlist.name)) "-" else playlist.name
|
||||
private fun getPlaylistTitle(playlist: PlaylistEntity): String {
|
||||
return if (TextUtils.isEmpty(playlist.playlistName)) "-" else playlist.playlistName
|
||||
}
|
||||
|
||||
private fun getPlaylistText(playlist: Playlist): String {
|
||||
return MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
|
||||
private fun getPlaylistText(playlist: PlaylistWithSongs): String {
|
||||
return MusicUtil.getPlaylistInfoString(activity, playlist.songs.toSongs())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val playlist = dataSet[position]
|
||||
holder.itemView.isActivated = isChecked(playlist)
|
||||
holder.title?.text = getPlaylistTitle(playlist)
|
||||
holder.title?.text = getPlaylistTitle(playlist.playlistEntity)
|
||||
holder.text?.text = getPlaylistText(playlist)
|
||||
holder.image?.setImageDrawable(getIconRes(playlist))
|
||||
holder.image?.setImageDrawable(getIconRes())
|
||||
val isChecked = isChecked(playlist)
|
||||
if (isChecked) {
|
||||
holder.menu?.hide()
|
||||
|
@ -92,37 +91,25 @@ class PlaylistAdapter(
|
|||
//PlaylistBitmapLoader(this, holder, playlist).execute()
|
||||
}
|
||||
|
||||
private fun getIconRes(playlist: Playlist): Drawable {
|
||||
return if (MusicUtil.isFavoritePlaylist(activity, playlist))
|
||||
TintHelper.createTintedDrawable(
|
||||
activity,
|
||||
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
|
||||
}
|
||||
private fun getIconRes(): Drawable = TintHelper.createTintedDrawable(
|
||||
activity,
|
||||
R.drawable.ic_playlist_play,
|
||||
ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
|
||||
)
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return dataSet.size
|
||||
}
|
||||
|
||||
override fun getIdentifier(position: Int): Playlist? {
|
||||
override fun getIdentifier(position: Int): PlaylistWithSongs? {
|
||||
return dataSet[position]
|
||||
}
|
||||
|
||||
override fun getName(playlist: Playlist): String {
|
||||
return playlist.name
|
||||
override fun getName(playlist: PlaylistWithSongs): String {
|
||||
return playlist.playlistEntity.playlistName
|
||||
}
|
||||
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Playlist>) {
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<PlaylistWithSongs>) {
|
||||
when (menuItem.itemId) {
|
||||
else -> SongsMenuHelper.handleMenuClick(
|
||||
activity,
|
||||
|
@ -132,37 +119,26 @@ class PlaylistAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getSongList(playlists: List<Playlist>): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
for (playlist in playlists) {
|
||||
if (playlist is AbsCustomPlaylist) {
|
||||
songs.addAll(playlist.songs())
|
||||
} else {
|
||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
||||
}
|
||||
private fun getSongList(playlists: List<PlaylistWithSongs>): List<Song> {
|
||||
val songs = mutableListOf<Song>()
|
||||
playlists.forEach {
|
||||
songs.addAll(it.songs.toSongs())
|
||||
}
|
||||
return songs
|
||||
}
|
||||
|
||||
private fun getSongs(playlist: Playlist): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
if (playlist is AbsSmartPlaylist) {
|
||||
songs.addAll(playlist.songs())
|
||||
} else {
|
||||
songs.addAll(playlist.getSongs())
|
||||
private fun getSongs(playlist: PlaylistWithSongs): List<SongEntity> =
|
||||
mutableListOf<SongEntity>().apply {
|
||||
addAll(playlist.songs)
|
||||
}
|
||||
return songs
|
||||
}
|
||||
|
||||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||
init {
|
||||
|
||||
image?.apply {
|
||||
val iconPadding =
|
||||
activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
|
||||
setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
|
||||
}
|
||||
|
||||
menu?.setOnClickListener { view ->
|
||||
val popupMenu = PopupMenu(activity, view)
|
||||
popupMenu.inflate(R.menu.menu_item_playlist)
|
||||
|
@ -221,7 +197,5 @@ class PlaylistAdapter(
|
|||
|
||||
companion object {
|
||||
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 code.name.monkey.retromusic.R
|
||||
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.model.PlaylistSong
|
||||
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
|
||||
|
||||
class OrderablePlaylistSongAdapter(
|
||||
private val playlist: PlaylistEntity,
|
||||
activity: FragmentActivity,
|
||||
dataSet: ArrayList<Song>,
|
||||
itemLayoutRes: Int,
|
||||
|
@ -54,8 +57,8 @@ class OrderablePlaylistSongAdapter(
|
|||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_remove_from_playlist -> {
|
||||
RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>)
|
||||
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||
RemoveSongFromPlaylistDialog.create(selection.toSongs(playlist.playListId))
|
||||
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +121,7 @@ class OrderablePlaylistSongAdapter(
|
|||
override fun onSongMenuItemClick(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_remove_from_playlist -> {
|
||||
RemoveFromPlaylistDialog.create(song as PlaylistSong)
|
||||
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId))
|
||||
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
||||
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.SwipeResultActionDefault
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.annotation.SwipeableItemResults
|
||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||
|
||||
class PlayingQueueAdapter(
|
||||
|
@ -153,8 +152,8 @@ class PlayingQueueAdapter(
|
|||
mDragStateFlags = flags
|
||||
}
|
||||
|
||||
override fun getSwipeableContainerView(): View? {
|
||||
return dummyContainer
|
||||
override fun getSwipeableContainerView(): View {
|
||||
return dummyContainer!!
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,18 +164,15 @@ class PlayingQueueAdapter(
|
|||
private const val UP_NEXT = 2
|
||||
}
|
||||
|
||||
override fun onSwipeItem(
|
||||
holder: ViewHolder?,
|
||||
position: Int, @SwipeableItemResults result: Int
|
||||
): SwipeResultAction {
|
||||
return if (result === SwipeableItemConstants.RESULT_CANCELED) {
|
||||
override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int): SwipeResultAction? {
|
||||
return if (result == SwipeableItemConstants.RESULT_CANCELED) {
|
||||
SwipeResultActionDefault()
|
||||
} else {
|
||||
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)) {
|
||||
SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H
|
||||
} 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(
|
||||
|
|
|
@ -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
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
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.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.extraNotNull
|
||||
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.repository.PlaylistRepository
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
||||
class AddToPlaylistDialog : DialogFragment() {
|
||||
private val playlistRepository by inject<PlaylistRepository>()
|
||||
override fun onCreateDialog(
|
||||
savedInstanceState: Bundle?
|
||||
): Dialog {
|
||||
val playlists = playlistRepository.playlists()
|
||||
val playlistNames = mutableListOf<String>()
|
||||
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||
|
||||
companion object {
|
||||
fun create(playlistEntities: List<PlaylistEntity>, song: Song): AddToPlaylistDialog {
|
||||
val list: MutableList<Song> = mutableListOf()
|
||||
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))
|
||||
for (p in playlists) {
|
||||
playlistNames.add(p.name)
|
||||
for (entity: PlaylistEntity in playlistEntities) {
|
||||
playlistNames.add(entity.playlistName)
|
||||
}
|
||||
return materialDialog(R.string.add_playlist_title)
|
||||
.setItems(playlistNames.toTypedArray()) { _, which ->
|
||||
val songs = extraNotNull<ArrayList<Song>>(EXTRA_SONG).value
|
||||
if (which == 0) {
|
||||
CreatePlaylistDialog.create(songs)
|
||||
.show(requireActivity().supportFragmentManager, "ADD_TO_PLAYLIST")
|
||||
.show(requireActivity().supportFragmentManager, "Dialog")
|
||||
} else {
|
||||
PlaylistsUtil.addToPlaylist(
|
||||
requireContext(),
|
||||
songs,
|
||||
playlists[which - 1].id,
|
||||
true
|
||||
)
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val songEntities: List<SongEntity> =
|
||||
songs.toSongsEntity(playlistEntities[which - 1])
|
||||
libraryViewModel.insertSongs(songEntities)
|
||||
libraryViewModel.forceReload(Playlists)
|
||||
}
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
.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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.bundleOf
|
||||
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.R
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
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.fragments.LibraryViewModel
|
||||
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||
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.TextInputLayout
|
||||
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() {
|
||||
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
override fun onCreateDialog(
|
||||
savedInstanceState: Bundle?
|
||||
): Dialog {
|
||||
companion object {
|
||||
fun create(song: Song): CreatePlaylistDialog {
|
||||
val list = mutableListOf<Song>()
|
||||
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 songs: List<Song> = extra<List<Song>>(EXTRA_SONG).value ?: emptyList()
|
||||
val playlistView: TextInputEditText = view.actionNewPlaylist
|
||||
val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer
|
||||
MaterialUtil.setTint(playlistContainer, false)
|
||||
|
||||
return materialDialog(R.string.new_playlist_title)
|
||||
.setView(view)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(
|
||||
R.string.create_action
|
||||
) { _, _ ->
|
||||
val extra = extraNotNull<ArrayList<Song>>(EXTRA_SONG)
|
||||
val playlistName = playlistView.text.toString()
|
||||
if (!TextUtils.isEmpty(playlistName)) {
|
||||
val playlistId = PlaylistsUtil.createPlaylist(
|
||||
requireContext(),
|
||||
playlistView.text.toString()
|
||||
)
|
||||
if (playlistId != -1) {
|
||||
PlaylistsUtil.addToPlaylist(requireContext(), extra.value, playlistId, true)
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) {
|
||||
val playlistId: Long =
|
||||
libraryViewModel.createPlaylist(PlaylistEntity(playlistName))
|
||||
libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) })
|
||||
libraryViewModel.forceReload(Playlists)
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
playlistContainer.error = "Playlist is can't be empty"
|
||||
}
|
||||
}
|
||||
.create()
|
||||
.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
|
||||
|
||||
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_PLAYLIST
|
||||
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.extraNotNull
|
||||
import code.name.monkey.retromusic.extensions.materialDialog
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
import code.name.monkey.retromusic.fragments.ReloadType
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
||||
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 {
|
||||
val playlists = extraNotNull<List<Playlist>>(EXTRA_PLAYLIST).value
|
||||
val playlists = extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLIST).value
|
||||
val title: Int
|
||||
val message: CharSequence
|
||||
//noinspection ConstantConditions
|
||||
|
@ -42,7 +48,7 @@ class DeletePlaylistDialog : DialogFragment() {
|
|||
} else {
|
||||
title = R.string.delete_playlist_title
|
||||
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
|
||||
)
|
||||
}
|
||||
|
@ -52,26 +58,12 @@ class DeletePlaylistDialog : DialogFragment() {
|
|||
.setMessage(message)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.action_delete) { _, _ ->
|
||||
PlaylistsUtil.deletePlaylists(requireContext(), playlists)
|
||||
libraryViewModel.deleteSongsFromPlaylist(playlists)
|
||||
libraryViewModel.deleteRoomPlaylist(playlists)
|
||||
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||
}
|
||||
.create()
|
||||
.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
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
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.activities.saf.SAFGuideActivity
|
||||
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.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
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() {
|
||||
@JvmField
|
||||
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()
|
||||
})
|
||||
}
|
||||
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||
|
||||
companion object {
|
||||
|
||||
fun create(song: Song): DeleteSongsDialog {
|
||||
val list = ArrayList<Song>()
|
||||
list.add(song)
|
||||
|
@ -119,5 +33,38 @@ class DeleteSongsDialog : DialogFragment() {
|
|||
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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore.Audio.Playlists.Members.PLAYLIST_ID
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.os.bundleOf
|
||||
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.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.extensions.accentColor
|
||||
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 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.TextInputLayout
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
||||
class RenamePlaylistDialog : DialogFragment() {
|
||||
|
||||
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
override fun onCreateDialog(
|
||||
savedInstanceState: Bundle?
|
||||
): Dialog {
|
||||
val layout = LayoutInflater.from(requireContext())
|
||||
.inflate(R.layout.dialog_playlist, null)
|
||||
companion object {
|
||||
fun create(playlistEntity: PlaylistEntity): RenamePlaylistDialog {
|
||||
return RenamePlaylistDialog().apply {
|
||||
arguments = bundleOf(
|
||||
EXTRA_PLAYLIST_ID to playlistEntity
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 nameContainer: TextInputLayout =
|
||||
layout.findViewById(R.id.actionNewPlaylistContainer)
|
||||
MaterialUtil.setTint(nameContainer, false)
|
||||
|
||||
val nameContainer: TextInputLayout = layout.findViewById(R.id.actionNewPlaylistContainer)
|
||||
nameContainer.accentColor()
|
||||
inputEditText.setText(playlistEntity.playlistName)
|
||||
return materialDialog(R.string.rename_playlist_title)
|
||||
.setView(layout)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.action_rename) { _, _ ->
|
||||
val name = inputEditText.text.toString()
|
||||
if (name.isNotEmpty()) {
|
||||
PlaylistsUtil.renamePlaylist(
|
||||
requireContext(),
|
||||
extraNotNull<Long>(PLAYLIST_ID).value,
|
||||
name
|
||||
)
|
||||
libraryViewModel.renameRoomPlaylist(playlistEntity.playListId, name)
|
||||
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||
} else {
|
||||
nameContainer.error = "Playlist name should'nt be empty"
|
||||
}
|
||||
}
|
||||
.create()
|
||||
.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")
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
timerUpdater = TimerUpdater()
|
||||
val layout = LayoutInflater.from(requireContext())
|
||||
.inflate(R.layout.dialog_sleep_timer, null)
|
||||
val layout =
|
||||
LayoutInflater.from(requireContext()).inflate(R.layout.dialog_sleep_timer, null)
|
||||
shouldFinishLastSong = layout.findViewById(R.id.shouldFinishLastSong)
|
||||
seekBar = layout.findViewById(R.id.seekBar)
|
||||
timerDisplay = layout.findViewById(R.id.timerDisplay)
|
||||
|
@ -158,7 +158,7 @@ class SleepTimerDialog : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private inner class TimerUpdater internal constructor() :
|
||||
private inner class TimerUpdater() :
|
||||
CountDownTimer(
|
||||
PreferenceUtil.nextSleepTimerElapsedRealTime - SystemClock.elapsedRealtime(),
|
||||
1000
|
||||
|
|
|
@ -21,8 +21,6 @@ import android.os.Bundle
|
|||
import android.text.Spanned
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.core.text.HtmlCompat
|
||||
|
@ -41,12 +39,6 @@ import org.jaudiotagger.tag.TagException
|
|||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
inline fun ViewGroup.forEach(action: (View) -> Unit) {
|
||||
for (i in 0 until childCount) {
|
||||
action(getChildAt(i))
|
||||
}
|
||||
}
|
||||
|
||||
class SongDetailDialog : DialogFragment() {
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
|
|
|
@ -15,13 +15,8 @@
|
|||
package code.name.monkey.retromusic.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.annotation.IdRes
|
||||
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.retromusic.R
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
|
||||
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
||||
|
@ -30,41 +25,6 @@ fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
|||
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 {
|
||||
val value = intent?.extras?.get(key)
|
||||
if (value is T) value else default
|
||||
|
|
|
@ -18,12 +18,18 @@ import android.app.Dialog
|
|||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.widget.Button
|
||||
import android.widget.CheckBox
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
|
@ -33,6 +39,8 @@ import code.name.monkey.retromusic.App
|
|||
import code.name.monkey.retromusic.R
|
||||
import com.google.android.material.button.MaterialButton
|
||||
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.TextInputLayout
|
||||
|
||||
|
@ -91,6 +99,10 @@ fun Button.accentTextColor() {
|
|||
setTextColor(ThemeStore.accentColor(App.getContext()))
|
||||
}
|
||||
|
||||
fun MaterialButton.accentTextColor() {
|
||||
setTextColor(ThemeStore.accentColor(App.getContext()))
|
||||
}
|
||||
|
||||
fun SeekBar.applyColor(@ColorInt color: Int) {
|
||||
thumbTintList = ColorStateList.valueOf(color)
|
||||
progressTintList = ColorStateList.valueOf(color)
|
||||
|
@ -107,6 +119,15 @@ fun ExtendedFloatingActionButton.accentColor() {
|
|||
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) {
|
||||
val backgroundColorStateList = ColorStateList.valueOf(color)
|
||||
val textColorColorStateList = ColorStateList.valueOf(
|
||||
|
@ -120,6 +141,12 @@ fun MaterialButton.applyColor(color: Int) {
|
|||
iconTint = textColorColorStateList
|
||||
}
|
||||
|
||||
fun MaterialButton.applyOutlineColor(color: Int) {
|
||||
val textColorColorStateList = ColorStateList.valueOf(color)
|
||||
setTextColor(textColorColorStateList)
|
||||
iconTint = textColorColorStateList
|
||||
}
|
||||
|
||||
fun TextInputLayout.accentColor() {
|
||||
val accentColor = ThemeStore.accentColor(context)
|
||||
val colorState = ColorStateList.valueOf(accentColor)
|
||||
|
@ -128,6 +155,39 @@ fun TextInputLayout.accentColor() {
|
|||
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 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 {
|
||||
return MaterialAlertDialogBuilder(
|
||||
requireContext(),
|
||||
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
|
||||
R.style.MaterialAlertDialogTheme
|
||||
).setTitle(title)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,15 @@ package code.name.monkey.retromusic.extensions
|
|||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.PowerManager
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.IntegerRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
|
@ -51,7 +54,8 @@ val FragmentManager.currentNavigationFragment: Fragment?
|
|||
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
|
||||
|
||||
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
||||
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||
val navHostFragment: NavHostFragment =
|
||||
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||
navHostFragment.targetFragment
|
||||
return navHostFragment.childFragmentManager.fragments.first()
|
||||
}
|
||||
|
@ -72,4 +76,12 @@ fun Fragment.showToast(@StringRes stringRes: Int) {
|
|||
|
||||
fun Fragment.showToast(message: String) {
|
||||
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
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.LayoutRes
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
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.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
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.artist.ArtistAdapter
|
||||
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.artists.ArtistClickListener
|
||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -34,6 +35,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
progressIndicator.hide()
|
||||
when (args.type) {
|
||||
TOP_ARTISTS -> {
|
||||
loadArtists(R.string.top_artists, TOP_ARTISTS)
|
||||
|
@ -47,32 +49,88 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
RECENT_ALBUMS -> {
|
||||
loadAlbums(R.string.recent_albums, RECENT_ALBUMS)
|
||||
}
|
||||
FAVOURITES -> {
|
||||
loadFavorite()
|
||||
}
|
||||
FAVOURITES -> 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() {
|
||||
toolbar.setTitle(R.string.favorites)
|
||||
CoroutineScope(IO).launch {
|
||||
val songs = repository.favoritePlaylistHome()
|
||||
withContext(Main) {
|
||||
recyclerView.apply {
|
||||
adapter = SongAdapter(
|
||||
requireActivity(),
|
||||
songs.arrayList as MutableList<Song>,
|
||||
R.layout.item_list, null
|
||||
)
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
}
|
||||
val songAdapter = SongAdapter(
|
||||
requireActivity(),
|
||||
mutableListOf(),
|
||||
R.layout.item_list, null
|
||||
)
|
||||
recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
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) {
|
||||
toolbar.setTitle(title)
|
||||
CoroutineScope(IO).launch {
|
||||
lifecycleScope.launch(IO) {
|
||||
val artists =
|
||||
if (type == TOP_ARTISTS) repository.topArtists() else repository.recentArtists()
|
||||
withContext(Main) {
|
||||
|
@ -86,7 +144,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
|
||||
private fun loadAlbums(title: Int, type: Int) {
|
||||
toolbar.setTitle(title)
|
||||
CoroutineScope(IO).launch {
|
||||
lifecycleScope.launch(IO) {
|
||||
val albums =
|
||||
if (type == TOP_ALBUMS) repository.topAlbums() else repository.recentAlbums()
|
||||
withContext(Main) {
|
||||
|
|
|
@ -4,83 +4,129 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||
import code.name.monkey.retromusic.model.*
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LibraryViewModel(
|
||||
private val realRepository: RealRepository
|
||||
private val repository: RealRepository
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val paletteColor = MutableLiveData<Int>()
|
||||
private val albums = MutableLiveData<List<Album>>()
|
||||
private val songs = MutableLiveData<List<Song>>()
|
||||
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 home = MutableLiveData<List<Home>>()
|
||||
|
||||
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 {
|
||||
viewModelScope.launch {
|
||||
loadLibraryContent()
|
||||
fetchHomeSections()
|
||||
}
|
||||
|
||||
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 {
|
||||
songs.value = loadSongs.await()
|
||||
albums.value = loadAlbums.await()
|
||||
artists.value = loadArtists.await()
|
||||
playlists.value = loadPlaylists.await()
|
||||
genres.value = loadGenres.await()
|
||||
home.value = loadHome.await()
|
||||
private fun fetchAlbums() {
|
||||
viewModelScope.launch(IO) {
|
||||
albums.postValue(repository.fetchAlbums())
|
||||
}
|
||||
}
|
||||
|
||||
private val loadHome: Deferred<List<Home>>
|
||||
get() = viewModelScope.async { realRepository.homeSections() }
|
||||
|
||||
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 fun fetchArtists() {
|
||||
viewModelScope.launch(IO) {
|
||||
artists.postValue(repository.fetchArtists())
|
||||
}
|
||||
}
|
||||
|
||||
private val loadArtists: Deferred<List<Artist>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.albumArtists()
|
||||
private fun fetchPlaylists() {
|
||||
viewModelScope.launch(IO) {
|
||||
playlists.postValue(repository.fetchPlaylistWithSongs())
|
||||
}
|
||||
}
|
||||
|
||||
private val loadPlaylists: Deferred<List<Playlist>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.allPlaylists()
|
||||
private fun fetchLegacyPlaylist() {
|
||||
viewModelScope.launch(IO) {
|
||||
legacyPlaylists.postValue(repository.fetchLegacyPlaylist())
|
||||
}
|
||||
}
|
||||
|
||||
private val loadGenres: Deferred<List<Genre>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.allGenres()
|
||||
private fun fetchGenres() {
|
||||
viewModelScope.launch(IO) {
|
||||
genres.postValue(repository.fetchGenres())
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchHomeSections() {
|
||||
viewModelScope.launch(IO) {
|
||||
home.postValue(repository.homeSections())
|
||||
}
|
||||
}
|
||||
|
||||
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
|
||||
when (reloadType) {
|
||||
Songs -> songs.value = loadSongs.await()
|
||||
Albums -> albums.value = loadAlbums.await()
|
||||
Artists -> artists.value = loadArtists.await()
|
||||
HomeSections -> songs.value = loadSongs.await()
|
||||
Songs -> fetchSongs()
|
||||
Albums -> fetchAlbums()
|
||||
Artists -> fetchArtists()
|
||||
HomeSections -> fetchHomeSections()
|
||||
Playlists -> fetchPlaylists()
|
||||
Genres -> fetchGenres()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,11 +135,10 @@ class LibraryViewModel(
|
|||
}
|
||||
|
||||
override fun onMediaStoreChanged() {
|
||||
loadLibraryContent()
|
||||
println("onMediaStoreChanged")
|
||||
loadLibraryContent()
|
||||
}
|
||||
|
||||
|
||||
override fun onServiceConnected() {
|
||||
println("onServiceConnected")
|
||||
}
|
||||
|
@ -108,6 +153,7 @@ class LibraryViewModel(
|
|||
|
||||
override fun onPlayingMetaChanged() {
|
||||
println("onPlayingMetaChanged")
|
||||
|
||||
}
|
||||
|
||||
override fun onPlayStateChanged() {
|
||||
|
@ -122,11 +168,76 @@ class LibraryViewModel(
|
|||
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 {
|
||||
Songs,
|
||||
Albums,
|
||||
Artists,
|
||||
HomeSections
|
||||
HomeSections,
|
||||
Playlists,
|
||||
Genres,
|
||||
}
|
|
@ -11,18 +11,14 @@ import android.view.GestureDetector
|
|||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.extensions.show
|
||||
import code.name.monkey.retromusic.extensions.textColorPrimary
|
||||
import code.name.monkey.retromusic.extensions.textColorSecondary
|
||||
import code.name.monkey.retromusic.extensions.*
|
||||
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import code.name.monkey.retromusic.util.ViewUtil
|
||||
import kotlinx.android.synthetic.main.fragment_mini_player.*
|
||||
import kotlin.math.abs
|
||||
|
||||
|
@ -67,7 +63,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
|
|||
|
||||
private fun setUpMiniPlayer() {
|
||||
setUpPlayPauseButton()
|
||||
ViewUtil.setProgressDrawable(progressBar, ThemeStore.accentColor(requireContext()))
|
||||
progressBar.accentColor()
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
private var flingPlayBackController: GestureDetector
|
||||
|
|
|
@ -24,7 +24,6 @@ enum class NowPlayingScreen constructor(
|
|||
Gradient(R.string.gradient, R.drawable.np_gradient, 17),
|
||||
Material(R.string.material, R.drawable.np_material, 11),
|
||||
Normal(R.string.normal, R.drawable.np_normal, 0),
|
||||
|
||||
//Peak(R.string.peak, R.drawable.np_peak, 14),
|
||||
Plain(R.string.plain, R.drawable.np_plain, 3),
|
||||
Simple(R.string.simple, R.drawable.np_simple, 8),
|
||||
|
|
|
@ -6,7 +6,9 @@ import android.os.Bundle
|
|||
import android.view.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
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.DeleteSongsDialog
|
||||
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.fragments.base.AbsMainActivityFragment
|
||||
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
||||
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.SortOrder
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
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.repository.RealRepository
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
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 kotlinx.android.synthetic.main.fragment_album_content.*
|
||||
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.core.parameter.parametersOf
|
||||
import java.util.*
|
||||
|
@ -66,23 +76,13 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
mainActivity.hideBottomBarVisibility(false)
|
||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
|
||||
toolbar.title = null
|
||||
|
||||
toolbar.title = " "
|
||||
postponeEnterTransition()
|
||||
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
|
||||
showAlbum(it)
|
||||
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()
|
||||
artistImage.setOnClickListener {
|
||||
requireActivity().findNavController(R.id.fragment_container)
|
||||
|
@ -140,14 +140,12 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
this.album = album
|
||||
|
||||
albumTitle.text = album.title
|
||||
val songText =
|
||||
resources.getQuantityString(
|
||||
R.plurals.albumSongs,
|
||||
album.songCount,
|
||||
album.songCount
|
||||
)
|
||||
val songText = resources.getQuantityString(
|
||||
R.plurals.albumSongs,
|
||||
album.songCount,
|
||||
album.songCount
|
||||
)
|
||||
songTitle.text = songText
|
||||
|
||||
if (MusicUtil.getYearString(album.year) == "-") {
|
||||
albumText.text = String.format(
|
||||
"%s • %s",
|
||||
|
@ -162,10 +160,25 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
|
||||
)
|
||||
}
|
||||
loadAlbumCover()
|
||||
loadAlbumCover(album)
|
||||
simpleSongAdapter.swapDataSet(album.songs)
|
||||
detailsViewModel.loadArtist(album.artistId)
|
||||
detailsViewModel.loadAlbumInfo(album)
|
||||
detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer {
|
||||
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>) {
|
||||
|
@ -191,7 +204,10 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
aboutAlbumTitle.show()
|
||||
aboutAlbumTitle.text =
|
||||
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()) {
|
||||
listeners.show()
|
||||
|
@ -206,7 +222,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
}
|
||||
|
||||
private fun loadArtistImage(artist: Artist) {
|
||||
detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner, Observer {
|
||||
moreAlbums(it)
|
||||
})
|
||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||
.forceDownload(PreferenceUtil.isAllowedToDownloadMetadata())
|
||||
.generatePalette(requireContext())
|
||||
.build()
|
||||
.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())
|
||||
.checkIgnoreMediaStore(requireContext())
|
||||
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
|
||||
.checkIgnoreMediaStore()
|
||||
.generatePalette(requireContext())
|
||||
.build()
|
||||
.dontAnimate()
|
||||
.dontTransform()
|
||||
.into(object : RetroMusicColoredTarget(image) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
setColors(colors)
|
||||
.into(object : SingleColorTarget(image) {
|
||||
override fun onColorReady(color: Int) {
|
||||
setColors(color)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setColors(color: MediaNotificationProcessor) {
|
||||
shuffleAction.applyColor(color.backgroundColor)
|
||||
playAction.applyColor(color.backgroundColor)
|
||||
private fun setColors(color: Int) {
|
||||
shuffleAction.applyColor(color)
|
||||
playAction.applyOutlineColor(color)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
|
@ -275,7 +292,13 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
return true
|
||||
}
|
||||
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
|
||||
}
|
||||
R.id.action_delete_from_device -> {
|
||||
|
|
|
@ -1,64 +1,44 @@
|
|||
package code.name.monkey.retromusic.fragments.albums
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.liveData
|
||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
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.repository.RealRepository
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
||||
class AlbumDetailsViewModel(
|
||||
private val realRepository: RealRepository,
|
||||
private val albumId: Int
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val _album = MutableLiveData<Album>()
|
||||
private val _artist = MutableLiveData<Artist>()
|
||||
private val _lastFmAlbum = MutableLiveData<LastFmAlbum>()
|
||||
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()
|
||||
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
||||
val album = realRepository.albumByIdAsync(albumId)
|
||||
emit(album)
|
||||
}
|
||||
|
||||
private fun loadAlbumDetails() = viewModelScope.launch {
|
||||
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) {
|
||||
fun getArtist(artistId: Int): LiveData<Artist> = liveData(IO) {
|
||||
val artist = realRepository.artistById(artistId)
|
||||
_artist.postValue(artist)
|
||||
|
||||
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
||||
if (albums.isNotEmpty()) _moreAlbums.postValue(albums)
|
||||
}
|
||||
emit(artist)
|
||||
}
|
||||
|
||||
private val loadAlbumAsync: Deferred<Album?>
|
||||
get() = viewModelScope.async(Dispatchers.IO) {
|
||||
realRepository.albumById(albumId)
|
||||
fun getAlbumInfo(album: Album): LiveData<Result<LastFmAlbum>> = liveData {
|
||||
emit(Result.Loading)
|
||||
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() {
|
||||
loadAlbumDetails()
|
||||
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {}
|
||||
|
|
|
@ -1,26 +1,29 @@
|
|||
package code.name.monkey.retromusic.fragments.albums
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.*
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||
import code.name.monkey.retromusic.R
|
||||
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.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.RetroUtil
|
||||
|
||||
class AlbumsFragment :
|
||||
AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||
|
||||
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||
AlbumClickListener {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.albumsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
libraryViewModel.getAlbums().observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
|
@ -95,8 +98,7 @@ class AlbumsFragment :
|
|||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
val controller = requireActivity().findNavController(R.id.fragment_container)
|
||||
controller.navigate(
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
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 {
|
||||
|
|
|
@ -10,33 +10,43 @@ import android.view.View
|
|||
import androidx.core.os.bundleOf
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
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.adapter.album.HorizontalAlbumAdapter
|
||||
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
||||
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
|
||||
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.showToast
|
||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||
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.model.Artist
|
||||
import code.name.monkey.retromusic.network.Result
|
||||
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.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
||||
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.core.parameter.parametersOf
|
||||
import java.util.*
|
||||
|
@ -66,13 +76,10 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
setupRecyclerView()
|
||||
postponeEnterTransition()
|
||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||
|
||||
showArtist(it)
|
||||
startPostponedEnterTransition()
|
||||
})
|
||||
detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
|
||||
artistInfo(it)
|
||||
})
|
||||
|
||||
|
||||
playAction.apply {
|
||||
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
||||
|
@ -133,6 +140,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
albumTitle.text = albumText
|
||||
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
||||
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
||||
|
||||
}
|
||||
|
||||
private fun loadBiography(
|
||||
|
@ -141,7 +149,14 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
) {
|
||||
biography = null
|
||||
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?) {
|
||||
|
@ -175,23 +190,26 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
private fun loadArtistImage(artist: Artist) {
|
||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||
.generatePalette(requireContext()).build()
|
||||
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
startPostponedEnterTransition()
|
||||
setColors(colors)
|
||||
.dontAnimate()
|
||||
.into(object : SingleColorTarget(image) {
|
||||
override fun onColorReady(color: Int) {
|
||||
setColors(color)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setColors(color: MediaNotificationProcessor) {
|
||||
shuffleAction.applyColor(color.backgroundColor)
|
||||
playAction.applyColor(color.backgroundColor)
|
||||
private fun setColors(color: Int) {
|
||||
val finalColor = if (PreferenceUtil.isAdaptiveColor) color
|
||||
else ThemeStore.accentColor(requireContext())
|
||||
shuffleAction.applyColor(finalColor)
|
||||
playAction.applyOutlineColor(finalColor)
|
||||
}
|
||||
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf("extra_album_id" to albumId),
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
null,
|
||||
FragmentNavigatorExtras(
|
||||
view to getString(R.string.transition_album_art)
|
||||
|
@ -216,7 +234,13 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
return true
|
||||
}
|
||||
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
|
||||
}
|
||||
R.id.action_set_artist_image -> {
|
||||
|
|
|
@ -1,51 +1,37 @@
|
|||
package code.name.monkey.retromusic.fragments.artists
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.liveData
|
||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||
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 kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
||||
class ArtistDetailsViewModel(
|
||||
private val realRepository: RealRepository,
|
||||
private val artistId: Int
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val loadArtistDetailsAsync: Deferred<Artist?>
|
||||
get() = viewModelScope.async(Dispatchers.IO) {
|
||||
realRepository.artistById(artistId)
|
||||
}
|
||||
|
||||
private val _artist = MutableLiveData<Artist>()
|
||||
private val _lastFmArtist = MutableLiveData<LastFmArtist>()
|
||||
|
||||
fun getArtist(): LiveData<Artist> = _artist
|
||||
fun getArtistInfo(): LiveData<LastFmArtist> = _lastFmArtist
|
||||
|
||||
init {
|
||||
loadArtistDetails()
|
||||
fun getArtist(): LiveData<Artist> = liveData(IO) {
|
||||
val artist = realRepository.artistById(artistId)
|
||||
emit(artist)
|
||||
}
|
||||
|
||||
private fun loadArtistDetails() = viewModelScope.launch {
|
||||
val artist =
|
||||
loadArtistDetailsAsync.await() ?: throw NullPointerException("Album couldn't found")
|
||||
_artist.postValue(artist)
|
||||
}
|
||||
|
||||
fun loadBiography(name: String, lang: String?, cache: String?) = viewModelScope.launch {
|
||||
fun getArtistInfo(
|
||||
name: String,
|
||||
lang: String?,
|
||||
cache: String?
|
||||
): LiveData<Result<LastFmArtist>> = liveData(IO) {
|
||||
emit(Result.Loading)
|
||||
val info = realRepository.artistInfo(name, lang, cache)
|
||||
_lastFmArtist.postValue(info)
|
||||
emit(info)
|
||||
}
|
||||
|
||||
override fun onMediaStoreChanged() {
|
||||
loadArtistDetails()
|
||||
getArtist()
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package code.name.monkey.retromusic.fragments.artists
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.*
|
||||
import android.widget.ImageView
|
||||
import androidx.core.os.bundleOf
|
||||
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.fragments.ReloadType
|
||||
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.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?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.artistsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
libraryViewModel.getArtists().observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
|
@ -104,6 +100,161 @@ class ArtistsFragment :
|
|||
val controller = findActivityNavController(R.id.fragment_container)
|
||||
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 {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package code.name.monkey.retromusic.fragments.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentUris
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
|
@ -15,30 +14,40 @@ import android.widget.Toast
|
|||
import androidx.annotation.LayoutRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
||||
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.extensions.hide
|
||||
import code.name.monkey.retromusic.extensions.whichFragment
|
||||
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.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
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 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 java.io.FileNotFoundException
|
||||
|
||||
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
|
||||
Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
|
||||
|
||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
||||
private var playerAlbumCoverFragment: PlayerAlbumCoverFragment? = null
|
||||
protected val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||
|
||||
|
@ -64,7 +73,13 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
return true
|
||||
}
|
||||
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
|
||||
}
|
||||
R.id.action_clear_playing_queue -> {
|
||||
|
@ -146,9 +161,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
return false
|
||||
}
|
||||
|
||||
protected open fun toggleFavorite(song: Song) {
|
||||
MusicUtil.toggleFavorite(requireActivity(), song)
|
||||
}
|
||||
|
||||
abstract fun playerToolbar(): Toolbar?
|
||||
|
||||
|
@ -170,79 +182,70 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
updateLyrics()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
if (updateIsFavoriteTask != null && !updateIsFavoriteTask!!.isCancelled) {
|
||||
updateIsFavoriteTask!!.cancel(true)
|
||||
}
|
||||
if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) {
|
||||
updateLyricsAsyncTask!!.cancel(true)
|
||||
}
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@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
|
||||
protected open fun toggleFavorite(song: Song) {
|
||||
lifecycleScope.launch(IO) {
|
||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||
if (playlist != null) {
|
||||
val songEntity = song.toSongEntity(playlist.playListId)
|
||||
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
||||
if (isFavorite) {
|
||||
libraryViewModel.removeSongFromPlaylist(songEntity)
|
||||
} else {
|
||||
libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
|
||||
}
|
||||
}
|
||||
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(l: Lyrics?) {
|
||||
setLyrics(l)
|
||||
fun updateIsFavorite() {
|
||||
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?) {
|
||||
onPostExecute(null)
|
||||
private fun updateLyrics() {
|
||||
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?) {
|
||||
|
@ -255,8 +258,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
) {
|
||||
view.findViewById<View>(R.id.status_bar).visibility = View.GONE
|
||||
}
|
||||
playerAlbumCoverFragment =
|
||||
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment?
|
||||
playerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
||||
playerAlbumCoverFragment?.setCallbacks(this)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
|
|
|
@ -290,7 +290,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
}
|
||||
}
|
||||
if (startIndex > -1) {
|
||||
MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true);
|
||||
MusicPlayerRemote.openQueue(songs, startIndex, true);
|
||||
} else {
|
||||
final File finalFile = file1;
|
||||
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
||||
|
|
|
@ -36,7 +36,7 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
|
|||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
|
||||
progressIndicator.hide()
|
||||
setupRecyclerView()
|
||||
detailsViewModel.getSongs().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||
songs(it)
|
||||
|
|
|
@ -21,18 +21,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.adapter.GenreAdapter
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
||||
|
||||
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
|
||||
MainActivityFragmentCallbacks {
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
return false
|
||||
}
|
||||
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.genresLiveData.observe(viewLifecycleOwner, Observer {
|
||||
libraryViewModel.getGenre().observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
|
|
|
@ -16,50 +16,36 @@ package code.name.monkey.retromusic.fragments.home
|
|||
|
||||
import android.app.ActivityOptions
|
||||
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 androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
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.TOP_PLAYED_PLAYLIST
|
||||
import code.name.monkey.retromusic.adapter.HomeAdapter
|
||||
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||
import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest
|
||||
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.PreferenceUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.abs_playlists.*
|
||||
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
||||
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
|
||||
|
||||
class HomeFragment :
|
||||
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 displayMetrics: DisplayMetrics
|
||||
get() {
|
||||
val display = mainActivity.windowManager.defaultDisplay
|
||||
val metrics = DisplayMetrics()
|
||||
display.getMetrics(metrics)
|
||||
return metrics
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setStatusBarColorAuto(view)
|
||||
|
@ -74,31 +60,26 @@ class HomeFragment :
|
|||
|
||||
lastAdded.setOnClickListener {
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to LastAddedPlaylist())
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to LAST_ADDED_PLAYLIST)
|
||||
)
|
||||
}
|
||||
|
||||
topPlayed.setOnClickListener {
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to TopTracksPlaylist())
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to TOP_PLAYED_PLAYLIST)
|
||||
)
|
||||
}
|
||||
|
||||
actionShuffle.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
MusicPlayerRemote.openAndShuffleQueue(
|
||||
repository.allSongs(),
|
||||
true
|
||||
)
|
||||
}
|
||||
libraryViewModel.shuffleSongs()
|
||||
}
|
||||
|
||||
history.setOnClickListener {
|
||||
requireActivity().findNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to HistoryPlaylist())
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to HISTORY_PLAYLIST)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -118,7 +99,7 @@ class HomeFragment :
|
|||
adapter = homeAdapter
|
||||
}
|
||||
|
||||
libraryViewModel.homeLiveData.observe(viewLifecycleOwner, Observer {
|
||||
libraryViewModel.getHome().observe(viewLifecycleOwner, Observer {
|
||||
homeAdapter.swapData(it)
|
||||
})
|
||||
|
||||
|
@ -138,6 +119,14 @@ class HomeFragment :
|
|||
).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 {
|
||||
|
||||
const val TAG: String = "BannerHomeFragment"
|
||||
|
|
|
@ -4,21 +4,26 @@ import android.os.Bundle
|
|||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
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.fragments.base.AbsMainActivityFragment
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import kotlinx.android.synthetic.main.fragment_library.*
|
||||
import java.lang.String
|
||||
|
||||
class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
retainInstance = true
|
||||
mainActivity.hideBottomBarVisibility(true)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.supportActionBar?.title = null
|
||||
|
@ -30,6 +35,17 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
|||
)
|
||||
}
|
||||
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() {
|
||||
|
@ -60,19 +76,15 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
|||
null,
|
||||
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)
|
||||
}
|
||||
|
||||
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.retromusic.R
|
||||
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.extensions.hide
|
||||
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() {
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
||||
.setAllowDragging(false)
|
||||
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
playerQueueSheet.setContentPadding(
|
||||
playerQueueSheet.contentPaddingLeft,
|
||||
(slideOffset * status_bar.height).toInt(),
|
||||
|
@ -83,18 +80,17 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
|
|||
}
|
||||
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
val activity = requireActivity() as AbsSlidingMusicPanelActivity
|
||||
when (newState) {
|
||||
BottomSheetBehavior.STATE_EXPANDED,
|
||||
BottomSheetBehavior.STATE_DRAGGING -> {
|
||||
activity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
}
|
||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||
resetToCurrentPosition()
|
||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
}
|
||||
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.setOnTouchListener { _, _ ->
|
||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
||||
.setAllowDragging(false)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
getQueuePanel().setAllowDragging(true)
|
||||
return@setOnTouchListener false
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ package code.name.monkey.retromusic.fragments.player.fit
|
|||
import android.animation.ObjectAnimator
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
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.service.MusicService
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
import kotlinx.android.synthetic.main.fragment_fit_playback_controls.*
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.annotation.SuppressLint
|
|||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.animation.LinearInterpolator
|
||||
|
@ -18,10 +17,8 @@ import androidx.core.view.ViewCompat
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.RetroBottomSheetBehavior
|
||||
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
||||
import code.name.monkey.retromusic.extensions.hide
|
||||
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 recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
|
||||
private var playingQueueAdapter: PlayingQueueAdapter? = null
|
||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
||||
private lateinit var linearLayoutManager: LinearLayoutManager
|
||||
|
||||
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
||||
.setAllowDragging(false)
|
||||
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
playerQueueSheet.setPadding(
|
||||
playerQueueSheet.paddingLeft,
|
||||
(slideOffset * status_bar.height).toInt(),
|
||||
|
@ -79,18 +73,17 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
}
|
||||
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
val activity = requireActivity() as AbsSlidingMusicPanelActivity
|
||||
when (newState) {
|
||||
BottomSheetBehavior.STATE_EXPANDED,
|
||||
BottomSheetBehavior.STATE_DRAGGING -> {
|
||||
activity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
}
|
||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
||||
resetToCurrentPosition()
|
||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
}
|
||||
else -> {
|
||||
activity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,8 +132,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
private fun setupSheet() {
|
||||
getQueuePanel().addBottomSheetCallback(bottomSheetCallbackList)
|
||||
playerQueueSheet.setOnTouchListener { _, _ ->
|
||||
(requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior()
|
||||
.setAllowDragging(false)
|
||||
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
|
||||
getQueuePanel().setAllowDragging(true)
|
||||
return@setOnTouchListener false
|
||||
}
|
||||
|
@ -159,7 +151,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
recyclerViewDragDropManager?.cancelDrag()
|
||||
super.onPause()
|
||||
progressViewUpdateHelper.stop()
|
||||
|
||||
}
|
||||
|
||||
override fun playerToolbar(): Toolbar? {
|
||||
|
@ -224,9 +215,8 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
|
||||
override fun toggleFavorite(song: Song) {
|
||||
super.toggleFavorite(song)
|
||||
MusicUtil.toggleFavorite(requireContext(), song)
|
||||
if (song.id == MusicPlayerRemote.currentSong.id) {
|
||||
updateFavorite()
|
||||
updateIsFavorite()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,6 +264,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
override fun onQueueChanged() {
|
||||
super.onQueueChanged()
|
||||
updateLabel()
|
||||
playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue)
|
||||
}
|
||||
|
||||
private fun updateSong() {
|
||||
|
@ -372,7 +363,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
} else {
|
||||
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
|
||||
nextSong.apply {
|
||||
text = "Next: $title"
|
||||
text = title
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
@ -478,36 +469,4 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
songTotalTime.text = MusicUtil.getReadableDurationString(total.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.MenuItem
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
|
||||
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.fragments.base.AbsMainActivityFragment
|
||||
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.util.PlaylistsUtil
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
|
||||
|
@ -32,7 +31,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
parametersOf(arguments.extraPlaylist)
|
||||
}
|
||||
|
||||
private lateinit var playlist: Playlist
|
||||
private lateinit var playlist: PlaylistWithSongs
|
||||
private lateinit var adapter: SongAdapter
|
||||
|
||||
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
|
||||
|
@ -46,28 +45,23 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
mainActivity.hideBottomBarVisibility(false)
|
||||
|
||||
playlist = arguments.extraPlaylist
|
||||
toolbar.title = playlist.playlistEntity.playlistName
|
||||
|
||||
setUpRecyclerView()
|
||||
|
||||
viewModel.getSongs().observe(viewLifecycleOwner, Observer {
|
||||
songs(it)
|
||||
})
|
||||
|
||||
viewModel.getPlaylist().observe(viewLifecycleOwner, Observer {
|
||||
playlist = it
|
||||
toolbar.title = it.name
|
||||
viewModel.getSongs().observe(viewLifecycleOwner, {
|
||||
songs(it.toSongs())
|
||||
})
|
||||
}
|
||||
|
||||
private fun setUpRecyclerView() {
|
||||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
if (playlist is AbsCustomPlaylist) {
|
||||
adapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null)
|
||||
recyclerView.adapter = adapter
|
||||
} else {
|
||||
recyclerViewDragDropManager = RecyclerViewDragDropManager()
|
||||
val animator = RefactoredDefaultItemAnimator()
|
||||
adapter = OrderablePlaylistSongAdapter(requireActivity(),
|
||||
recyclerViewDragDropManager = RecyclerViewDragDropManager()
|
||||
val animator = RefactoredDefaultItemAnimator()
|
||||
adapter =
|
||||
OrderablePlaylistSongAdapter(
|
||||
playlist.playlistEntity,
|
||||
requireActivity(),
|
||||
ArrayList(),
|
||||
R.layout.item_list,
|
||||
null,
|
||||
|
@ -75,7 +69,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
|
||||
if (PlaylistsUtil.moveItem(
|
||||
requireContext(),
|
||||
playlist.id,
|
||||
playlist.playlistEntity.playListId,
|
||||
fromPosition,
|
||||
toPosition
|
||||
)
|
||||
|
@ -86,13 +80,13 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
}
|
||||
}
|
||||
})
|
||||
wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter)
|
||||
wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter)
|
||||
|
||||
recyclerView.adapter = wrappedAdapter
|
||||
recyclerView.itemAnimator = animator
|
||||
recyclerView.adapter = wrappedAdapter
|
||||
recyclerView.itemAnimator = animator
|
||||
|
||||
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
|
||||
|
||||
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
|
||||
}
|
||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||
override fun onChanged() {
|
||||
super.onChanged()
|
||||
|
@ -103,9 +97,9 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
val menuRes = if (playlist is AbsCustomPlaylist)
|
||||
val menuRes =/* if (playlist is AbsCustomPlaylist)
|
||||
R.menu.menu_smart_playlist_detail
|
||||
else R.menu.menu_playlist_detail
|
||||
else*/ R.menu.menu_playlist_detail
|
||||
inflater.inflate(menuRes, menu)
|
||||
}
|
||||
|
||||
|
@ -129,7 +123,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
return String(Character.toChars(unicode))
|
||||
}
|
||||
|
||||
public override fun onPause() {
|
||||
override fun onPause() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager!!.cancelDrag()
|
||||
}
|
||||
|
@ -160,11 +154,11 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
}
|
||||
|
||||
fun songs(songs: List<Song>) {
|
||||
progressIndicator.hide()
|
||||
if (songs.isNotEmpty()) {
|
||||
adapter.swapDataSet(songs)
|
||||
} else {
|
||||
showEmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,42 +3,29 @@ package code.name.monkey.retromusic.fragments.playlists
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
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.repository.RealRepository
|
||||
import code.name.monkey.retromusic.util.PlaylistsUtil
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PlaylistDetailsViewModel(
|
||||
private val realRepository: RealRepository,
|
||||
private var playlist: Playlist
|
||||
private var playlist: PlaylistWithSongs
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val _playListSongs = MutableLiveData<List<Song>>()
|
||||
private val _playlist = MutableLiveData<Playlist>().apply {
|
||||
private val _playlist = MutableLiveData<PlaylistWithSongs>().apply {
|
||||
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() {
|
||||
if (playlist !is AbsCustomPlaylist) {
|
||||
/*if (playlist !is AbsCustomPlaylist) {
|
||||
// Playlist deleted
|
||||
if (!PlaylistsUtil.doesPlaylistExist(App.getContext(), playlist.id)) {
|
||||
//TODO Finish the page
|
||||
|
@ -54,7 +41,7 @@ class PlaylistDetailsViewModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
loadPlaylistSongs(playlist)
|
||||
loadPlaylistSongs(playlist)*/
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {}
|
||||
|
@ -64,4 +51,4 @@ class PlaylistDetailsViewModel(
|
|||
override fun onPlayStateChanged() {}
|
||||
override fun onRepeatModeChanged() {}
|
||||
override fun onShuffleModeChanged() {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
package code.name.monkey.retromusic.fragments.playlists
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
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.adapter.playlist.PlaylistAdapter
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
||||
import kotlinx.android.synthetic.main.fragment_library.*
|
||||
|
||||
class PlaylistsFragment :
|
||||
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>(),
|
||||
MainActivityFragmentCallbacks {
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
return false
|
||||
}
|
||||
class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager>() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
libraryViewModel.getPlaylists().observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
|
@ -30,8 +28,8 @@ class PlaylistsFragment :
|
|||
override val emptyMessage: Int
|
||||
get() = R.string.no_playlists
|
||||
|
||||
override fun createLayoutManager(): GridLayoutManager {
|
||||
return GridLayoutManager(requireContext(), 1)
|
||||
override fun createLayoutManager(): LinearLayoutManager {
|
||||
return LinearLayoutManager(requireContext())
|
||||
}
|
||||
|
||||
override fun createAdapter(): PlaylistAdapter {
|
||||
|
@ -43,9 +41,18 @@ class PlaylistsFragment :
|
|||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): PlaylistsFragment {
|
||||
return PlaylistsFragment()
|
||||
}
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
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.fragments.base.AbsRecyclerViewFragment
|
||||
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.draggable.RecyclerViewDragDropManager
|
||||
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.
|
||||
*/
|
||||
class PlayingQueueFragment :
|
||||
AbsRecyclerViewFragment<PlayingQueueAdapter, LinearLayoutManager>(),
|
||||
MainActivityFragmentCallbacks {
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
return false
|
||||
}
|
||||
class PlayingQueueFragment : AbsRecyclerViewFragment<PlayingQueueAdapter, LinearLayoutManager>() {
|
||||
|
||||
private lateinit var wrappedAdapter: RecyclerView.Adapter<*>
|
||||
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
|
||||
|
|
|
@ -6,9 +6,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class SearchViewModel(private val realRepository: RealRepository) : ViewModel() {
|
||||
private val results = MutableLiveData<MutableList<Any>>()
|
||||
|
@ -17,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel()
|
|||
|
||||
fun search(query: String?) = viewModelScope.launch(IO) {
|
||||
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)
|
||||
|
||||
buyProContainer.apply {
|
||||
if (!App.isProVersion()) show() else hide()
|
||||
if (App.isProVersion()) hide() else show()
|
||||
setOnClickListener {
|
||||
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