diff --git a/.gitignore b/.gitignore
index 37f05b7f5..6a32941f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,8 +38,4 @@ obj/
captures
app/normal/release/
/models/
-
-app/font/
-app/src/debug/
-/app/nofont/
-/crowdin.properties
+/app/release/
diff --git a/app/build.gradle b/app/build.gradle
index 6b4cc101a..692677dd2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,20 +2,11 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
-apply plugin: "ru.cleverpumpkin.proguard-dictionaries-generator"
apply plugin: "androidx.navigation.safeargs.kotlin"
-proguardDictionaries {
- dictionaryNames = [
- "build/class-dictionary",
- "build/package-dictionary",
- "build/obfuscation-dictionary"
- ]
-}
-
android {
compileSdkVersion 29
- buildToolsVersion = '30.0.0'
+ buildToolsVersion = '30.0.1'
defaultConfig {
minSdkVersion 21
@@ -25,7 +16,7 @@ android {
vectorDrawables.useSupportLibrary = true
applicationId 'io.github.muntashirakon.Music'
- versionCode 10443
+ versionCode 10444
versionName '3.5.10'
multiDexEnabled true
@@ -73,66 +64,51 @@ android {
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-rc1'
- implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ def nav_version = "2.3.0"
+ implementation "androidx.navigation:navigation-runtime-ktx:$nav_version"
+ 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-alpha02'
- implementation 'androidx.legacy:legacy-support-v4:1.0.0'
-
- 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.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 '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"
@@ -142,7 +118,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'
}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 5e2e2be56..a7f474df0 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -41,25 +41,14 @@
public *;
}
--keep class !android.support.v7.internal.view.menu.**,** {*;}
-dontwarn
-ignorewarnings
--keep public class android.support.design.widget.BottomNavigationView { *; }
--keep public class android.support.design.internal.BottomNavigationMenuView { *; }
--keep public class android.support.design.internal.BottomNavigationPresenter { *; }
--keep public class android.support.design.internal.BottomNavigationItemView { *; }
-
#-dontwarn android.support.v8.renderscript.*
#-keepclassmembers class android.support.v8.renderscript.RenderScript {
# native *** rsn*(...);
# native *** n*(...);
#}
-#-keep class org.jaudiotagger.** { *; }
-
-
--obfuscationdictionary build/obfuscation-dictionary.txt
--classobfuscationdictionary build/class-dictionary.txt
--packageobfuscationdictionary build/package-dictionary.txt
+#-keep class org.jaudiotagger.** { *; }
\ No newline at end of file
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
deleted file mode 100644
index 08c9ac789..000000000
--- a/app/release/output-metadata.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "version": 1,
- "artifactType": {
- "type": "APK",
- "kind": "Directory"
- },
- "applicationId": "io.github.muntashirakon.Music",
- "variantName": "release",
- "elements": [
- {
- "type": "SINGLE",
- "filters": [],
- "properties": [],
- "versionCode": 10443,
- "versionName": "3.5.10",
- "enabled": true,
- "outputFile": "app-release.apk"
- }
- ]
-}
\ No newline at end of file
diff --git a/app/src/debug/res/font/bold.ttf b/app/src/debug/res/font/bold.ttf
new file mode 100644
index 000000000..96619df92
Binary files /dev/null and b/app/src/debug/res/font/bold.ttf differ
diff --git a/app/src/debug/res/font/google_sans_bold.ttf b/app/src/debug/res/font/google_sans_bold.ttf
new file mode 100644
index 000000000..80497666e
Binary files /dev/null and b/app/src/debug/res/font/google_sans_bold.ttf differ
diff --git a/app/src/debug/res/font/google_sans_medium.ttf b/app/src/debug/res/font/google_sans_medium.ttf
new file mode 100644
index 000000000..1543660da
Binary files /dev/null and b/app/src/debug/res/font/google_sans_medium.ttf differ
diff --git a/app/src/debug/res/font/google_sans_regular.ttf b/app/src/debug/res/font/google_sans_regular.ttf
new file mode 100644
index 000000000..ab605f9e2
Binary files /dev/null and b/app/src/debug/res/font/google_sans_regular.ttf differ
diff --git a/app/src/debug/res/font/medium.ttf b/app/src/debug/res/font/medium.ttf
new file mode 100644
index 000000000..fd818d6f5
Binary files /dev/null and b/app/src/debug/res/font/medium.ttf differ
diff --git a/app/src/debug/res/font/regular.ttf b/app/src/debug/res/font/regular.ttf
new file mode 100644
index 000000000..e2c69c3fb
Binary files /dev/null and b/app/src/debug/res/font/regular.ttf differ
diff --git a/app/src/debug/res/font/sans.xml b/app/src/debug/res/font/sans.xml
new file mode 100644
index 000000000..7bbc8513b
--- /dev/null
+++ b/app/src/debug/res/font/sans.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml
new file mode 100644
index 000000000..81154a395
--- /dev/null
+++ b/app/src/debug/res/values/styles.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d90e768d1..26f52498e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -115,6 +115,7 @@
+
+
-
diff --git a/app/src/main/assets/contributors.json b/app/src/main/assets/contributors.json
index 2efd24509..b76201619 100644
--- a/app/src/main/assets/contributors.json
+++ b/app/src/main/assets/contributors.json
@@ -13,13 +13,13 @@
},
{
"name": "Daksh P. Jain",
- "summary": "Telegram group maintainer",
- "link": "https://dakshpjain.eu.org",
+ "summary": "Support Representative & Moderator",
+ "link": "https://daksh.eu.org",
"profile_image": "https://i.imgur.com/fnYpg65.jpg"
},
{
"name": "Milind Goel",
- "summary": "Github & Telegram maintainer",
+ "summary": "Support Representative & Moderator",
"link": "https://t.me/MilindGoel15",
"profile_image": "https://i.imgur.com/Bz4De21_d.jpg"
}
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
index f9c45db6b..a4a872d34 100644
Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/java/io/github/muntashirakon/music/Constants.kt b/app/src/main/java/io/github/muntashirakon/music/Constants.kt
index 85c8c327b..5e3755eb3 100644
--- a/app/src/main/java/io/github/muntashirakon/music/Constants.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/Constants.kt
@@ -30,7 +30,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"
diff --git a/app/src/main/java/io/github/muntashirakon/music/HomeSection.kt b/app/src/main/java/io/github/muntashirakon/music/HomeSection.kt
index 237e5bca6..1db2e52cc 100644
--- a/app/src/main/java/io/github/muntashirakon/music/HomeSection.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/HomeSection.kt
@@ -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
\ No newline at end of file
+const val PLAYLISTS = 7
+const val HISTORY_PLAYLIST = 8
+const val LAST_ADDED_PLAYLIST = 9
+const val TOP_PLAYED_PLAYLIST = 10
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/MainModule.kt b/app/src/main/java/io/github/muntashirakon/music/MainModule.kt
index af439dcb6..72a808366 100644
--- a/app/src/main/java/io/github/muntashirakon/music/MainModule.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/MainModule.kt
@@ -1,5 +1,12 @@
package io.github.muntashirakon.music
+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 io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.fragments.albums.AlbumDetailsViewModel
import io.github.muntashirakon.music.fragments.artists.ArtistDetailsViewModel
@@ -7,17 +14,103 @@ import io.github.muntashirakon.music.fragments.genres.GenreDetailsViewModel
import io.github.muntashirakon.music.fragments.playlists.PlaylistDetailsViewModel
import io.github.muntashirakon.music.fragments.search.SearchViewModel
import io.github.muntashirakon.music.model.Genre
-import io.github.muntashirakon.music.model.Playlist
-import io.github.muntashirakon.music.network.networkModule
+import io.github.muntashirakon.music.network.*
import io.github.muntashirakon.music.repository.*
+import io.github.muntashirakon.music.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().insertBlacklistPath(BlackListStoreEntity(it))
+ }
+ }
+ }
+ })
+ .fallbackToDestructiveMigration()
+ .build()
+ }
+ factory {
+ get().lyricsDao()
+ }
+
+ factory {
+ get().playlistDao()
+ }
+
+ factory {
+ get().blackListStore()
+ }
+
+ factory {
+ get().playCountDao()
+ }
+
+ factory {
+ get().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 {
@@ -73,21 +162,21 @@ private val viewModules = module {
LibraryViewModel(get())
}
- viewModel { (albumId: Int) ->
+ viewModel { (albumId: Long) ->
AlbumDetailsViewModel(
get(),
albumId
)
}
- viewModel { (artistId: Int) ->
+ viewModel { (artistId: Long) ->
ArtistDetailsViewModel(
get(),
artistId
)
}
- viewModel { (playlist: Playlist) ->
+ viewModel { (playlist: PlaylistWithSongs) ->
PlaylistDetailsViewModel(
get(),
playlist
@@ -106,4 +195,4 @@ private val viewModules = module {
}
}
-val appModules = listOf(dataModule, viewModules, networkModule)
\ No newline at end of file
+val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule)
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/DriveModeActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/DriveModeActivity.kt
index 51c17e796..6435aec1c 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/DriveModeActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/DriveModeActivity.kt
@@ -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) {
}
})
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/MainActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/MainActivity.kt
index 665823529..00e04b216 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/MainActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/MainActivity.kt
@@ -3,30 +3,23 @@ package io.github.muntashirakon.music.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 io.github.muntashirakon.music.*
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
import io.github.muntashirakon.music.extensions.findNavController
-import io.github.muntashirakon.music.fragments.LibraryViewModel
-import io.github.muntashirakon.music.helper.MusicPlayerRemote.openAndShuffleQueue
-import io.github.muntashirakon.music.helper.MusicPlayerRemote.openQueue
-import io.github.muntashirakon.music.helper.MusicPlayerRemote.playFromUri
-import io.github.muntashirakon.music.helper.MusicPlayerRemote.shuffleMode
+import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.SearchQueryHelper.getSongs
import io.github.muntashirakon.music.model.Song
-import io.github.muntashirakon.music.repository.PlaylistSongsLoader.getPlaylistSongList
-import io.github.muntashirakon.music.repository.Repository
+import io.github.muntashirakon.music.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.service.MusicService
-import io.github.muntashirakon.music.util.AppRater.appLaunched
+import io.github.muntashirakon.music.util.AppRater
import io.github.muntashirakon.music.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,11 +28,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
const val APP_UPDATE_REQUEST_CODE = 9002
}
- private val repository by inject()
- private val libraryViewModel by inject()
-
- private var blockRequestPermissions = false
-
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_main_content)
}
@@ -47,13 +35,15 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
+ if (!hasPermissions()) {
+ findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
+ }
setStatusbarColorAuto()
setNavigationbarColorAuto()
setLightNavigationBar(true)
setTaskDescriptionColorAuto()
hideStatusBar()
- appLaunched(this)
- addMusicServiceEventListener(libraryViewModel)
+ AppRater.appLaunched(this)
updateTabs()
}
@@ -72,24 +62,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
}
}
- override fun onDestroy() {
- super.onDestroy()
- PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
- }
-
- override fun requestPermissions() {
- if (!blockRequestPermissions) {
- super.requestPermissions()
- }
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
- if (!hasPermissions()) {
- requestPermissions()
- }
- }
-
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == GENERAL_THEME || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TOGGLE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES
) {
@@ -99,64 +71,71 @@ 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 =
- 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 =
- ArrayList(getPlaylistSongList(this, id))
- openQueue(songs, position, 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)
- 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())
- }
+ handlePlaybackIntent(intent)
}
- private fun parseIdFromIntent(
+ 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 = getSongs(intent.extras!!)
+ if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
+ MusicPlayerRemote.openAndShuffleQueue(songs, true)
+ } else {
+ MusicPlayerRemote.openQueue(songs, 0, true)
+ }
+ handled = true
+ }
+ if (uri != null && uri.toString().isNotEmpty()) {
+ MusicPlayerRemote.playFromUri(uri)
+ handled = true
+ } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
+ val id = parseLongFromIntent(intent, "playlistId", "playlist")
+ if (id >= 0L) {
+ val position: Int = intent.getIntExtra("position", 0)
+ val songs: List =
+ PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id)
+ MusicPlayerRemote.openQueue(songs, position, true)
+ handled = true
+ }
+ } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
+ val id = parseLongFromIntent(intent, "albumId", "album")
+ if (id >= 0L) {
+ 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 = parseLongFromIntent(intent, "artistId", "artist")
+ if (id >= 0L) {
+ val position: Int = intent.getIntExtra("position", 0)
+ MusicPlayerRemote.openQueue(
+ libraryViewModel.artistById(id).songs,
+ position,
+ true
+ )
+ handled = true
+ }
+ }
+ if (handled) {
+ setIntent(Intent())
+ }
+ }
+
+ }
+
+ private fun parseLongFromIntent(
intent: Intent, longKey: String,
stringKey: String
): Long {
@@ -167,7 +146,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
try {
id = idString.toLong()
} catch (e: NumberFormatException) {
- Log.e(TAG, e.message)
+ println(e.message)
}
}
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/PermissionActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/PermissionActivity.kt
new file mode 100644
index 000000000..b448836a1
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/PermissionActivity.kt
@@ -0,0 +1,63 @@
+package code.name.monkey.retromusic.activities
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.provider.Settings
+import androidx.core.text.HtmlCompat
+import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.appthemehelper.util.VersionUtils
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
+import code.name.monkey.retromusic.extensions.accentBackgroundColor
+import code.name.monkey.retromusic.extensions.show
+import code.name.monkey.retromusic.util.RingtoneManager
+import kotlinx.android.synthetic.main.activity_permission.*
+import kotlinx.android.synthetic.main.fragment_library.appNameText
+
+
+class PermissionActivity : AbsMusicServiceActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView((R.layout.activity_permission))
+ setStatusbarColorAuto()
+ setNavigationbarColorAuto()
+ setLightNavigationBar(true)
+ setTaskDescriptionColorAuto()
+ setupTitle()
+
+ storagePermission.setButtonClick {
+ requestPermissions()
+ }
+ if (VersionUtils.hasMarshmallow()) audioPermission.show()
+ audioPermission.setButtonClick {
+ if (RingtoneManager.requiresDialog(this@PermissionActivity)) {
+ val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
+ intent.data = Uri.parse("package:" + applicationContext.packageName)
+ startActivity(intent)
+ }
+ }
+ finish.accentBackgroundColor()
+ finish.setOnClickListener {
+ if (hasPermissions() && !RingtoneManager.requiresDialog(this)) {
+ startActivity(
+ Intent(this, MainActivity::class.java).addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK
+ )
+ )
+ finish()
+ }
+ }
+ }
+
+ private fun setupTitle() {
+ val color = ThemeStore.accentColor(this)
+ val hexColor = String.format("#%06X", 0xFFFFFF and color)
+ val appName = HtmlCompat.fromHtml(
+ "Hello there!
Welcome to Retro Music",
+ HtmlCompat.FROM_HTML_MODE_COMPACT
+ )
+ appNameText.text = appName
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/PlayingQueueActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/PlayingQueueActivity.kt
index ad4661670..40bdff127 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/PlayingQueueActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/PlayingQueueActivity.kt
@@ -104,7 +104,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
}
}
})
- val fastScroller = ThemedFastScroller.create(recyclerView)
+ ThemedFastScroller.create(recyclerView)
}
private fun checkForPadding() {
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsBaseActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsBaseActivity.kt
index 5ee650c7f..a797a2809 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsBaseActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsBaseActivity.kt
@@ -46,7 +46,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
if (!hasPermissions()) {
- requestPermissions()
+ //requestPermissions()
}
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsMusicServiceActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsMusicServiceActivity.kt
index c7da95d2a..9d10348df 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsMusicServiceActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsMusicServiceActivity.kt
@@ -4,17 +4,23 @@ import android.Manifest
import android.content.*
import android.os.Bundle
import android.os.IBinder
+import androidx.lifecycle.lifecycleScope
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.db.toPlayCount
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
+import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.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()
-
+ 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() {
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsSlidingMusicPanelActivity.kt
index e05776f72..c06f0a7c4 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsSlidingMusicPanelActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/base/AbsSlidingMusicPanelActivity.kt
@@ -12,11 +12,9 @@ import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
-import com.google.android.material.bottomsheet.BottomSheetBehavior
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.RetroBottomSheetBehavior
import io.github.muntashirakon.music.extensions.hide
-import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.extensions.whichFragment
import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.fragments.MiniPlayerFragment
@@ -26,6 +24,7 @@ import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.model.CategoryInfo
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.views.BottomNavigationBarTinted
+import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -34,7 +33,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
- private val libraryViewModel by viewModel()
+ protected val libraryViewModel by viewModel()
private lateinit var behavior: RetroBottomSheetBehavior
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()
@@ -186,6 +178,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
behavior.isHideable = true
behavior.peekHeight = 0
collapsePanel()
+ ViewCompat.setElevation(slidingPanel, 0f)
ViewCompat.setElevation(bottomNavigationView, 10f)
} else {
ViewCompat.setElevation(bottomNavigationView, 10f)
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/bugreport/model/DeviceInfo.java b/app/src/main/java/io/github/muntashirakon/music/activities/bugreport/model/DeviceInfo.java
index a8d4c50f3..e1f12ddee 100644
--- a/app/src/main/java/io/github/muntashirakon/music/activities/bugreport/model/DeviceInfo.java
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/bugreport/model/DeviceInfo.java
@@ -87,7 +87,7 @@ public class DeviceInfo {
return "Device info:\n"
+ "---\n"
+ "\n"
- + "App version | " + versionName + " |
\n"
+ + "App version | " + versionName + " |
\n"
+ "App version code | " + versionCode + " |
\n"
+ "Android build version | " + buildVersion + " |
\n"
+ "Android release version | " + releaseVersion + " |
\n"
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AbsTagEditorActivity.kt
index 67f300d90..7a13acf8d 100755
--- a/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AbsTagEditorActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AbsTagEditorActivity.kt
@@ -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
@@ -41,7 +40,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
val repository by inject()
lateinit var saveFab: MaterialButton
- protected var id: Int = 0
+ protected var id: Long = 0
private set
private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false
@@ -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()
}
@@ -254,11 +251,11 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private fun getIntentExtras() {
val intentExtras = intent.extras
if (intentExtras != null) {
- id = intentExtras.getInt(EXTRA_ID)
+ id = intentExtras.getLong(EXTRA_ID)
}
}
- protected abstract suspend fun getSongPaths(): List
+ protected abstract fun getSongPaths(): List
protected fun searchWebFor(vararg keys: String) {
val stringBuilder = StringBuilder()
@@ -399,7 +396,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
}
}
- class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
+ class ArtworkInfo constructor(val albumId: Long, val artwork: Bitmap?)
companion object {
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AlbumTagEditorActivity.kt
index 9f01b7063..a4d2c3814 100755
--- a/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AlbumTagEditorActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/AlbumTagEditorActivity.kt
@@ -14,17 +14,18 @@ import android.transition.Slide
import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil
-import com.bumptech.glide.Glide
-import com.bumptech.glide.load.engine.DiskCacheStrategy
-import com.bumptech.glide.request.animation.GlideAnimation
-import com.bumptech.glide.request.target.SimpleTarget
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.extensions.appHandleColor
import io.github.muntashirakon.music.glide.palette.BitmapPaletteTranscoder
import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
+import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.ImageUtil
import io.github.muntashirakon.music.util.RetroColorUtil.generatePalette
import io.github.muntashirakon.music.util.RetroColorUtil.getColor
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.bumptech.glide.request.animation.GlideAnimation
+import com.bumptech.glide.request.target.SimpleTarget
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.tag.FieldKey
import java.util.*
@@ -44,9 +45,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() {
@@ -167,13 +168,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
)
}
- override suspend fun getSongPaths(): List {
- val songs = repository.albumById(id).songs
- val paths = ArrayList(songs!!.size)
- for (song in songs) {
- paths.add(song.data)
- }
- return paths
+ override fun getSongPaths(): List {
+ return repository.albumById(id).songs
+ .map(Song::data)
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
diff --git a/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/SongTagEditorActivity.kt b/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/SongTagEditorActivity.kt
index 30ae4ce48..baf9f580f 100755
--- a/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/SongTagEditorActivity.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/activities/tageditor/SongTagEditorActivity.kt
@@ -88,7 +88,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
writeValuesToFiles(fieldKeyValueMap, null)
}
- override suspend fun getSongPaths(): List {
+ override fun getSongPaths(): List {
val paths = ArrayList(1)
paths.add(songRepository.song(id).data)
return paths
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/CategoryInfoAdapter.java b/app/src/main/java/io/github/muntashirakon/music/adapter/CategoryInfoAdapter.java
index c31276854..55132839c 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/CategoryInfoAdapter.java
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/CategoryInfoAdapter.java
@@ -71,13 +71,13 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter {
- if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) {
- categoryInfo.visible = !categoryInfo.visible;
- holder.checkBox.setChecked(categoryInfo.visible);
+ if (!(categoryInfo.isVisible() && isLastCheckedCategory(categoryInfo))) {
+ categoryInfo.setVisible(!categoryInfo.isVisible());
+ holder.checkBox.setChecked(categoryInfo.isVisible());
} else {
Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category,
Toast.LENGTH_SHORT).show();
@@ -110,9 +110,9 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter,
private val mItemLayoutRes: Int
) : RecyclerView.Adapter() {
-
-
+ val colors = listOf(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(),
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/HomeAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/HomeAdapter.kt
index ac163e1a7..0d9d57955 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/HomeAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/HomeAdapter.kt
@@ -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, 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, 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, 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)
layoutManager = gridLayoutManager()
}
}
}
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
- fun bindView(artists: List, titleRes: Int) {
+ fun bindView(home: Home) {
+ title.setText(home.titleRes)
recyclerView.apply {
layoutManager = linearLayoutManager()
- adapter = artistsAdapter(artists as List)
+ adapter = artistsAdapter(home.arrayList as List)
}
- title.text = activity.getString(titleRes)
}
}
@@ -161,8 +167,7 @@ class HomeAdapter(
R.id.image8
)
- fun bindView(songs: List) {
- songs as List
+ fun bindView(home: Home) {
val color = ThemeStore.accentColor(activity)
itemView.findViewById(R.id.message).setTextColor(color)
itemView.findViewById(R.id.card6).apply {
@@ -170,9 +175,9 @@ class HomeAdapter(
}
images.forEachIndexed { index, id ->
itemView.findViewById(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, titleRes: Int) {
- arrow.hide()
+ fun bindView(home: Home) {
+ title.setText(home.titleRes)
recyclerView.apply {
val songAdapter = SongAdapter(
activity,
- songs as MutableList,
+ home.arrayList as MutableList,
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, 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,
+ R.layout.item_grid_genre
+ )
recyclerView.apply {
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
- val genreAdapter =
- GenreAdapter(activity, genres as List, 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)
@@ -226,7 +233,7 @@ class HomeAdapter(
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
- override fun onArtist(artistId: Int, imageView: ImageView) {
+ override fun onArtist(artistId: Long, imageView: ImageView) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId),
@@ -237,7 +244,7 @@ class HomeAdapter(
)
}
- override fun onAlbumClick(albumId: Int, view: View) {
+ override fun onAlbumClick(albumId: Long, view: View) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId),
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/SearchAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/SearchAdapter.kt
index fcef5c254..8726619d8 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/SearchAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/SearchAdapter.kt
@@ -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
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumAdapter.kt
index 011356c60..0ad1834e4 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumAdapter.kt
@@ -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)
}
@@ -137,7 +136,7 @@ open class AlbumAdapter(
private fun getSongList(albums: List): List {
val songs = ArrayList()
for (album in albums) {
- songs.addAll(album.songs!!)
+ songs.addAll(album.songs)
}
return songs
}
@@ -171,7 +170,7 @@ open class AlbumAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
- image?.let { albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, it) }
+ albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, itemView)
}
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumCoverPagerAdapter.kt
index 16a6bcba4..64d1ca381 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumCoverPagerAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/album/AlbumCoverPagerAdapter.kt
@@ -90,6 +90,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 +98,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(),
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/album/HorizontalAlbumAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/album/HorizontalAlbumAdapter.kt
index cb6dd36e1..9d53628f5 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/album/HorizontalAlbumAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/album/HorizontalAlbumAdapter.kt
@@ -3,8 +3,6 @@ package io.github.muntashirakon.music.adapter.album
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
-import code.name.monkey.appthemehelper.util.ATHUtil
-import com.bumptech.glide.Glide
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
import io.github.muntashirakon.music.glide.AlbumGlideRequest
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
@@ -13,6 +11,7 @@ import io.github.muntashirakon.music.interfaces.CabHolder
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
+import com.bumptech.glide.Glide
class HorizontalAlbumAdapter(
activity: FragmentActivity,
@@ -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!!) {
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/base/MediaEntryViewHolder.java b/app/src/main/java/io/github/muntashirakon/music/adapter/base/MediaEntryViewHolder.java
index 86d7982bf..8895d1e7d 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/base/MediaEntryViewHolder.java
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/base/MediaEntryViewHolder.java
@@ -113,6 +113,7 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
itemView.setOnLongClickListener(this);
}
+ @Nullable
@Override
public View getSwipeableContainerView() {
return null;
@@ -129,11 +130,12 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
}
public void setImageTransitionName(@NonNull String transitionName) {
- if (imageContainerCard != null) {
+ itemView.setTransitionName(transitionName);
+ /* if (imageContainerCard != null) {
imageContainerCard.setTransitionName(transitionName);
}
if (image != null) {
image.setTransitionName(transitionName);
- }
+ }*/
}
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/LegacyPlaylistAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/LegacyPlaylistAdapter.kt
new file mode 100644
index 000000000..c74c8a5f9
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/LegacyPlaylistAdapter.kt
@@ -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,
+ private val layoutRes: Int,
+ private val playlistClickListener: PlaylistClickListener
+) :
+ RecyclerView.Adapter() {
+
+ fun swapData(list: List) {
+ 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)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/PlaylistAdapter.kt
index 223cff33d..70f0ef9af 100755
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/PlaylistAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/playlist/PlaylistAdapter.kt
@@ -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 io.github.muntashirakon.music.EXTRA_PLAYLIST
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.db.PlaylistWithSongs
+import io.github.muntashirakon.music.db.SongEntity
+import io.github.muntashirakon.music.db.toSongs
import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
import io.github.muntashirakon.music.interfaces.CabHolder
-import io.github.muntashirakon.music.model.AbsCustomPlaylist
import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.model.Song
-import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist
import io.github.muntashirakon.music.repository.PlaylistSongsLoader
import io.github.muntashirakon.music.util.AutoGeneratedPlaylistBitmap
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.RetroColorUtil
-import java.util.*
class PlaylistAdapter(
private val activity: FragmentActivity,
- var dataSet: List,
+ var dataSet: List,
private var itemLayoutRes: Int,
cabHolder: CabHolder?
-) : AbsMultiSelectAdapter(
+) : AbsMultiSelectAdapter(
activity,
cabHolder,
R.menu.menu_playlists_selection
) {
-
init {
setHasStableIds(true)
}
- fun swapDataSet(dataSet: List) {
+ fun swapDataSet(dataSet: List) {
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) {
+ override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
when (menuItem.itemId) {
else -> SongsMenuHelper.handleMenuClick(
activity,
@@ -132,37 +119,26 @@ class PlaylistAdapter(
}
}
- private fun getSongList(playlists: List): List {
- val songs = ArrayList()
- 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): List {
+ val songs = mutableListOf()
+ playlists.forEach {
+ songs.addAll(it.songs.toSongs())
}
return songs
}
- private fun getSongs(playlist: Playlist): List {
- val songs = ArrayList()
- if (playlist is AbsSmartPlaylist) {
- songs.addAll(playlist.songs())
- } else {
- songs.addAll(playlist.getSongs())
+ private fun getSongs(playlist: PlaylistWithSongs): List =
+ mutableListOf().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
}
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/song/OrderablePlaylistSongAdapter.kt
index 0bc4efe30..88ab0eac0 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/song/OrderablePlaylistSongAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/song/OrderablePlaylistSongAdapter.kt
@@ -3,19 +3,23 @@ package io.github.muntashirakon.music.adapter.song
import android.view.MenuItem
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.db.PlaylistEntity
+import code.name.monkey.retromusic.db.toSongEntity
+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
+import code.name.monkey.retromusic.util.ViewUtil
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
-import io.github.muntashirakon.music.R
-import io.github.muntashirakon.music.R.menu
-import io.github.muntashirakon.music.dialogs.RemoveFromPlaylistDialog
-import io.github.muntashirakon.music.interfaces.CabHolder
-import io.github.muntashirakon.music.model.PlaylistSong
-import io.github.muntashirakon.music.model.Song
-import io.github.muntashirakon.music.util.ViewUtil
class OrderablePlaylistSongAdapter(
+ private val playlist: PlaylistEntity,
activity: FragmentActivity,
dataSet: ArrayList,
itemLayoutRes: Int,
@@ -54,8 +58,8 @@ class OrderablePlaylistSongAdapter(
override fun onMultipleItemAction(menuItem: MenuItem, selection: List) {
when (menuItem.itemId) {
R.id.action_remove_from_playlist -> {
- RemoveFromPlaylistDialog.create(selection as ArrayList)
- .show(activity.supportFragmentManager, "ADD_PLAYLIST")
+ RemoveSongFromPlaylistDialog.create(selection.toSongs(playlist.playListId))
+ .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
return
}
}
@@ -118,7 +122,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
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/adapter/song/PlayingQueueAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/adapter/song/PlayingQueueAdapter.kt
index 4f3c1891a..96a939710 100644
--- a/app/src/main/java/io/github/muntashirakon/music/adapter/song/PlayingQueueAdapter.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/adapter/song/PlayingQueueAdapter.kt
@@ -4,15 +4,6 @@ import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
-import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
-import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
-import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
-import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter
-import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants
-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 io.github.muntashirakon.music.R
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying
@@ -21,6 +12,14 @@ import io.github.muntashirakon.music.helper.MusicPlayerRemote.removeFromQueue
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.ViewUtil
+import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
+import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
+import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
+import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter
+import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants
+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 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(
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreDao.kt b/app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreDao.kt
new file mode 100644
index 000000000..db0dd0f64
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreDao.kt
@@ -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)
+
+ @Delete
+ suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
+
+ @Query("DELETE FROM BlackListStoreEntity")
+ suspend fun clearBlacklist()
+
+ @Query("SELECT * FROM BlackListStoreEntity")
+ fun blackListPaths(): List
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreEntity.kt b/app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreEntity.kt
new file mode 100644
index 000000000..5ccbce07c
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/BlackListStoreEntity.kt
@@ -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
+)
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/HistoryDao.kt b/app/src/main/java/io/github/muntashirakon/music/db/HistoryDao.kt
new file mode 100644
index 000000000..97288235d
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/HistoryDao.kt
@@ -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: Long): HistoryEntity?
+
+ @Update
+ suspend fun updateHistorySong(historyEntity: HistoryEntity)
+
+ @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
+ fun historySongs(): List
+
+ @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
+ fun observableHistorySongs(): LiveData>
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/HistoryEntity.kt b/app/src/main/java/io/github/muntashirakon/music/db/HistoryEntity.kt
new file mode 100644
index 000000000..a4facd796
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/HistoryEntity.kt
@@ -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: Long,
+ 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: Long,
+ @ColumnInfo(name = "album_name")
+ val albumName: String,
+ @ColumnInfo(name = "artist_id")
+ val artistId: Long,
+ @ColumnInfo(name = "artist_name")
+ val artistName: String,
+ val composer: String?,
+ @ColumnInfo(name = "album_artist")
+ val albumArtist: String?,
+ @ColumnInfo(name = "time_played")
+ val timePlayed: Long
+)
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/LyricsDao.kt b/app/src/main/java/io/github/muntashirakon/music/db/LyricsDao.kt
new file mode 100644
index 000000000..a09b430a2
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/LyricsDao.kt
@@ -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)
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/LyricsEntity.kt b/app/src/main/java/io/github/muntashirakon/music/db/LyricsEntity.kt
new file mode 100644
index 000000000..0cec6431c
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/LyricsEntity.kt
@@ -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
+)
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/PlayCountDao.kt b/app/src/main/java/io/github/muntashirakon/music/db/PlayCountDao.kt
new file mode 100644
index 000000000..4107b7ba5
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/PlayCountDao.kt
@@ -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: Long): List
+
+ @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
+ fun playCountSongs(): List
+
+ @Query("DELETE FROM SongEntity WHERE id =:songId")
+ fun deleteSong(songId: Long)
+
+ @Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id")
+ fun updateQuantity(id: Long)
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/PlayCountEntity.kt b/app/src/main/java/io/github/muntashirakon/music/db/PlayCountEntity.kt
new file mode 100644
index 000000000..0fe6c0885
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/PlayCountEntity.kt
@@ -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: Long,
+ 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: Long,
+ @ColumnInfo(name = "album_name")
+ val albumName: String,
+ @ColumnInfo(name = "artist_id")
+ val artistId: Long,
+ @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
+)
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/PlaylistDao.kt b/app/src/main/java/io/github/muntashirakon/music/db/PlaylistDao.kt
new file mode 100644
index 000000000..36a4e8330
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/PlaylistDao.kt
@@ -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: Long, name: String)
+
+ @Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
+ fun isPlaylistExists(name: String): List
+
+ @Query("SELECT * FROM PlaylistEntity")
+ suspend fun playlists(): List
+
+ @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
+ suspend fun deletePlaylistSongs(playlistId: Long)
+
+ @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
+ suspend fun deleteSongFromPlaylist(playlistId: Long, songId: Long)
+
+ @Transaction
+ @Query("SELECT * FROM PlaylistEntity")
+ suspend fun playlistsWithSongs(): List
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertSongsToPlaylist(songEntities: List)
+
+ @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
+ suspend fun isSongExistsInPlaylist(playlistId: Long, songId: Long): List
+
+ @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId")
+ fun songsFromPlaylist(playlistId: Long): LiveData>
+
+ @Delete
+ suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
+
+ @Delete
+ suspend fun deletePlaylists(playlistEntities: List)
+
+ @Delete
+ suspend fun deletePlaylistSongs(songs: List)
+
+
+ @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
+ fun favoritesSongsLiveData(playlistId: Long): LiveData>
+
+ @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
+ fun favoritesSongs(playlistId: Long): List
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/PlaylistEntity.kt b/app/src/main/java/io/github/muntashirakon/music/db/PlaylistEntity.kt
new file mode 100644
index 000000000..236e9cb40
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/PlaylistEntity.kt
@@ -0,0 +1,17 @@
+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(
+ @PrimaryKey(autoGenerate = true)
+ @ColumnInfo(name = "playlist_id")
+ val playListId: Long = 0,
+ @ColumnInfo(name = "playlist_name")
+ val playlistName: String
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/PlaylistWithSongs.kt b/app/src/main/java/io/github/muntashirakon/music/db/PlaylistWithSongs.kt
new file mode 100644
index 000000000..5a256bde7
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/PlaylistWithSongs.kt
@@ -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
+) : Parcelable
+
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/RetroDatabase.kt b/app/src/main/java/io/github/muntashirakon/music/db/RetroDatabase.kt
new file mode 100644
index 000000000..6be545b6a
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/RetroDatabase.kt
@@ -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
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/SongEntity.kt b/app/src/main/java/io/github/muntashirakon/music/db/SongEntity.kt
new file mode 100644
index 000000000..6a6d236a3
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/SongEntity.kt
@@ -0,0 +1,39 @@
+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(
+ @PrimaryKey(autoGenerate = true)
+ @ColumnInfo(name = "song_key")
+ val songPrimaryKey: Long = 0L,
+ @ColumnInfo(name = "playlist_creator_id")
+ val playlistCreatorId: Long,
+ val id: Long,
+ 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: Long,
+ @ColumnInfo(name = "album_name")
+ val albumName: String,
+ @ColumnInfo(name = "artist_id")
+ val artistId: Long,
+ @ColumnInfo(name = "artist_name")
+ val artistName: String,
+ val composer: String?,
+ @ColumnInfo(name = "album_artist")
+ val albumArtist: String?
+) : Parcelable
+
diff --git a/app/src/main/java/io/github/muntashirakon/music/db/SongExtension.kt b/app/src/main/java/io/github/muntashirakon/music/db/SongExtension.kt
new file mode 100644
index 000000000..03666f0a2
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/db/SongExtension.kt
@@ -0,0 +1,133 @@
+package code.name.monkey.retromusic.db
+
+import code.name.monkey.retromusic.model.Song
+
+fun List.toSongs(): List {
+ return map {
+ it.toSong()
+ }
+}
+
+fun List.toSongs(playlistId: Long): List {
+ return map {
+ it.toSongEntity(playlistId)
+ }
+}
+
+fun Song.toHistoryEntity(timePlayed: Long): HistoryEntity {
+ return HistoryEntity(
+ id = id,
+ title = title,
+ trackNumber = trackNumber,
+ year = year,
+ duration = duration,
+ data = data,
+ dateModified = dateModified,
+ albumId = albumId,
+ albumName = albumName,
+ artistId = artistId,
+ artistName = artistName,
+ composer = composer,
+ albumArtist = albumArtist,
+ timePlayed = timePlayed
+ )
+}
+
+fun Song.toSongEntity(playListId: Long): SongEntity {
+ return SongEntity(
+ playlistCreatorId = playListId,
+ id = id,
+ title = title,
+ trackNumber = trackNumber,
+ year = year,
+ duration = duration,
+ data = data,
+ dateModified = dateModified,
+ albumId = albumId,
+ albumName = albumName,
+ artistId = artistId,
+ artistName = artistName,
+ composer = composer,
+ albumArtist = albumArtist
+ )
+}
+
+fun SongEntity.toSong(): Song {
+ return Song(
+ id = id,
+ title = title,
+ trackNumber = trackNumber,
+ year = year,
+ duration = duration,
+ data = data,
+ dateModified = dateModified,
+ albumId = albumId,
+ albumName = albumName,
+ artistId = artistId,
+ artistName = artistName,
+ composer = composer,
+ albumArtist = albumArtist
+ )
+}
+
+fun PlayCountEntity.toSong(): Song {
+ return Song(
+ id = id,
+ title = title,
+ trackNumber = trackNumber,
+ year = year,
+ duration = duration,
+ data = data,
+ dateModified = dateModified,
+ albumId = albumId,
+ albumName = albumName,
+ artistId = artistId,
+ artistName = artistName,
+ composer = composer,
+ albumArtist = albumArtist
+ )
+}
+
+fun HistoryEntity.toSong(): Song {
+ return Song(
+ id = id,
+ title = title,
+ trackNumber = trackNumber,
+ year = year,
+ duration = duration,
+ data = data,
+ dateModified = dateModified,
+ albumId = albumId,
+ albumName = albumName,
+ artistId = artistId,
+ artistName = artistName,
+ composer = composer,
+ albumArtist = albumArtist
+ )
+}
+
+fun Song.toPlayCount(): PlayCountEntity {
+ return PlayCountEntity(
+ id = id,
+ title = title,
+ trackNumber = trackNumber,
+ year = year,
+ duration = duration,
+ data = data,
+ dateModified = dateModified,
+ albumId = albumId,
+ albumName = albumName,
+ artistId = artistId,
+ artistName = artistName,
+ composer = composer,
+ albumArtist = albumArtist,
+ timePlayed = System.currentTimeMillis(),
+ playCount = 1
+ )
+}
+
+fun List.toSongsEntity(playlistEntity: PlaylistEntity): List {
+ return map {
+ it.toSongEntity(playlistEntity.playListId)
+ }
+}
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/AddToPlaylistDialog.kt
index 79560c438..b76d4b186 100644
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/AddToPlaylistDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/AddToPlaylistDialog.kt
@@ -1,76 +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 io.github.muntashirakon.music.dialogs
import android.app.Dialog
import android.os.Bundle
+import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
+import androidx.lifecycle.lifecycleScope
+import io.github.muntashirakon.music.EXTRA_PLAYLISTS
import io.github.muntashirakon.music.EXTRA_SONG
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.db.SongEntity
+import io.github.muntashirakon.music.db.toSongsEntity
import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.extraNotNull
import io.github.muntashirakon.music.extensions.materialDialog
+import io.github.muntashirakon.music.fragments.LibraryViewModel
+import io.github.muntashirakon.music.fragments.ReloadType.Playlists
import io.github.muntashirakon.music.model.Song
-import io.github.muntashirakon.music.repository.PlaylistRepository
-import io.github.muntashirakon.music.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()
- override fun onCreateDialog(
- savedInstanceState: Bundle?
- ): Dialog {
- val playlists = playlistRepository.playlists()
- val playlistNames = mutableListOf()
+ private val libraryViewModel by sharedViewModel()
+
+ companion object {
+ fun create(playlistEntities: List, song: Song): AddToPlaylistDialog {
+ val list: MutableList = mutableListOf()
+ list.add(song)
+ return create(playlistEntities, list)
+ }
+
+ fun create(playlistEntities: List, songs: List): AddToPlaylistDialog {
+ return AddToPlaylistDialog().apply {
+ arguments = bundleOf(
+ EXTRA_SONG to songs,
+ EXTRA_PLAYLISTS to playlistEntities
+ )
+ }
+ }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val playlistEntities: List =
+ extraNotNull>(EXTRA_PLAYLISTS).value
+ val songs: List = extraNotNull>(EXTRA_SONG).value
+ val playlistNames: MutableList = 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>(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 =
+ songs.toSongsEntity(playlistEntities[which - 1])
+ libraryViewModel.insertSongs(songEntities)
+ libraryViewModel.forceReload(Playlists)
+ }
}
dismiss()
}
.create().colorButtons()
}
-
- companion object {
-
- fun create(song: Song): AddToPlaylistDialog {
- val list = ArrayList()
- list.add(song)
- return create(list)
- }
-
- fun create(songs: List): AddToPlaylistDialog {
- val dialog = AddToPlaylistDialog()
- val args = Bundle()
- args.putParcelableArrayList(EXTRA_SONG, ArrayList(songs))
- dialog.arguments = args
- return dialog
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/CreatePlaylistDialog.kt
index 088fe7d38..35787a8ab 100644
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/CreatePlaylistDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/CreatePlaylistDialog.kt
@@ -1,88 +1,75 @@
-/*
- * 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 io.github.muntashirakon.music.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 io.github.muntashirakon.music.EXTRA_SONG
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.extensions.colorButtons
-import io.github.muntashirakon.music.extensions.extraNotNull
+import io.github.muntashirakon.music.extensions.extra
import io.github.muntashirakon.music.extensions.materialDialog
+import io.github.muntashirakon.music.fragments.LibraryViewModel
+import io.github.muntashirakon.music.fragments.ReloadType.Playlists
import io.github.muntashirakon.music.model.Song
-import io.github.muntashirakon.music.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()
- @SuppressLint("InflateParams")
- override fun onCreateDialog(
- savedInstanceState: Bundle?
- ): Dialog {
+ companion object {
+ fun create(song: Song): CreatePlaylistDialog {
+ val list = mutableListOf()
+ list.add(song)
+ return create(list)
+ }
+
+ fun create(songs: List): 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 = extra>(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>(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 = playlistName))
+ libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId) })
+ 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()
- if (song != null) {
- list.add(song)
- }
- return create(list)
- }
-
- @JvmStatic
- fun create(songs: ArrayList): CreatePlaylistDialog {
- val dialog = CreatePlaylistDialog()
- val args = Bundle()
- args.putParcelableArrayList(EXTRA_SONG, songs)
- dialog.arguments = args
- return dialog
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/DeletePlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/DeletePlaylistDialog.kt
index 6f416a585..8d4359788 100644
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/DeletePlaylistDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/DeletePlaylistDialog.kt
@@ -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 io.github.muntashirakon.music.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 io.github.muntashirakon.music.EXTRA_PLAYLIST
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.extraNotNull
import io.github.muntashirakon.music.extensions.materialDialog
-import io.github.muntashirakon.music.model.Playlist
-import io.github.muntashirakon.music.util.PlaylistsUtil
+import io.github.muntashirakon.music.fragments.LibraryViewModel
+import io.github.muntashirakon.music.fragments.ReloadType
+import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class DeletePlaylistDialog : DialogFragment() {
+ private val libraryViewModel by sharedViewModel()
+
+ companion object {
+
+ fun create(playlist: PlaylistEntity): DeletePlaylistDialog {
+ val list = mutableListOf()
+ list.add(playlist)
+ return create(list)
+ }
+
+ fun create(playlists: List): DeletePlaylistDialog {
+ return DeletePlaylistDialog().apply {
+ arguments = bundleOf(EXTRA_PLAYLIST to playlists)
+ }
+ }
+ }
+
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- val playlists = extraNotNull>(EXTRA_PLAYLIST).value
+ val playlists = extraNotNull>(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()
- list.add(playlist)
- return create(list)
- }
-
- fun create(playlist: ArrayList): DeletePlaylistDialog {
- val dialog = DeletePlaylistDialog()
- val args = Bundle()
- args.putParcelableArrayList(EXTRA_PLAYLIST, playlist)
- dialog.arguments = args
- return dialog
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsAsyncTask.java b/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsAsyncTask.java
deleted file mode 100644
index c038d0aa1..000000000
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsAsyncTask.java
+++ /dev/null
@@ -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 io.github.muntashirakon.music.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 io.github.muntashirakon.music.R;
-import io.github.muntashirakon.music.activities.saf.SAFGuideActivity;
-import io.github.muntashirakon.music.misc.DialogAsyncTask;
-import io.github.muntashirakon.music.model.Song;
-import io.github.muntashirakon.music.util.SAFUtil;
-
-/**
- * Created by hemanths on 2019-07-31.
- */
-public class DeleteSongsAsyncTask extends DialogAsyncTask {
-
- private WeakReference activityWeakReference;
- private WeakReference 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 safUris;
-
- public List songs;
-
- public LoadingInfo(List songs, List 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;
- }
- }
-}
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsDialog.kt
index 43ba88dc5..ae441e4c4 100644
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/DeleteSongsDialog.kt
@@ -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 io.github.muntashirakon.music.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 io.github.muntashirakon.music.EXTRA_SONG
import io.github.muntashirakon.music.R
-import io.github.muntashirakon.music.activities.saf.SAFGuideActivity
import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.extraNotNull
import io.github.muntashirakon.music.extensions.materialDialog
+import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.MusicUtil
-import io.github.muntashirakon.music.util.SAFUtil
+import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class DeleteSongsDialog : DialogFragment() {
- @JvmField
- var currentSong: Song? = null
-
- @JvmField
- var songsToRemove: List? = null
-
- private var deleteSongsAsyncTask: DeleteSongsAsyncTask? = null
-
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- val songs = extraNotNull>(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, safUris: List?) {
- MusicUtil.deleteTracks(requireActivity(), songs, safUris, Runnable {
- dismiss()
- })
- }
+ private val libraryViewModel by sharedViewModel()
companion object {
-
fun create(song: Song): DeleteSongsDialog {
val list = ArrayList()
list.add(song)
@@ -119,5 +33,38 @@ class DeleteSongsDialog : DialogFragment() {
return dialog
}
}
-}
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val songs = extraNotNull>(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()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/ImportPlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/ImportPlaylistDialog.kt
new file mode 100644
index 000000000..359ef1c5b
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/ImportPlaylistDialog.kt
@@ -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()
+
+ 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()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/LyricsDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/LyricsDialog.kt
new file mode 100644
index 000000000..9c3b63c78
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/LyricsDialog.kt
@@ -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()
+
+ 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 = 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
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveFromPlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveFromPlaylistDialog.kt
deleted file mode 100644
index 8c0a3d352..000000000
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveFromPlaylistDialog.kt
+++ /dev/null
@@ -1,83 +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 io.github.muntashirakon.music.dialogs
-
-import android.app.Dialog
-import android.os.Bundle
-import androidx.core.text.HtmlCompat
-import androidx.fragment.app.DialogFragment
-import io.github.muntashirakon.music.EXTRA_SONG
-import io.github.muntashirakon.music.R
-import io.github.muntashirakon.music.extensions.colorButtons
-import io.github.muntashirakon.music.extensions.materialDialog
-import io.github.muntashirakon.music.model.PlaylistSong
-import io.github.muntashirakon.music.util.PlaylistsUtil
-
-class RemoveFromPlaylistDialog : DialogFragment() {
-
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- val songs = requireArguments().getParcelableArrayList(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(R.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(R.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
- )
- }
- .setNegativeButton(android.R.string.cancel, null)
- .create()
- .colorButtons()
- }
-
- companion object {
-
- fun create(song: PlaylistSong): RemoveFromPlaylistDialog {
- val list = ArrayList()
- list.add(song)
- return create(list)
- }
-
- fun create(songs: ArrayList): RemoveFromPlaylistDialog {
- val dialog = RemoveFromPlaylistDialog()
- val args = Bundle()
- args.putParcelableArrayList(EXTRA_SONG, songs)
- dialog.arguments = args
- return dialog
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveSongFromPlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveSongFromPlaylistDialog.kt
new file mode 100644
index 000000000..b52e9fef5
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/RemoveSongFromPlaylistDialog.kt
@@ -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()
+
+ companion object {
+ fun create(song: SongEntity): RemoveSongFromPlaylistDialog {
+ val list = mutableListOf()
+ list.add(song)
+ return create(list)
+ }
+
+ fun create(songs: List): RemoveSongFromPlaylistDialog {
+ return RemoveSongFromPlaylistDialog().apply {
+ arguments = bundleOf(
+ EXTRA_SONG to songs
+ )
+ }
+ }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val songs = extraNotNull>(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()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/RenamePlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/RenamePlaylistDialog.kt
index 466f08916..ea6738145 100644
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/RenamePlaylistDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/RenamePlaylistDialog.kt
@@ -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 io.github.muntashirakon.music.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 io.github.muntashirakon.music.EXTRA_PLAYLIST_ID
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.extensions.accentColor
import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.extraNotNull
import io.github.muntashirakon.music.extensions.materialDialog
-import io.github.muntashirakon.music.util.PlaylistsUtil
+import io.github.muntashirakon.music.fragments.LibraryViewModel
+import io.github.muntashirakon.music.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()
- @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(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(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
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/RetroSingleCheckedListAdapter.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/RetroSingleCheckedListAdapter.kt
deleted file mode 100644
index 151961214..000000000
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/RetroSingleCheckedListAdapter.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.github.muntashirakon.music.dialogs
-
-import android.content.Context
-import android.widget.ArrayAdapter
-import io.github.muntashirakon.music.R
-
-class RetroSingleCheckedListAdapter(
- context: Context,
- resource: Int = R.layout.dialog_list_item,
- objects: MutableList
-) : ArrayAdapter(context, resource, objects) {
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/SavePlaylistDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/SavePlaylistDialog.kt
new file mode 100644
index 000000000..dd92a9a2d
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/SavePlaylistDialog.kt
@@ -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(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()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/SleepTimerDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/SleepTimerDialog.kt
index e5f0d6039..fc88b8489 100755
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/SleepTimerDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/SleepTimerDialog.kt
@@ -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
diff --git a/app/src/main/java/io/github/muntashirakon/music/dialogs/SongDetailDialog.kt b/app/src/main/java/io/github/muntashirakon/music/dialogs/SongDetailDialog.kt
index e03540c8a..a6235e8d1 100644
--- a/app/src/main/java/io/github/muntashirakon/music/dialogs/SongDetailDialog.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/dialogs/SongDetailDialog.kt
@@ -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")
diff --git a/app/src/main/java/io/github/muntashirakon/music/extensions/ActivityEx.kt b/app/src/main/java/io/github/muntashirakon/music/extensions/ActivityEx.kt
index c525ef166..e4a1dacb9 100644
--- a/app/src/main/java/io/github/muntashirakon/music/extensions/ActivityEx.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/extensions/ActivityEx.kt
@@ -15,13 +15,8 @@
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.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 Activity.extra(key: String, default: T? = null) = lazy {
val value = intent?.extras?.get(key)
if (value is T) value else default
diff --git a/app/src/main/java/io/github/muntashirakon/music/extensions/ColorExt.kt b/app/src/main/java/io/github/muntashirakon/music/extensions/ColorExt.kt
index 3f93d4d3c..bf069359a 100644
--- a/app/src/main/java/io/github/muntashirakon/music/extensions/ColorExt.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/extensions/ColorExt.kt
@@ -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
@@ -31,6 +37,8 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
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
import io.github.muntashirakon.music.App
@@ -41,6 +49,7 @@ fun Int.ripAlpha(): Int {
}
fun Dialog.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal)
+
fun Toolbar.backgroundTintList() {
val surfaceColor = ATHUtil.resolveColor(context, R.attr.colorSurface, Color.BLACK)
val colorStateList = ColorStateList.valueOf(surfaceColor)
@@ -76,7 +85,6 @@ fun Fragment.resolveColor(@AttrRes attr: Int, fallBackColor: Int = 0) =
fun Dialog.resolveColor(@AttrRes attr: Int, fallBackColor: Int = 0) =
ATHUtil.resolveColor(context, attr, fallBackColor)
-
fun CheckBox.addAccentColor() {
buttonTintList = ColorStateList.valueOf(ThemeStore.accentColor(context))
}
@@ -91,6 +99,23 @@ fun Button.accentTextColor() {
setTextColor(ThemeStore.accentColor(App.getContext()))
}
+fun MaterialButton.accentTextColor() {
+ setTextColor(ThemeStore.accentColor(App.getContext()))
+}
+
+fun MaterialButton.accentBackgroundColor() {
+ backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(App.getContext()))
+}
+
+fun MaterialButton.accentOutlineColor() {
+ val color = ThemeStore.accentColor(context)
+ val colorStateList = ColorStateList.valueOf(color)
+ iconTint = colorStateList
+ strokeColor = colorStateList
+ setTextColor(colorStateList)
+ rippleColor = colorStateList
+}
+
fun SeekBar.applyColor(@ColorInt color: Int) {
thumbTintList = ColorStateList.valueOf(color)
progressTintList = ColorStateList.valueOf(color)
@@ -107,6 +132,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 +154,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 +168,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() {
-}
\ No newline at end of file
+}
+
+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)
+}
+
diff --git a/app/src/main/java/io/github/muntashirakon/music/extensions/CursorExtensions.kt b/app/src/main/java/io/github/muntashirakon/music/extensions/CursorExtensions.kt
new file mode 100644
index 000000000..22c8e8667
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/extensions/CursorExtensions.kt
@@ -0,0 +1,37 @@
+package code.name.monkey.retromusic.extensions
+
+import android.database.Cursor
+
+// exception is rethrown manually in order to have a readable stacktrace
+
+internal fun Cursor.getInt(columnName: String): Int {
+ try {
+ return this.getInt(this.getColumnIndex(columnName))
+ } catch (ex: Throwable) {
+ throw IllegalStateException("invalid column $columnName", ex)
+ }
+}
+
+internal fun Cursor.getLong(columnName: String): Long {
+ try {
+ return this.getLong(this.getColumnIndex(columnName))
+ } catch (ex: Throwable) {
+ throw IllegalStateException("invalid column $columnName", ex)
+ }
+}
+
+internal fun Cursor.getString(columnName: String): String {
+ try {
+ return this.getString(this.getColumnIndex(columnName))
+ } catch (ex: Throwable) {
+ throw IllegalStateException("invalid column $columnName", ex)
+ }
+}
+
+internal fun Cursor.getStringOrNull(columnName: String): String? {
+ try {
+ return this.getString(this.getColumnIndex(columnName))
+ } catch (ex: Throwable) {
+ throw IllegalStateException("invalid column $columnName", ex)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/extensions/DialogExtension.kt b/app/src/main/java/io/github/muntashirakon/music/extensions/DialogExtension.kt
index fd375c107..5f1252ca5 100644
--- a/app/src/main/java/io/github/muntashirakon/music/extensions/DialogExtension.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/extensions/DialogExtension.kt
@@ -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)
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/extensions/FragmentExt.kt b/app/src/main/java/io/github/muntashirakon/music/extensions/FragmentExt.kt
index 7c300f54a..d9244bde0 100644
--- a/app/src/main/java/io/github/muntashirakon/music/extensions/FragmentExt.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/extensions/FragmentExt.kt
@@ -2,12 +2,15 @@ package io.github.muntashirakon.music.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
@@ -73,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)!!
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/CoroutineViewModel.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/CoroutineViewModel.kt
new file mode 100644
index 000000000..9b6a5ca4c
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/CoroutineViewModel.kt
@@ -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()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/DetailListFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/DetailListFragment.kt
index f90145eca..9aeda938b 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/DetailListFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/DetailListFragment.kt
@@ -3,6 +3,11 @@ package io.github.muntashirakon.music.fragments
import android.os.Bundle
import android.view.View
import android.widget.ImageView
+import androidx.core.os.bundleOf
+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.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
@@ -10,15 +15,14 @@ import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
import io.github.muntashirakon.music.adapter.song.SongAdapter
+import io.github.muntashirakon.music.db.toSong
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.model.Artist
-import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.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 +38,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 +52,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,
- 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 +147,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) {
@@ -120,11 +181,21 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
- override fun onArtist(artistId: Int, imageView: ImageView) {
-
+ override fun onArtist(artistId: Long, imageView: ImageView) {
+ findNavController().navigate(
+ R.id.artistDetailsFragment,
+ bundleOf(EXTRA_ARTIST_ID to artistId),
+ null,
+ FragmentNavigatorExtras(imageView to getString(R.string.transition_artist_image))
+ )
}
- override fun onAlbumClick(albumId: Int, view: View) {
-
+ override fun onAlbumClick(albumId: Long, view: View) {
+ findNavController().navigate(
+ R.id.albumDetailsFragment,
+ bundleOf(EXTRA_ALBUM_ID to albumId),
+ null,
+ FragmentNavigatorExtras(view to getString(R.string.transition_album_art))
+ )
}
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/LibraryViewModel.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/LibraryViewModel.kt
index 6406d0ffc..d1848bd15 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/LibraryViewModel.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/LibraryViewModel.kt
@@ -4,83 +4,130 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.db.PlaylistWithSongs
+import io.github.muntashirakon.music.db.SongEntity
+import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.fragments.ReloadType.*
+import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
import io.github.muntashirakon.music.model.*
import io.github.muntashirakon.music.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()
private val albums = MutableLiveData>()
private val songs = MutableLiveData>()
private val artists = MutableLiveData>()
- private val playlists = MutableLiveData>()
+ private val playlists = MutableLiveData>()
+ private val legacyPlaylists = MutableLiveData>()
private val genres = MutableLiveData>()
private val home = MutableLiveData>()
val paletteColorLiveData: LiveData = paletteColor
- val homeLiveData: LiveData> = home
- val albumsLiveData: LiveData> = albums
- val songsLiveData: LiveData> = songs
- val artistsLiveData: LiveData> = artists
- val playlisitsLiveData: LiveData> = playlists
- val genresLiveData: LiveData> = genres
init {
- viewModelScope.launch {
- loadLibraryContent()
+ fetchHomeSections()
+ }
+
+ private fun loadLibraryContent() = viewModelScope.launch(IO) {
+ fetchHomeSections()
+ fetchSongs()
+ fetchAlbums()
+ fetchArtists()
+ fetchGenres()
+ fetchPlaylists()
+ }
+
+ fun getSongs(): LiveData> {
+ fetchSongs()
+ return songs
+ }
+
+ fun getAlbums(): LiveData> {
+ fetchAlbums()
+ return albums
+ }
+
+ fun getArtists(): LiveData> {
+ fetchArtists()
+ return artists
+ }
+
+ fun getPlaylists(): LiveData> {
+ fetchPlaylists()
+ return playlists
+ }
+
+ fun getLegacyPlaylist(): LiveData> {
+ fetchLegacyPlaylist()
+ return legacyPlaylists
+ }
+
+ fun getGenre(): LiveData> {
+ fetchGenres()
+ return genres
+ }
+
+ fun getHome(): LiveData> {
+ 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>
- get() = viewModelScope.async { realRepository.homeSections() }
-
- private val loadSongs: Deferred>
- get() = viewModelScope.async(IO) { realRepository.allSongs() }
-
- private val loadAlbums: Deferred>
- get() = viewModelScope.async(IO) {
- realRepository.allAlbums()
+ private fun fetchArtists() {
+ viewModelScope.launch(IO) {
+ artists.postValue(repository.fetchArtists())
}
+ }
- private val loadArtists: Deferred>
- get() = viewModelScope.async(IO) {
- realRepository.albumArtists()
+ private fun fetchPlaylists() {
+ viewModelScope.launch(IO) {
+ playlists.postValue(repository.fetchPlaylistWithSongs())
}
+ }
- private val loadPlaylists: Deferred>
- get() = viewModelScope.async(IO) {
- realRepository.allPlaylists()
+ private fun fetchLegacyPlaylist() {
+ viewModelScope.launch(IO) {
+ legacyPlaylists.postValue(repository.fetchLegacyPlaylist())
}
+ }
- private val loadGenres: Deferred>
- 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 +136,10 @@ class LibraryViewModel(
}
override fun onMediaStoreChanged() {
- loadLibraryContent()
println("onMediaStoreChanged")
+ loadLibraryContent()
}
-
override fun onServiceConnected() {
println("onServiceConnected")
}
@@ -108,6 +154,7 @@ class LibraryViewModel(
override fun onPlayingMetaChanged() {
println("onPlayingMetaChanged")
+
}
override fun onPlayStateChanged() {
@@ -122,11 +169,76 @@ class LibraryViewModel(
println("onShuffleModeChanged")
}
+ fun shuffleSongs() = viewModelScope.launch(IO) {
+ val songs = repository.allSongs()
+ MusicPlayerRemote.openAndShuffleQueue(
+ songs,
+ true
+ )
+ }
+
+ fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) {
+ repository.renameRoomPlaylist(playListId, name)
+ }
+
+ fun deleteSongsInPlaylist(songs: List) = viewModelScope.launch(IO) {
+ repository.deleteSongsInPlaylist(songs)
+ }
+
+ fun deleteSongsFromPlaylist(playlists: List) = viewModelScope.launch(IO) {
+ repository.deletePlaylistSongs(playlists)
+ }
+
+ fun deleteRoomPlaylist(playlists: List) = viewModelScope.launch(IO) {
+ repository.deleteRoomPlaylist(playlists)
+ }
+
+ suspend fun albumById(id: Long) = repository.albumById(id)
+ suspend fun artistById(id: Long) = repository.artistById(id)
+ suspend fun favoritePlaylist() = repository.favoritePlaylist()
+ suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
+ suspend fun insertSongs(songs: List) = repository.insertSongs(songs)
+ suspend fun removeSongFromPlaylist(songEntity: SongEntity) =
+ repository.removeSongFromPlaylist(songEntity)
+
+ suspend fun checkPlaylistExists(playlistName: String): List =
+ 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(playlistName = playlist.name))
+ val songEntities = playlist.getSongs().map {
+ it.toSongEntity(playListId)
+ }
+ repository.insertSongs(songEntities)
+ }
+ forceReload(Playlists)
+ }
+ }
+
+ fun deleteTracks(songs: List) = viewModelScope.launch(IO) {
+ repository.deleteSongs(songs)
+ fetchPlaylists()
+ loadLibraryContent()
+ }
}
enum class ReloadType {
Songs,
Albums,
Artists,
- HomeSections
+ HomeSections,
+ Playlists,
+ Genres,
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/MiniPlayerFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/MiniPlayerFragment.kt
index 69636ffba..adaa793f8 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/MiniPlayerFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/MiniPlayerFragment.kt
@@ -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 io.github.muntashirakon.music.R
-import io.github.muntashirakon.music.extensions.show
-import io.github.muntashirakon.music.extensions.textColorPrimary
-import io.github.muntashirakon.music.extensions.textColorSecondary
+import io.github.muntashirakon.music.extensions.*
import io.github.muntashirakon.music.fragments.base.AbsMusicServiceFragment
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.MusicProgressViewUpdateHelper
import io.github.muntashirakon.music.helper.PlayPauseButtonOnClickHandler
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
-import io.github.muntashirakon.music.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
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/NowPlayingScreen.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/NowPlayingScreen.kt
index 964127b53..79972c57b 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/NowPlayingScreen.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/NowPlayingScreen.kt
@@ -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),
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsFragment.kt
index 15bf1b0e9..b61af2bbb 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsFragment.kt
@@ -6,8 +6,11 @@ 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.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator
@@ -15,7 +18,6 @@ import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
-import com.bumptech.glide.Glide
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
import io.github.muntashirakon.music.R
@@ -26,22 +28,33 @@ import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
import io.github.muntashirakon.music.extensions.applyColor
+import io.github.muntashirakon.music.extensions.applyOutlineColor
import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.glide.AlbumGlideRequest
import io.github.muntashirakon.music.glide.ArtistGlideRequest
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
+import io.github.muntashirakon.music.glide.SingleColorTarget
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.helper.SortOrder
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.model.Artist
+import io.github.muntashirakon.music.network.Result
import io.github.muntashirakon.music.network.model.LastFmAlbum
+import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.RetroUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
+import com.bumptech.glide.Glide
+import com.google.android.material.transition.platform.MaterialArcMotion
+import com.google.android.material.transition.platform.MaterialContainerTransform
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.*
@@ -60,29 +73,27 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
private val savedSortOrder: String
get() = PreferenceUtil.albumDetailSongSortOrder
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ sharedElementEnterTransition = MaterialContainerTransform().apply {
+ duration = 1000L
+ pathMotion = MaterialArcMotion()
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
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)
@@ -91,11 +102,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
bundleOf(EXTRA_ARTIST_ID to album.artistId)
)
}
- playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
+ playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs, 0, true) }
shuffleAction.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(
- album.songs!!,
+ album.songs,
true
)
}
@@ -134,20 +145,18 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
private fun showAlbum(album: Album) {
- if (album.songs!!.isEmpty()) {
+ if (album.songs.isEmpty()) {
return
}
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 +171,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) {
@@ -191,7 +215,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 +233,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,30 +248,29 @@ 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) {
+ override fun onAlbumClick(albumId: Long, 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))
)
}
@@ -275,7 +305,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().fetchPlaylists()
+ withContext(Dispatchers.Main) {
+ AddToPlaylistDialog.create(playlists, songs)
+ .show(childFragmentManager, "ADD_PLAYLIST")
+ }
+ }
return true
}
R.id.action_delete_from_device -> {
@@ -326,29 +362,31 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
private fun setSaveSortOrder(sortOrder: String) {
PreferenceUtil.albumDetailSongSortOrder = sortOrder
- when (sortOrder) {
- SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
+ val songs = when (sortOrder) {
+ SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
o1.trackNumber.compareTo(
o2.trackNumber
)
- })
- SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
+ }
+ SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
o1.title.compareTo(
o2.title
)
- })
- SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
+ }
+ SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
o2.title.compareTo(
o1.title
)
- })
- SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
+ }
+ SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
o1.duration.compareTo(
o2.duration
)
- })
+ }
+ else -> throw IllegalArgumentException("invalid $sortOrder")
}
- album.songs?.let { simpleSongAdapter.swapDataSet(it) }
+ album = album.copy(songs = songs)
+ simpleSongAdapter.swapDataSet(album.songs)
}
companion object {
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsViewModel.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsViewModel.kt
index 65b7338b2..e50d7f69c 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsViewModel.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumDetailsViewModel.kt
@@ -1,68 +1,43 @@
package io.github.muntashirakon.music.fragments.albums
import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
+import androidx.lifecycle.liveData
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.model.Artist
+import io.github.muntashirakon.music.network.Result
import io.github.muntashirakon.music.network.model.LastFmAlbum
import io.github.muntashirakon.music.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
+ private val repository: RealRepository,
+ private val albumId: Long
) : ViewModel(), MusicServiceEventListener {
- private val _album = MutableLiveData()
- private val _artist = MutableLiveData()
- private val _lastFmAlbum = MutableLiveData()
- private val _moreAlbums = MutableLiveData>()
-
- fun getAlbum(): LiveData = _album
- fun getArtist(): LiveData = _artist
- fun getAlbumInfo(): LiveData = _lastFmAlbum
- fun getMoreAlbums(): LiveData> = _moreAlbums
-
- init {
- loadAlbumDetails()
+ fun getAlbum(): LiveData = liveData(IO) {
+ emit(repository.albumByIdAsync(albumId))
}
- private fun loadAlbumDetails() = viewModelScope.launch {
- val album = loadAlbumAsync.await() ?: throw NullPointerException("Album couldn't found")
- _album.postValue(album)
+ fun getArtist(artistId: Long): LiveData = liveData(IO) {
+ val artist = repository.artistById(artistId)
+ emit(artist)
}
- fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) {
- try {
- val lastFmAlbum = realRepository.albumInfo(
- album.artistName ?: "-", album.title ?: "-"
- )
- _lastFmAlbum.postValue(lastFmAlbum)
- } catch (ignored: Exception) {}
+ fun getAlbumInfo(album: Album): LiveData> = liveData {
+ emit(Result.Loading)
+ emit(repository.albumInfo(album.artistName ?: "-", album.title ?: "-"))
}
- fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) {
- val artist = realRepository.artistById(artistId)
- _artist.postValue(artist)
-
- artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
- if (albums.isNotEmpty()) _moreAlbums.postValue(albums)
+ fun getMoreAlbums(artist: Artist): LiveData> = liveData(IO) {
+ artist.albums.filter { item -> item.id != albumId }.let { albums ->
+ if (albums.isNotEmpty()) emit(albums)
}
}
- private val loadAlbumAsync: Deferred
- get() = viewModelScope.async(Dispatchers.IO) {
- realRepository.albumById(albumId)
- }
-
override fun onMediaStoreChanged() {
- loadAlbumDetails()
+
}
override fun onServiceConnected() {}
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumsFragment.kt
index 9724b3247..b4492d089 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/albums/AlbumsFragment.kt
@@ -1,26 +1,35 @@
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
+import io.github.muntashirakon.music.extensions.findActivityNavController
import io.github.muntashirakon.music.fragments.ReloadType
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
+import io.github.muntashirakon.music.helper.SortOrder
+import io.github.muntashirakon.music.helper.SortOrder.AlbumSortOrder
import io.github.muntashirakon.music.util.PreferenceUtil
+import io.github.muntashirakon.music.util.RetroUtil
+import com.google.android.material.transition.platform.MaterialFadeThrough
-class AlbumsFragment :
- AbsRecyclerViewCustomGridSizeFragment(),
+
+class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment(),
AlbumClickListener {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enterTransition = MaterialFadeThrough()
+ }
+
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
@@ -40,7 +49,7 @@ class AlbumsFragment :
return AlbumAdapter(
requireActivity(),
dataSet,
- R.layout.item_grid,
+ itemLayoutRes(),
null,
this
)
@@ -94,9 +103,8 @@ class AlbumsFragment :
}
}
- override fun onAlbumClick(albumId: Int, view: View) {
- val controller = requireActivity().findNavController(R.id.fragment_container)
- controller.navigate(
+ override fun onAlbumClick(albumId: Long, view: View) {
+ findActivityNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId),
null,
@@ -105,8 +113,183 @@ 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 {
- fun onAlbumClick(albumId: Int, view: View)
+ fun onAlbumClick(albumId: Long, view: View)
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsFragment.kt
index 679be368a..e8b25d765 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsFragment.kt
@@ -10,33 +10,41 @@ 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 com.bumptech.glide.Glide
+import io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.album.HorizontalAlbumAdapter
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
import io.github.muntashirakon.music.extensions.applyColor
+import io.github.muntashirakon.music.extensions.applyOutlineColor
import io.github.muntashirakon.music.extensions.show
import io.github.muntashirakon.music.extensions.showToast
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.glide.ArtistGlideRequest
-import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
+import io.github.muntashirakon.music.glide.SingleColorTarget
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.model.Artist
+import io.github.muntashirakon.music.network.Result
import io.github.muntashirakon.music.network.model.LastFmArtist
+import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.util.CustomArtistImageUtil
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.RetroUtil
-import io.github.muntashirakon.music.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 +74,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 +138,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 +147,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 +188,24 @@ 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) {
+ shuffleAction.applyColor(color)
+ playAction.applyOutlineColor(color)
}
- override fun onAlbumClick(albumId: Int, view: View) {
+
+ override fun onAlbumClick(albumId: Long, 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 +230,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().fetchPlaylists()
+ withContext(Dispatchers.Main) {
+ AddToPlaylistDialog.create(playlists, songs)
+ .show(childFragmentManager, "ADD_PLAYLIST")
+ }
+ }
return true
}
R.id.action_set_artist_image -> {
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsViewModel.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsViewModel.kt
index 06a6d15e2..0bdd3b140 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsViewModel.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistDetailsViewModel.kt
@@ -1,51 +1,37 @@
package io.github.muntashirakon.music.fragments.artists
import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
+import androidx.lifecycle.liveData
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
import io.github.muntashirakon.music.model.Artist
+import io.github.muntashirakon.music.network.Result
import io.github.muntashirakon.music.network.model.LastFmArtist
import io.github.muntashirakon.music.repository.RealRepository
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.Dispatchers.IO
class ArtistDetailsViewModel(
private val realRepository: RealRepository,
- private val artistId: Int
+ private val artistId: Long
) : ViewModel(), MusicServiceEventListener {
- private val loadArtistDetailsAsync: Deferred
- get() = viewModelScope.async(Dispatchers.IO) {
- realRepository.artistById(artistId)
- }
-
- private val _artist = MutableLiveData()
- private val _lastFmArtist = MutableLiveData()
-
- fun getArtist(): LiveData = _artist
- fun getArtistInfo(): LiveData = _lastFmArtist
-
- init {
- loadArtistDetails()
+ fun getArtist(): LiveData = 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> = 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() {}
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistsFragment.kt
index bb641ff98..7cc396b54 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/artists/ArtistsFragment.kt
@@ -1,7 +1,7 @@
package io.github.muntashirakon.music.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,22 @@ import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
import io.github.muntashirakon.music.extensions.findActivityNavController
import io.github.muntashirakon.music.fragments.ReloadType
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
-import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
+import io.github.muntashirakon.music.helper.SortOrder.ArtistSortOrder
import io.github.muntashirakon.music.util.PreferenceUtil
+import io.github.muntashirakon.music.util.RetroUtil
+import com.google.android.material.transition.platform.MaterialFadeThrough
-class ArtistsFragment :
- AbsRecyclerViewCustomGridSizeFragment(),
- MainActivityFragmentCallbacks, ArtistClickListener {
- override fun handleBackPress(): Boolean {
- return false
+class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment(),
+ ArtistClickListener {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enterTransition = MaterialFadeThrough()
}
-
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
@@ -50,7 +51,7 @@ class ArtistsFragment :
return ArtistAdapter(
requireActivity(),
dataSet,
- R.layout.item_grid_circle,
+ itemLayoutRes(),
null,
this
)
@@ -100,12 +101,167 @@ class ArtistsFragment :
}
}
- override fun onArtist(artistId: Int, imageView: ImageView) {
+ override fun onArtist(artistId: Long, imageView: ImageView) {
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 {
- fun onArtist(artistId: Int, imageView: ImageView)
+ fun onArtist(artistId: Long, imageView: ImageView)
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerFragment.kt
index 5e3cc98d7..52a32e945 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerFragment.kt
@@ -1,10 +1,9 @@
package io.github.muntashirakon.music.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,41 @@ 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 io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
import io.github.muntashirakon.music.activities.tageditor.SongTagEditorActivity
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.db.SongEntity
+import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.dialogs.*
import io.github.muntashirakon.music.extensions.hide
+import io.github.muntashirakon.music.extensions.whichFragment
import io.github.muntashirakon.music.fragments.LibraryViewModel
+import io.github.muntashirakon.music.fragments.ReloadType
import io.github.muntashirakon.music.fragments.player.PlayerAlbumCoverFragment
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.PaletteColorHolder
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.model.lyrics.Lyrics
+import io.github.muntashirakon.music.repository.RealRepository
+import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.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()
@@ -64,7 +74,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().fetchPlaylists()
+ withContext(Main) {
+ AddToPlaylistDialog.create(playlists, song)
+ .show(childFragmentManager, "ADD_PLAYLIST")
+ }
+ }
return true
}
R.id.action_clear_playing_queue -> {
@@ -146,9 +162,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 +183,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() {
- 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() {
- 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 +259,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
) {
view.findViewById(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)
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewFragment.kt
index 8cc11fdbe..ba9270647 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewFragment.kt
@@ -78,8 +78,7 @@ abstract class AbsRecyclerViewFragment, LM : Recycle
return String(Character.toChars(unicode))
}
- private fun checkIsEmpty() {
- emptyEmoji.text = getEmojiByUnicode(0x1F631)
+ private fun checkIsEmpty() {
emptyText.setText(emptyMessage)
empty.visibility = if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsFragment.kt
index 5b676af48..99febc1e6 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsFragment.kt
@@ -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)
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenresFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenresFragment.kt
index a4f623639..ad4c8a37b 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenresFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenresFragment.kt
@@ -21,18 +21,17 @@ import androidx.recyclerview.widget.LinearLayoutManager
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.GenreAdapter
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewFragment
-import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
+import com.google.android.material.transition.platform.MaterialFadeThrough
-class GenresFragment : AbsRecyclerViewFragment(),
- MainActivityFragmentCallbacks {
-
- override fun handleBackPress(): Boolean {
- return false
+class GenresFragment : AbsRecyclerViewFragment() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enterTransition = MaterialFadeThrough()
}
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
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/home/HomeFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/home/HomeFragment.kt
index b68533c2d..1e43ba0ee 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/home/HomeFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/home/HomeFragment.kt
@@ -16,50 +16,41 @@ package io.github.muntashirakon.music.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 com.bumptech.glide.Glide
-import io.github.muntashirakon.music.EXTRA_PLAYLIST
+import io.github.muntashirakon.music.HISTORY_PLAYLIST
+import io.github.muntashirakon.music.LAST_ADDED_PLAYLIST
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.TOP_PLAYED_PLAYLIST
import io.github.muntashirakon.music.adapter.HomeAdapter
import io.github.muntashirakon.music.extensions.findActivityNavController
import io.github.muntashirakon.music.fragments.LibraryViewModel
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
import io.github.muntashirakon.music.glide.UserProfileGlideRequest
-import io.github.muntashirakon.music.helper.MusicPlayerRemote
-import io.github.muntashirakon.music.model.smartplaylist.HistoryPlaylist
-import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
-import io.github.muntashirakon.music.model.smartplaylist.TopTracksPlaylist
-import io.github.muntashirakon.music.repository.Repository
import io.github.muntashirakon.music.util.NavigationUtil
import io.github.muntashirakon.music.util.PreferenceUtil
+import com.bumptech.glide.Glide
+import com.google.android.material.transition.platform.MaterialFadeThrough
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) {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enterTransition = MaterialFadeThrough()
+ }
- private val repository by inject()
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 +65,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 +104,7 @@ class HomeFragment :
adapter = homeAdapter
}
- libraryViewModel.homeLiveData.observe(viewLifecycleOwner, Observer {
+ libraryViewModel.getHome().observe(viewLifecycleOwner, Observer {
homeAdapter.swapData(it)
})
@@ -138,6 +124,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"
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/library/LibraryFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/library/LibraryFragment.kt
index 7243bb12f..6a9bf6306 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/library/LibraryFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/library/LibraryFragment.kt
@@ -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 com.google.android.material.appbar.AppBarLayout
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.dialogs.CreatePlaylistDialog
+import io.github.muntashirakon.music.dialogs.ImportPlaylistDialog
import io.github.muntashirakon.music.extensions.findNavController
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
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 Music",
+ 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
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/player/classic/ClassicPlayerFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/player/classic/ClassicPlayerFragment.kt
index 3eb89e3e4..6721be988 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/player/classic/ClassicPlayerFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/player/classic/ClassicPlayerFragment.kt
@@ -20,7 +20,6 @@ import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.RetroBottomSheetBehavior
-import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
import io.github.muntashirakon.music.adapter.song.PlayingQueueAdapter
import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.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
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/player/fit/FitPlaybackControlsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/player/fit/FitPlaybackControlsFragment.kt
index 7d75b09db..83a3781b1 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/player/fit/FitPlaybackControlsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/player/fit/FitPlaybackControlsFragment.kt
@@ -3,9 +3,7 @@ package io.github.muntashirakon.music.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 io.github.muntashirakon.music.helper.PlayPauseButtonOnClickHandler
import io.github.muntashirakon.music.misc.SimpleOnSeekbarChangeListener
import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.util.MusicUtil
-
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
import kotlinx.android.synthetic.main.fragment_fit_playback_controls.*
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/player/gradient/GradientPlayerFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/player/gradient/GradientPlayerFragment.kt
index af21957ff..31f068ce1 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/player/gradient/GradientPlayerFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/player/gradient/GradientPlayerFragment.kt
@@ -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
@@ -15,14 +14,16 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.ViewCompat
+import androidx.lifecycle.lifecycleScope
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 io.github.muntashirakon.music.R
import io.github.muntashirakon.music.RetroBottomSheetBehavior
-import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
import io.github.muntashirakon.music.adapter.song.PlayingQueueAdapter
+import io.github.muntashirakon.music.db.PlaylistEntity
+import io.github.muntashirakon.music.db.SongEntity
+import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.extensions.hide
import io.github.muntashirakon.music.extensions.ripAlpha
import io.github.muntashirakon.music.extensions.show
@@ -39,7 +40,7 @@ import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.ViewUtil
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
-import com.google.android.material.bottomsheet.BottomSheetBehavior
+import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
@@ -48,6 +49,9 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.fragment_gradient_controls.*
import kotlinx.android.synthetic.main.fragment_gradient_player.*
import kotlinx.android.synthetic.main.status_bar.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_player),
MusicProgressViewUpdateHelper.Callback,
@@ -62,14 +66,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() {
+ private val bottomSheetCallbackList = object : 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 +80,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)
+ STATE_EXPANDED,
+ STATE_DRAGGING -> {
+ mainActivity.getBottomSheetBehavior().setAllowDragging(false)
}
- BottomSheetBehavior.STATE_COLLAPSED -> {
+ STATE_COLLAPSED -> {
resetToCurrentPosition()
- activity.getBottomSheetBehavior().setAllowDragging(true)
+ mainActivity.getBottomSheetBehavior().setAllowDragging(true)
}
else -> {
- activity.getBottomSheetBehavior().setAllowDragging(true)
+ mainActivity.getBottomSheetBehavior().setAllowDragging(true)
}
}
}
@@ -139,8 +139,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 +158,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
recyclerViewDragDropManager?.cancelDrag()
super.onPause()
progressViewUpdateHelper.stop()
-
}
override fun playerToolbar(): Toolbar? {
@@ -176,9 +174,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
override fun onBackPressed(): Boolean {
var wasExpanded = false
- if (getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED) {
- wasExpanded = getQueuePanel().state == BottomSheetBehavior.STATE_EXPANDED
- getQueuePanel().state = BottomSheetBehavior.STATE_COLLAPSED
+ if (getQueuePanel().state == STATE_EXPANDED) {
+ wasExpanded = getQueuePanel().state == STATE_EXPANDED
+ getQueuePanel().state = STATE_COLLAPSED
return wasExpanded
}
return wasExpanded
@@ -224,9 +222,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()
+ updateIsFavoriteIcon()
}
}
@@ -234,6 +231,23 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
toggleFavorite(MusicPlayerRemote.currentSong)
}
+ private fun updateIsFavoriteIcon() {
+ lifecycleScope.launch(Dispatchers.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(Dispatchers.Main) {
+ val icon =
+ if (isFavorite) R.drawable.ic_favorite
+ else R.drawable.ic_favorite_border
+ songFavourite.setImageResource(icon)
+ }
+ }
+ }
+ }
+
private fun hideVolumeIfAvailable() {
if (PreferenceUtil.isVolumeVisibilityMode) {
childFragmentManager.beginTransaction()
@@ -251,6 +265,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
updatePlayPauseDrawableState()
updatePlayPauseDrawableState()
updateQueue()
+ updateIsFavoriteIcon()
}
override fun onPlayStateChanged() {
@@ -269,11 +284,13 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
super.onPlayingMetaChanged()
updateSong()
updateQueuePosition()
+ updateIsFavoriteIcon()
}
override fun onQueueChanged() {
super.onQueueChanged()
updateLabel()
+ playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue)
}
private fun updateSong() {
@@ -368,13 +385,10 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
private fun updateLabel() {
(MusicPlayerRemote.playingQueue.size - 1).apply {
if (this == (MusicPlayerRemote.position)) {
- nextSong.hide()
+ nextSong.text = "Last song"
} else {
val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title
- nextSong.apply {
- text = "Next: $title"
- show()
- }
+ nextSong.text = title
}
}
}
@@ -469,45 +483,11 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
-
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
-
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() {
- 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)
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsFragment.kt
index 26b27d5bf..08f1a2318 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsFragment.kt
@@ -5,23 +5,22 @@ 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 com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
-import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
-import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.song.OrderablePlaylistSongAdapter
import io.github.muntashirakon.music.adapter.song.SongAdapter
+import io.github.muntashirakon.music.db.PlaylistWithSongs
+import io.github.muntashirakon.music.db.toSongs
import io.github.muntashirakon.music.extensions.dipToPix
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
-import io.github.muntashirakon.music.model.AbsCustomPlaylist
-import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.util.PlaylistsUtil
+import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
+import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
+import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
@@ -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,22 @@ 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(
+ recyclerViewDragDropManager = RecyclerViewDragDropManager()
+ val animator = RefactoredDefaultItemAnimator()
+ adapter =
+ OrderablePlaylistSongAdapter(
+ playlist.playlistEntity,
requireActivity(),
ArrayList(),
R.layout.item_list,
@@ -76,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
)
@@ -87,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()
@@ -104,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)
}
@@ -121,15 +114,10 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
private fun checkIsEmpty() {
checkForPadding()
- emptyEmoji.text = getEmojiByUnicode(0x1F631)
empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
}
- private fun getEmojiByUnicode(unicode: Int): String {
- return String(Character.toChars(unicode))
- }
-
override fun onPause() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag()
@@ -161,11 +149,11 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
}
fun songs(songs: List) {
+ progressIndicator.hide()
if (songs.isNotEmpty()) {
adapter.swapDataSet(songs)
} else {
showEmptyView()
}
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsViewModel.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsViewModel.kt
index 253208a78..56a98ae2a 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsViewModel.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistDetailsViewModel.kt
@@ -3,42 +3,29 @@ package io.github.muntashirakon.music.fragments.playlists
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import io.github.muntashirakon.music.App
+import io.github.muntashirakon.music.db.PlaylistWithSongs
+import io.github.muntashirakon.music.db.SongEntity
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
-import io.github.muntashirakon.music.model.AbsCustomPlaylist
-import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.RealRepository
-import io.github.muntashirakon.music.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>()
- private val _playlist = MutableLiveData().apply {
+ private val _playlist = MutableLiveData().apply {
postValue(playlist)
}
- fun getPlaylist(): LiveData = _playlist
+ fun getPlaylist(): LiveData = _playlist
- fun getSongs(): LiveData> = _playListSongs
+ fun getSongs(): LiveData> = 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() {}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistsFragment.kt
index 10bc589d6..18d119a78 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/playlists/PlaylistsFragment.kt
@@ -1,25 +1,28 @@
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.playlist.PlaylistAdapter
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewFragment
-import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
+import com.google.android.material.transition.platform.MaterialFadeThrough
+import kotlinx.android.synthetic.main.fragment_library.*
-class PlaylistsFragment :
- AbsRecyclerViewFragment(),
- MainActivityFragmentCallbacks {
-
- override fun handleBackPress(): Boolean {
- return false
+class PlaylistsFragment : AbsRecyclerViewFragment() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enterTransition = MaterialFadeThrough()
}
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 +33,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 +46,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)
}
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/queue/PlayingQueueFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/queue/PlayingQueueFragment.kt
index 1a27597b0..ae9538cb1 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/queue/PlayingQueueFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/queue/PlayingQueueFragment.kt
@@ -22,7 +22,6 @@ import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.song.PlayingQueueAdapter
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewFragment
import io.github.muntashirakon.music.helper.MusicPlayerRemote
-import io.github.muntashirakon.music.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(),
- MainActivityFragmentCallbacks {
-
- override fun handleBackPress(): Boolean {
- return false
- }
+class PlayingQueueFragment : AbsRecyclerViewFragment() {
private lateinit var wrappedAdapter: RecyclerView.Adapter<*>
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchViewModel.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchViewModel.kt
index fdf8a287a..0ec0b5997 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchViewModel.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchViewModel.kt
@@ -6,9 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.github.muntashirakon.music.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>()
@@ -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.postValue(result)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/settings/MainSettingsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/settings/MainSettingsFragment.kt
index 603773f90..3e8cb1c74 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/settings/MainSettingsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/settings/MainSettingsFragment.kt
@@ -14,13 +14,19 @@
package io.github.muntashirakon.music.fragments.settings
+import android.content.res.ColorStateList
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
+import code.name.monkey.appthemehelper.ThemeStore
+import io.github.muntashirakon.music.App
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.extensions.hide
+import io.github.muntashirakon.music.extensions.show
+import io.github.muntashirakon.music.util.NavigationUtil
import kotlinx.android.synthetic.main.fragment_main_settings.*
class MainSettingsFragment : Fragment(), View.OnClickListener {
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/settings/OtherSettingsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/settings/OtherSettingsFragment.kt
index 78903150c..417457c54 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/settings/OtherSettingsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/settings/OtherSettingsFragment.kt
@@ -19,12 +19,16 @@ import android.view.View
import androidx.preference.Preference
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEListPreference
import io.github.muntashirakon.music.R
+import io.github.muntashirakon.music.fragments.LibraryViewModel
+import io.github.muntashirakon.music.fragments.ReloadType.HomeSections
+import org.koin.androidx.viewmodel.ext.android.sharedViewModel
/**
* @author Hemanth S (h4h13).
*/
class OtherSettingsFragment : AbsSettingsFragment() {
+ private val libraryViewModel by sharedViewModel()
override fun invalidateSettings() {
val languagePreference: ATEListPreference? = findPreference("language_name")
languagePreference?.setOnPreferenceChangeListener { _, _ ->
@@ -42,6 +46,7 @@ class OtherSettingsFragment : AbsSettingsFragment() {
val preference: Preference? = findPreference("last_added_interval")
preference?.setOnPreferenceChangeListener { lastAdded, newValue ->
setSummary(lastAdded, newValue)
+ libraryViewModel.forceReload(HomeSections)
true
}
val languagePreference: Preference? = findPreference("language_name")
diff --git a/app/src/main/java/io/github/muntashirakon/music/fragments/songs/SongsFragment.kt b/app/src/main/java/io/github/muntashirakon/music/fragments/songs/SongsFragment.kt
index f33ca639f..351fb9add 100644
--- a/app/src/main/java/io/github/muntashirakon/music/fragments/songs/SongsFragment.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/fragments/songs/SongsFragment.kt
@@ -1,7 +1,7 @@
package io.github.muntashirakon.music.fragments.songs
import android.os.Bundle
-import android.view.View
+import android.view.*
import androidx.annotation.LayoutRes
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
@@ -9,20 +9,21 @@ import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.song.SongAdapter
import io.github.muntashirakon.music.fragments.ReloadType
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
-import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
+import io.github.muntashirakon.music.helper.SortOrder.SongSortOrder
import io.github.muntashirakon.music.util.PreferenceUtil
+import io.github.muntashirakon.music.util.RetroUtil
+import com.google.android.material.transition.platform.MaterialFadeThrough
-class SongsFragment :
- AbsRecyclerViewCustomGridSizeFragment(),
- MainActivityFragmentCallbacks {
- override fun handleBackPress(): Boolean {
- return false
+class SongsFragment : AbsRecyclerViewCustomGridSizeFragment() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enterTransition = MaterialFadeThrough()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer {
+ libraryViewModel.getSongs().observe(viewLifecycleOwner, Observer {
if (it.isNotEmpty())
adapter?.swapDataSet(it)
else
@@ -42,7 +43,7 @@ class SongsFragment :
return SongAdapter(
requireActivity(),
dataSet,
- R.layout.item_list,
+ itemLayoutRes(),
null
)
}
@@ -88,6 +89,213 @@ class SongsFragment :
libraryViewModel.forceReload(ReloadType.Songs)
}
+ 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_song_sort_order_asc,
+ 0,
+ R.string.sort_order_a_z
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_A_Z
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_desc,
+ 1,
+ R.string.sort_order_z_a
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_Z_A
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_artist,
+ 2,
+ R.string.sort_order_artist
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_ARTIST
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_album,
+ 3,
+ R.string.sort_order_album
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_ALBUM
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_year,
+ 4,
+ R.string.sort_order_year
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_YEAR
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_date,
+ 5,
+ R.string.sort_order_date
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_DATE
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_date_modified,
+ 6,
+ R.string.sort_order_date_modified
+ ).isChecked =
+ currentSortOrder == SongSortOrder.SONG_DATE_MODIFIED
+ sortOrderMenu.add(
+ 0,
+ R.id.action_song_sort_order_composer,
+ 7,
+ R.string.sort_order_composer
+ ).isChecked =
+ currentSortOrder == SongSortOrder.COMPOSER
+
+ 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_song_sort_order_asc -> sortOrder = SongSortOrder.SONG_A_Z
+ R.id.action_song_sort_order_desc -> sortOrder = SongSortOrder.SONG_Z_A
+ R.id.action_song_sort_order_artist -> sortOrder = SongSortOrder.SONG_ARTIST
+ R.id.action_song_sort_order_album -> sortOrder = SongSortOrder.SONG_ALBUM
+ R.id.action_song_sort_order_year -> sortOrder = SongSortOrder.SONG_YEAR
+ R.id.action_song_sort_order_date -> sortOrder = SongSortOrder.SONG_DATE
+ R.id.action_song_sort_order_composer -> sortOrder = SongSortOrder.COMPOSER
+ R.id.action_song_sort_order_date_modified -> sortOrder =
+ SongSortOrder.SONG_DATE_MODIFIED
+ }
+ 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
+ }
+
companion object {
@JvmField
var TAG: String = SongsFragment::class.java.simpleName
diff --git a/app/src/main/java/io/github/muntashirakon/music/glide/AlbumGlideRequest.java b/app/src/main/java/io/github/muntashirakon/music/glide/AlbumGlideRequest.java
index 1c3c04336..7cb689e68 100644
--- a/app/src/main/java/io/github/muntashirakon/music/glide/AlbumGlideRequest.java
+++ b/app/src/main/java/io/github/muntashirakon/music/glide/AlbumGlideRequest.java
@@ -69,7 +69,7 @@ public class AlbumGlideRequest {
}
@NonNull
- public Builder checkIgnoreMediaStore(@NonNull Context context) {
+ public Builder checkIgnoreMediaStore() {
return ignoreMediaStore(PreferenceUtil.INSTANCE.isIgnoreMediaStoreArtwork());
}
diff --git a/app/src/main/java/io/github/muntashirakon/music/glide/SingleColorTarget.kt b/app/src/main/java/io/github/muntashirakon/music/glide/SingleColorTarget.kt
new file mode 100644
index 000000000..d4b2db1cc
--- /dev/null
+++ b/app/src/main/java/io/github/muntashirakon/music/glide/SingleColorTarget.kt
@@ -0,0 +1,39 @@
+package code.name.monkey.retromusic.glide
+
+import android.graphics.drawable.Drawable
+import android.widget.ImageView
+import code.name.monkey.appthemehelper.util.ATHUtil
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget
+import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
+import code.name.monkey.retromusic.util.ColorUtil
+import com.bumptech.glide.request.animation.GlideAnimation
+
+
+abstract class SingleColorTarget(view: ImageView) : BitmapPaletteTarget(view) {
+
+ protected val defaultFooterColor: Int
+ get() = ATHUtil.resolveColor(view.context, R.attr.colorControlNormal)
+
+ abstract fun onColorReady(color: Int)
+
+ override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
+ super.onLoadFailed(e, errorDrawable)
+ onColorReady(defaultFooterColor)
+ }
+
+ override fun onResourceReady(
+ resource: BitmapPaletteWrapper?,
+ glideAnimation: GlideAnimation?
+ ) {
+ super.onResourceReady(resource, glideAnimation)
+ resource?.let {
+ onColorReady(
+ ColorUtil.getColor(
+ it.palette,
+ ATHUtil.resolveColor(view.context, R.attr.colorPrimary)
+ )
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/muntashirakon/music/glide/artistimage/ArtistImageLoader.kt b/app/src/main/java/io/github/muntashirakon/music/glide/artistimage/ArtistImageLoader.kt
index 090cc217e..2b31c6f18 100644
--- a/app/src/main/java/io/github/muntashirakon/music/glide/artistimage/ArtistImageLoader.kt
+++ b/app/src/main/java/io/github/muntashirakon/music/glide/artistimage/ArtistImageLoader.kt
@@ -15,8 +15,8 @@
package io.github.muntashirakon.music.glide.artistimage
import android.content.Context
-import io.github.muntashirakon.music.deezer.DeezerApiService
-import io.github.muntashirakon.music.deezer.Data
+import io.github.muntashirakon.music.model.Data
+import io.github.muntashirakon.music.network.DeezerService
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import com.bumptech.glide.Priority
@@ -38,7 +38,7 @@ class ArtistImage(val artistName: String)
class ArtistImageFetcher(
private val context: Context,
- private val deezerApiService: DeezerApiService,
+ private val deezerService: DeezerService,
val model: ArtistImage,
val urlLoader: ModelLoader,
val width: Int,
@@ -66,16 +66,16 @@ class ArtistImageFetcher(
PreferenceUtil.isAllowedToDownloadMetadata()
) {
val artists = model.artistName.split(",")
- val response = deezerApiService.getArtistImage(artists[0]).execute()
+ val response = deezerService.getArtistImage(artists[0]).execute()
if (!response.isSuccessful) {
- throw IOException("Request failed with code: " + response.code());
+ throw IOException("Request failed with code: " + response.code())
}
if (isCancelled) return null
return try {
- val deezerResponse = response.body();
+ val deezerResponse = response.body()
val imageUrl = deezerResponse?.data?.get(0)?.let { getHighestQuality(it) }
// Fragile way to detect a place holder image returned from Deezer:
// ex: "https://e-cdns-images.dzcdn.net/images/artist//250x250-000000-80-0-0.jpg"
@@ -106,7 +106,7 @@ class ArtistImageFetcher(
class ArtistImageLoader(
val context: Context,
- private val deezerApiService: DeezerApiService,
+ private val deezerService: DeezerService,
private val urlLoader: ModelLoader
) : StreamModelLoader