From 6ace96708bf6fb4df92234b5fcfabf09bdf4fd33 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Thu, 20 Aug 2020 00:13:06 +0530 Subject: [PATCH 01/46] Add Room database for custom playlist Here we go again! Doing custom playlist db --- app/build.gradle | 6 +- .../java/code/name/monkey/retromusic/App.kt | 3 +- .../code/name/monkey/retromusic/MainModule.kt | 5 ++ .../retromusic/activities/MainActivity.kt | 8 +++ .../name/monkey/retromusic/db/PlaylistDao.kt | 19 ++++++ .../monkey/retromusic/db/PlaylistDatabase.kt | 34 ++++++++++ .../monkey/retromusic/db/PlaylistEntity.kt | 15 +++++ .../monkey/retromusic/db/PlaylistWithSongs.kt | 12 ++++ .../retromusic/db/RoomPlaylistRepository.kt | 9 +++ .../name/monkey/retromusic/db/SongEntity.kt | 17 +++++ .../retromusic/dialogs/AddToRetroPlaylist.kt | 63 +++++++++++++++++++ .../retromusic/dialogs/CreateRetroPlaylist.kt | 43 +++++++++++++ .../fragments/library/LibraryFragment.kt | 23 +++++-- 13 files changed, 250 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt diff --git a/app/build.gradle b/app/build.gradle index 3f4414d0..cac506dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -162,7 +162,6 @@ dependencies { implementation 'com.google.android.play:core:1.8.0' implementation 'me.jorgecastillo:androidcolorx:0.2.0' - debugImplementation 'com.amitshekhar.android:debug-db:1.0.4' implementation 'com.github.dhaval2404:imagepicker:1.7.1' def koin_version = "2.1.5" @@ -177,4 +176,9 @@ dependencies { implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" + def room_version = "2.2.5" + implementation "androidx.room:room-runtime:$room_version" + kapt "androidx.room:room-compiler:$room_version" + implementation "androidx.room:room-ktx:$room_version" + debugImplementation 'com.amitshekhar.android:debug-db:1.0.6' } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index de916793..a4caf9d1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -20,6 +20,7 @@ import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager +import com.amitshekhar.DebugDB import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.TransactionDetails import org.koin.android.ext.koin.androidContext @@ -32,7 +33,7 @@ class App : MultiDexApplication() { override fun onCreate() { super.onCreate() instance = this - + DebugDB.getAddressLog(); startKoin { androidContext(this@App) modules(appModules) diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index f1e52df6..f884f1fa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -1,5 +1,6 @@ package code.name.monkey.retromusic +import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel @@ -65,6 +66,10 @@ private val dataModule = module { single { androidContext().contentResolver } + + single { + PlaylistDatabase.getDatabase(get()) + } } private val viewModules = module { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 16491acc..87791f4a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -10,6 +10,7 @@ import android.view.View import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity +import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue @@ -25,6 +26,7 @@ import code.name.monkey.retromusic.util.AppRater.appLaunched import code.name.monkey.retromusic.util.PreferenceUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import java.util.* @@ -55,6 +57,12 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis appLaunched(this) addMusicServiceEventListener(libraryViewModel) updateTabs() + + val database: PlaylistDatabase = get() + lifecycleScope.launch { + println("Size:${database.playlistDao().playlistsWithSong()}") + } + } override fun onSupportNavigateUp(): Boolean = diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt new file mode 100644 index 00000000..7c595b3c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -0,0 +1,19 @@ +package code.name.monkey.retromusic.db + +import androidx.room.* + +@Dao +interface PlaylistDao { + @Insert + suspend fun createPlaylist(playlistEntity: PlaylistEntity) + + @Query("SELECT * FROM PlaylistEntity") + suspend fun playlists(): List + + @Transaction + @Query("SELECT * FROM PlaylistEntity") + suspend fun playlistsWithSong(): List + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertSongs(songEntities: List) +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt new file mode 100644 index 00000000..582c705a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt @@ -0,0 +1,34 @@ +package code.name.monkey.retromusic.db + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database( + entities = [PlaylistEntity::class, SongEntity::class], + version = 4, + exportSchema = false +) +abstract class PlaylistDatabase : RoomDatabase() { + abstract fun playlistDao(): PlaylistDao + + companion object { + @Volatile + private var INSTANCE: PlaylistDatabase? = null + + fun getDatabase( + context: Context + ): PlaylistDatabase { + return INSTANCE ?: synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + PlaylistDatabase::class.java, + "playlists.db" + ).fallbackToDestructiveMigration().build() + INSTANCE = instance + instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt new file mode 100644 index 00000000..7a490564 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt @@ -0,0 +1,15 @@ +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 + @ColumnInfo(name = "playlist_name") + val playlistName: String +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt new file mode 100644 index 00000000..c47fac08 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.db + +import androidx.room.Embedded +import androidx.room.Relation + +data class PlaylistWithSongs( + @Embedded val playlistEntity: PlaylistEntity, + @Relation( + parentColumn = "playlist_name", + entityColumn = "playlist_creator_name" + ) val songs: List +) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt new file mode 100644 index 00000000..94477b4d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt @@ -0,0 +1,9 @@ +package code.name.monkey.retromusic.db + +import androidx.annotation.WorkerThread + +class RoomPlaylistRepository(private val playlistDao: PlaylistDao) { + + @WorkerThread + suspend fun getPlaylistWithSongs(): List = playlistDao.playlistsWithSong() +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt new file mode 100644 index 00000000..3f492fc4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -0,0 +1,17 @@ +package code.name.monkey.retromusic.db + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +class SongEntity( + @ColumnInfo(name = "song_id") + val songId: Int, + @ColumnInfo(name = "playlist_creator_name") + val playlistCreatorName: String +) { + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "song_key") + var songPrimaryKey: Long = 0 +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt new file mode 100644 index 00000000..b731c198 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -0,0 +1,63 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.PlaylistEntity +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.model.Song +import code.name.monkey.retromusic.repository.RealSongRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.android.get + +class AddToRetroPlaylist : DialogFragment() { + companion object { + fun getInstance(playlistName: List): AddToRetroPlaylist { + return AddToRetroPlaylist().apply { + arguments = bundleOf("playlist_names" to playlistName) + } + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val playlistEntities = extraNotNull>("playlist_names").value + val playlistNames = mutableListOf() + playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist)) + for (p in playlistEntities) { + playlistNames.add(p.playlistName) + } + return materialDialog(R.string.add_playlist_title) + .setItems(playlistNames.toTypedArray()) { _, which -> + val songs = RealSongRepository(requireContext()).songs() + println(songs.size) + if (which == 0) { + CreateRetroPlaylist().show(requireActivity().supportFragmentManager, "Dialog") + } else { + lifecycleScope.launch(Dispatchers.IO) { + println(Thread.currentThread().name) + val database: PlaylistDatabase = get() + val songEntities = songs.withPlaylistIds(playlistEntities[which - 1]) + database.playlistDao().insertSongs(songEntities) + } + } + dismiss() + } + .create().colorButtons() + } +} + +private fun List.withPlaylistIds(playlistEntity: PlaylistEntity): List { + val songEntities = map { + SongEntity(it.id, playlistEntity.playlistName) + } + println(songEntities.size) + return songEntities +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt new file mode 100644 index 00000000..c7d9fad0 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -0,0 +1,43 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import android.text.TextUtils +import android.view.LayoutInflater +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.extensions.colorButtons +import code.name.monkey.retromusic.extensions.materialDialog +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.launch +import org.koin.android.ext.android.get + +class CreateRetroPlaylist : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null) + val playlistView: TextInputEditText = view.actionNewPlaylist + val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer + return materialDialog(R.string.new_playlist_title) + .setView(view) + .setPositiveButton( + R.string.create_action + ) { _, _ -> + val playlistName = playlistView.text.toString() + if (!TextUtils.isEmpty(playlistName)) { + val database: PlaylistDatabase = get() + lifecycleScope.launch { + database.playlistDao().createPlaylist(PlaylistEntity(playlistName)) + } + } else { + playlistContainer.error = "Playlist is can't be empty" + } + } + .create() + .colorButtons() + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index 41d40f09..162133d1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -4,15 +4,20 @@ import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.ui.NavigationUI import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import com.google.android.material.appbar.AppBarLayout import kotlinx.android.synthetic.main.fragment_library.* +import kotlinx.coroutines.launch +import org.koin.android.ext.android.get class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { @@ -55,11 +60,19 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_settings -> findNavController().navigate( - R.id.settingsActivity, - null, - navOptions - ) + R.id.action_settings -> + //CreateRetroPlaylist().show(childFragmentManager, "Dialog") + lifecycleScope.launch { + val database = get() + AddToRetroPlaylist.getInstance(database.playlistDao().playlists()) + .show(childFragmentManager, "PlaylistDialog") + } + + /*findNavController().navigate( + R.id.settingsActivity, + null, + navOptions + )*/ } return super.onOptionsItemSelected(item) } From b5e07a31d860e9d4d3332e8c83fba750ad2211ee Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Thu, 20 Aug 2020 12:19:08 +0530 Subject: [PATCH 02/46] Add Room for playlist Added DAO Queries and Able insert songs to playlist --- .../code/name/monkey/retromusic/MainModule.kt | 18 ++++-- .../retromusic/activities/MainActivity.kt | 7 +-- .../adapter/playlist/PlaylistAdapter.kt | 60 +++++++++---------- .../name/monkey/retromusic/db/PlaylistDao.kt | 7 +++ .../monkey/retromusic/db/PlaylistDatabase.kt | 2 +- .../monkey/retromusic/db/PlaylistEntity.kt | 7 ++- .../monkey/retromusic/db/PlaylistWithSongs.kt | 4 +- .../retromusic/db/RoomPlaylistRepository.kt | 35 ++++++++++- .../name/monkey/retromusic/db/SongEntity.kt | 4 +- .../retromusic/dialogs/AddToRetroPlaylist.kt | 10 ++-- .../retromusic/dialogs/CreateRetroPlaylist.kt | 10 +++- .../retromusic/fragments/LibraryViewModel.kt | 12 +++- .../fragments/library/LibraryFragment.kt | 6 +- .../fragments/playlists/PlaylistsFragment.kt | 3 +- .../retromusic/repository/Repository.kt | 13 +++- .../name/monkey/retromusic/util/MusicUtil.kt | 8 +++ 16 files changed, 140 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index f884f1fa..675f5abd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -1,6 +1,8 @@ package code.name.monkey.retromusic import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.RealRoomPlaylistRepository +import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel @@ -16,9 +18,15 @@ import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.bind import org.koin.dsl.module +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()) } bind Repository::class single { @@ -64,12 +72,12 @@ private val dataModule = module { } single { - androidContext().contentResolver + PlaylistDatabase.getDatabase(get()).playlistDao() } single { - PlaylistDatabase.getDatabase(get()) - } + RealRoomPlaylistRepository(get()) + } bind RoomPlaylistRepository::class } private val viewModules = module { @@ -111,4 +119,4 @@ private val viewModules = module { } } -val appModules = listOf(dataModule, viewModules, networkModule) \ No newline at end of file +val appModules = listOf(mainModule, dataModule, viewModules, networkModule) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 87791f4a..45d94b07 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -10,7 +10,7 @@ import android.view.View import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity -import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue @@ -58,11 +58,10 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis addMusicServiceEventListener(libraryViewModel) updateTabs() - val database: PlaylistDatabase = get() + val playlistRepository = get() lifecycleScope.launch { - println("Size:${database.playlistDao().playlistsWithSong()}") + println("Size:${playlistRepository.playlistWithSongs()}") } - } override fun onSupportNavigateUp(): Boolean = diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index 39d4f8e1..a4fa0914 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -13,22 +13,21 @@ import androidx.appcompat.widget.PopupMenu import androidx.core.os.bundleOf import androidx.fragment.app.FragmentActivity import androidx.navigation.findNavController -import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.EXTRA_PLAYLIST import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.show -import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.interfaces.CabHolder -import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist import code.name.monkey.retromusic.repository.PlaylistSongsLoader import code.name.monkey.retromusic.util.AutoGeneratedPlaylistBitmap import code.name.monkey.retromusic.util.MusicUtil @@ -37,10 +36,10 @@ 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 @@ -51,13 +50,13 @@ class PlaylistAdapter( 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,18 +68,18 @@ 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.playlistInfoString(activity, getSongs(playlist)) } 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)) val isChecked = isChecked(playlist) @@ -92,37 +91,34 @@ class PlaylistAdapter( //PlaylistBitmapLoader(this, holder, playlist).execute() } - private fun getIconRes(playlist: Playlist): Drawable { - return if (MusicUtil.isFavoritePlaylist(activity, playlist)) + private fun getIconRes(playlist: PlaylistWithSongs): Drawable { + return/* if (MusicUtil.isFavoritePlaylist(activity, playlist)) TintHelper.createTintedDrawable( activity, R.drawable.ic_favorite, ThemeStore.accentColor(activity) ) - else TintHelper.createTintedDrawable( + else*/ TintHelper.createTintedDrawable( activity, R.drawable.ic_playlist_play, ATHUtil.resolveColor(activity, R.attr.colorControlNormal) ) } - override fun getItemViewType(position: Int): Int { - return if (dataSet[position] is AbsSmartPlaylist) SMART_PLAYLIST else DEFAULT_PLAYLIST - } override fun getItemCount(): Int { 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,25 +128,27 @@ class PlaylistAdapter( } } - private fun getSongList(playlists: List): List { + private fun getSongList(playlists: List): List { val songs = ArrayList() - for (playlist in playlists) { + /* for (playlist in playlists) { + songs.addAll(playlist.songs) if (playlist is AbsCustomPlaylist) { songs.addAll(playlist.songs()) } else { songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id)) } - } + }*/ return songs } - private fun getSongs(playlist: Playlist): List { - val songs = ArrayList() - if (playlist is AbsSmartPlaylist) { + private fun getSongs(playlist: PlaylistWithSongs): List { + val songs = ArrayList() + songs.addAll(playlist.songs) + /*if (playlist is AbsSmartPlaylist) { songs.addAll(playlist.songs()) } else { songs.addAll(playlist.getSongs()) - } + }*/ return songs } @@ -167,7 +165,7 @@ class PlaylistAdapter( val popupMenu = PopupMenu(activity, view) popupMenu.inflate(R.menu.menu_item_playlist) popupMenu.setOnMenuItemClickListener { item -> - PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item) + return@setOnMenuItemClickListener true //PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item) } popupMenu.show() } diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index 7c595b3c..efe2e437 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -4,6 +4,10 @@ import androidx.room.* @Dao interface PlaylistDao { + + @Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name") + suspend fun checkPlaylistExists(name: String): List + @Insert suspend fun createPlaylist(playlistEntity: PlaylistEntity) @@ -16,4 +20,7 @@ interface PlaylistDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertSongs(songEntities: List) + + @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND song_id = :songId") + suspend fun checkSongExistsWithPlaylistName(playlistName: String, songId: Int): List } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt index 582c705a..3f8ec314 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt @@ -7,7 +7,7 @@ import androidx.room.RoomDatabase @Database( entities = [PlaylistEntity::class, SongEntity::class], - version = 4, + version = 7, exportSchema = false ) abstract class PlaylistDatabase : RoomDatabase() { diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt index 7a490564..3bb1681f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt @@ -9,7 +9,10 @@ import kotlinx.android.parcel.Parcelize @Entity @Parcelize class PlaylistEntity( - @PrimaryKey @ColumnInfo(name = "playlist_name") val playlistName: String -) : Parcelable \ No newline at end of file +) : Parcelable { + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "playlist_id") + var playListId: Int = 0 +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt index c47fac08..6645d6cd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt @@ -6,7 +6,7 @@ import androidx.room.Relation data class PlaylistWithSongs( @Embedded val playlistEntity: PlaylistEntity, @Relation( - parentColumn = "playlist_name", - entityColumn = "playlist_creator_name" + parentColumn = "playlist_id", + entityColumn = "playlist_creator_id" ) val songs: List ) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt index 94477b4d..7ab60e80 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt @@ -2,8 +2,39 @@ package code.name.monkey.retromusic.db import androidx.annotation.WorkerThread -class RoomPlaylistRepository(private val playlistDao: PlaylistDao) { + +interface RoomPlaylistRepository { + suspend fun createPlaylist(playlistEntity: PlaylistEntity) + suspend fun checkPlaylistExists(playlistName: String): List + suspend fun playlists(): List + suspend fun playlistWithSongs(): List + suspend fun insertSongs(songs: List) +} + +class RealRoomPlaylistRepository(private val playlistDao: PlaylistDao) : RoomPlaylistRepository { + @WorkerThread + override suspend fun createPlaylist(playlistEntity: PlaylistEntity) = + playlistDao.createPlaylist(playlistEntity) @WorkerThread - suspend fun getPlaylistWithSongs(): List = playlistDao.playlistsWithSong() + override suspend fun checkPlaylistExists(playlistName: String): List = + playlistDao.checkPlaylistExists(playlistName) + + @WorkerThread + override suspend fun playlists(): List = playlistDao.playlists() + + @WorkerThread + override suspend fun playlistWithSongs(): List = + playlistDao.playlistsWithSong() + + @WorkerThread + override suspend fun insertSongs(songs: List) { + /* val tempList = ArrayList(songs) + val existingSongs = songs.map { + playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId) + }.first() + println("Existing ${existingSongs.size}") + tempList.removeAll(existingSongs)*/ + playlistDao.insertSongs(songs) + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt index 3f492fc4..75c096ac 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -8,8 +8,8 @@ import androidx.room.PrimaryKey class SongEntity( @ColumnInfo(name = "song_id") val songId: Int, - @ColumnInfo(name = "playlist_creator_name") - val playlistCreatorName: String + @ColumnInfo(name = "playlist_creator_id") + val playlistCreatorId: Int ) { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "song_key") diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index b731c198..b3c29b02 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -6,8 +6,8 @@ import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull @@ -37,15 +37,13 @@ class AddToRetroPlaylist : DialogFragment() { return materialDialog(R.string.add_playlist_title) .setItems(playlistNames.toTypedArray()) { _, which -> val songs = RealSongRepository(requireContext()).songs() - println(songs.size) if (which == 0) { CreateRetroPlaylist().show(requireActivity().supportFragmentManager, "Dialog") } else { lifecycleScope.launch(Dispatchers.IO) { - println(Thread.currentThread().name) - val database: PlaylistDatabase = get() + val playlistRepository = get() val songEntities = songs.withPlaylistIds(playlistEntities[which - 1]) - database.playlistDao().insertSongs(songEntities) + playlistRepository.insertSongs(songEntities) } } dismiss() @@ -56,7 +54,7 @@ class AddToRetroPlaylist : DialogFragment() { private fun List.withPlaylistIds(playlistEntity: PlaylistEntity): List { val songEntities = map { - SongEntity(it.id, playlistEntity.playlistName) + SongEntity(it.id, playlistEntity.playListId) } println(songEntities.size) return songEntities diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt index c7d9fad0..9f0b6ea3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -7,8 +7,8 @@ import android.view.LayoutInflater import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.materialDialog import com.google.android.material.textfield.TextInputEditText @@ -29,9 +29,13 @@ class CreateRetroPlaylist : DialogFragment() { ) { _, _ -> val playlistName = playlistView.text.toString() if (!TextUtils.isEmpty(playlistName)) { - val database: PlaylistDatabase = get() + val playlistRepository: RoomPlaylistRepository = get() lifecycleScope.launch { - database.playlistDao().createPlaylist(PlaylistEntity(playlistName)) + if (playlistRepository.checkPlaylistExists(playlistName).isEmpty()) { + playlistRepository.createPlaylist(PlaylistEntity(playlistName)) + } else { + println("Playlist exists") + } } } else { playlistContainer.error = "Playlist is can't be empty" diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index dd4727a7..baa117a6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.fragments.ReloadType.* import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.* @@ -22,6 +23,7 @@ class LibraryViewModel( private val songs = MutableLiveData>() private val artists = MutableLiveData>() private val playlists = MutableLiveData>() + private val roomPlaylists = MutableLiveData>() private val genres = MutableLiveData>() private val home = MutableLiveData>() @@ -31,6 +33,7 @@ class LibraryViewModel( val songsLiveData: LiveData> = songs val artistsLiveData: LiveData> = artists val playlisitsLiveData: LiveData> = playlists + val roomPlaylisitsLiveData: LiveData> = roomPlaylists val genresLiveData: LiveData> = genres init { @@ -44,7 +47,8 @@ class LibraryViewModel( albums.value = loadAlbums.await() artists.value = loadArtists.await() playlists.value = loadPlaylists.await() - genres.value = loadGenres.await() + roomPlaylists.value = loadPlaylistsWithSongs.await() + //genres.value = loadGenres.await() home.value = loadHome.await() } @@ -68,6 +72,10 @@ class LibraryViewModel( get() = viewModelScope.async(IO) { realRepository.allPlaylists() } + private val loadPlaylistsWithSongs: Deferred> + get() = viewModelScope.async(IO) { + realRepository.playlistWithSongs() + } private val loadGenres: Deferred> get() = viewModelScope.async(IO) { @@ -80,7 +88,7 @@ class LibraryViewModel( Songs -> songs.value = loadSongs.await() Albums -> albums.value = loadAlbums.await() Artists -> artists.value = loadArtists.await() - HomeSections -> songs.value = loadSongs.await() + HomeSections -> home.value = loadHome.await() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index 162133d1..ad50073c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -10,7 +10,7 @@ import androidx.navigation.ui.NavigationUI import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment @@ -63,8 +63,8 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { R.id.action_settings -> //CreateRetroPlaylist().show(childFragmentManager, "Dialog") lifecycleScope.launch { - val database = get() - AddToRetroPlaylist.getInstance(database.playlistDao().playlists()) + val playlistRepository = get() + AddToRetroPlaylist.getInstance(playlistRepository.playlists()) .show(childFragmentManager, "PlaylistDialog") } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 22681715..6659fca1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -19,7 +19,7 @@ class PlaylistsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer { + libraryViewModel.roomPlaylisitsLiveData.observe(viewLifecycleOwner, Observer { if (it.isNotEmpty()) adapter?.swapDataSet(it) else @@ -43,6 +43,7 @@ class PlaylistsFragment : ) } + companion object { fun newInstance(): PlaylistsFragment { return PlaylistsFragment() diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index d035a72d..5ebdc374 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -16,6 +16,8 @@ package code.name.monkey.retromusic.repository import android.content.Context import code.name.monkey.retromusic.* +import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService @@ -82,6 +84,10 @@ interface Repository { suspend fun homeSectionsFlow(): Flow>> + suspend fun playlist(playlistId: Int): Playlist + + suspend fun playlistWithSongs(): List + fun songsFlow(): Flow>> fun albumsFlow(): Flow>> @@ -92,7 +98,6 @@ interface Repository { fun genresFlow(): Flow>> - suspend fun playlist(playlistId: Int): Playlist } class RealRepository( @@ -105,7 +110,8 @@ class RealRepository( private val lastAddedRepository: LastAddedRepository, private val playlistRepository: PlaylistRepository, private val searchRepository: RealSearchRepository, - private val playedTracksRepository: TopPlayedRepository + private val playedTracksRepository: TopPlayedRepository, + private val roomPlaylistRepository: RoomPlaylistRepository ) : Repository { override suspend fun allAlbums(): List = albumRepository.albums() @@ -214,6 +220,9 @@ class RealRepository( override suspend fun playlist(playlistId: Int) = playlistRepository.playlist(playlistId) + override suspend fun playlistWithSongs(): List = + roomPlaylistRepository.playlistWithSongs() + override suspend fun suggestionsHome(): Home { val songs = NotPlayedPlaylist().songs().shuffled().takeIf { diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index 130cee69..e1dfd027 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -13,6 +13,7 @@ import android.widget.Toast import androidx.core.content.FileProvider import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Playlist @@ -189,6 +190,13 @@ object MusicUtil : KoinComponent { ) } + fun playlistInfoString( + context: Context, + songs: List + ): String { + return getSongCountString(context, songs.size) + } + fun getReadableDurationString(songDurationMillis: Long): String? { var minutes = songDurationMillis / 1000 / 60 val seconds = songDurationMillis / 1000 % 60 From a93dcb028588f200d98fb96be4fbf9b5877b4e3e Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Thu, 20 Aug 2020 15:22:38 +0530 Subject: [PATCH 03/46] Changes Playlist to PlaylistEntity --- .../code/name/monkey/retromusic/MainModule.kt | 4 +- .../retromusic/activities/MainActivity.kt | 7 -- .../name/monkey/retromusic/db/PlaylistDao.kt | 5 +- .../monkey/retromusic/db/PlaylistWithSongs.kt | 8 +- .../retromusic/db/RoomPlaylistRepository.kt | 21 ++++-- .../name/monkey/retromusic/db/SongEntity.kt | 5 +- .../retromusic/dialogs/CreateRetroPlaylist.kt | 14 +++- .../retromusic/fragments/LibraryViewModel.kt | 6 +- .../playlists/PlaylistDetailsFragment.kt | 74 +++++++++---------- .../playlists/PlaylistDetailsViewModel.kt | 21 +++--- .../retromusic/repository/Repository.kt | 10 ++- .../retromusic/repository/SongRepository.kt | 19 ++--- .../res/layout/fragment_playlist_detail.xml | 8 ++ app/src/main/res/navigation/main_graph.xml | 2 +- 14 files changed, 115 insertions(+), 89 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index 675f5abd..e1f77f0e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -1,6 +1,7 @@ package code.name.monkey.retromusic import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.RealRoomPlaylistRepository import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.fragments.LibraryViewModel @@ -10,7 +11,6 @@ import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.search.SearchViewModel import code.name.monkey.retromusic.model.Genre -import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.network.networkModule import code.name.monkey.retromusic.repository.* import org.koin.android.ext.koin.androidContext @@ -100,7 +100,7 @@ private val viewModules = module { ) } - viewModel { (playlist: Playlist) -> + viewModel { (playlist: PlaylistWithSongs) -> PlaylistDetailsViewModel( get(), playlist diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 45d94b07..16491acc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -10,7 +10,6 @@ import android.view.View import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity -import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue @@ -26,7 +25,6 @@ import code.name.monkey.retromusic.util.AppRater.appLaunched import code.name.monkey.retromusic.util.PreferenceUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import java.util.* @@ -57,11 +55,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis appLaunched(this) addMusicServiceEventListener(libraryViewModel) updateTabs() - - val playlistRepository = get() - lifecycleScope.launch { - println("Size:${playlistRepository.playlistWithSongs()}") - } } override fun onSupportNavigateUp(): Boolean = diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index efe2e437..caf41875 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -9,7 +9,7 @@ interface PlaylistDao { suspend fun checkPlaylistExists(name: String): List @Insert - suspend fun createPlaylist(playlistEntity: PlaylistEntity) + suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long @Query("SELECT * FROM PlaylistEntity") suspend fun playlists(): List @@ -23,4 +23,7 @@ interface PlaylistDao { @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND song_id = :songId") suspend fun checkSongExistsWithPlaylistName(playlistName: String, songId: Int): List + + @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId ORDER BY song_key") + suspend fun getSongs(playlistId: Int): List } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt index 6645d6cd..405c7944 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt @@ -1,12 +1,16 @@ 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 -) \ No newline at end of file + ) + val songs: List +):Parcelable \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt index 7ab60e80..bdd7e0be 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt @@ -4,16 +4,17 @@ import androidx.annotation.WorkerThread interface RoomPlaylistRepository { - suspend fun createPlaylist(playlistEntity: PlaylistEntity) + suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun checkPlaylistExists(playlistName: String): List suspend fun playlists(): List suspend fun playlistWithSongs(): List suspend fun insertSongs(songs: List) + suspend fun getSongs(playlistEntity: PlaylistEntity): List } class RealRoomPlaylistRepository(private val playlistDao: PlaylistDao) : RoomPlaylistRepository { @WorkerThread - override suspend fun createPlaylist(playlistEntity: PlaylistEntity) = + override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = playlistDao.createPlaylist(playlistEntity) @WorkerThread @@ -29,12 +30,16 @@ class RealRoomPlaylistRepository(private val playlistDao: PlaylistDao) : RoomPla @WorkerThread override suspend fun insertSongs(songs: List) { - /* val tempList = ArrayList(songs) - val existingSongs = songs.map { - playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId) - }.first() - println("Existing ${existingSongs.size}") - tempList.removeAll(existingSongs)*/ + /* val tempList = ArrayList(songs) + val existingSongs = songs.map { + playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId) + }.first() + println("Existing ${existingSongs.size}") + tempList.removeAll(existingSongs)*/ playlistDao.insertSongs(songs) } + + override suspend fun getSongs(playlistEntity: PlaylistEntity): List { + return playlistDao.getSongs(playlistEntity.playListId) + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt index 75c096ac..c7410bcf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -1,16 +1,19 @@ 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 +@Parcelize @Entity class SongEntity( @ColumnInfo(name = "song_id") val songId: Int, @ColumnInfo(name = "playlist_creator_id") val playlistCreatorId: Int -) { +) : Parcelable { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "song_key") var songPrimaryKey: Long = 0 diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt index 9f0b6ea3..74402ede 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -11,13 +11,18 @@ import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import kotlinx.android.synthetic.main.dialog_playlist.view.* import kotlinx.coroutines.launch -import org.koin.android.ext.android.get +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class CreateRetroPlaylist : DialogFragment() { + private val playlistRepository by inject() + private val libraryViewModel by sharedViewModel() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null) val playlistView: TextInputEditText = view.actionNewPlaylist @@ -29,13 +34,16 @@ class CreateRetroPlaylist : DialogFragment() { ) { _, _ -> val playlistName = playlistView.text.toString() if (!TextUtils.isEmpty(playlistName)) { - val playlistRepository: RoomPlaylistRepository = get() lifecycleScope.launch { if (playlistRepository.checkPlaylistExists(playlistName).isEmpty()) { - playlistRepository.createPlaylist(PlaylistEntity(playlistName)) + val id: Long = + playlistRepository.createPlaylist(PlaylistEntity(playlistName)) + println(id) + libraryViewModel.forceReload(ReloadType.Playlists) } else { println("Playlist exists") } + } } else { playlistContainer.error = "Playlist is can't be empty" diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index baa117a6..53952e5c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -89,6 +89,8 @@ class LibraryViewModel( Albums -> albums.value = loadAlbums.await() Artists -> artists.value = loadArtists.await() HomeSections -> home.value = loadHome.await() + Playlists -> roomPlaylists.value = loadPlaylistsWithSongs.await() + Genres -> genres.value = loadGenres.await() } } @@ -136,5 +138,7 @@ enum class ReloadType { Songs, Albums, Artists, - HomeSections + HomeSections, + Playlists, + Genres, } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index 5c2d989b..e8b65a1e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -12,11 +12,9 @@ import androidx.recyclerview.widget.RecyclerView import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter import code.name.monkey.retromusic.adapter.song.SongAdapter +import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.extensions.dipToPix import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment -import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper -import code.name.monkey.retromusic.model.AbsCustomPlaylist -import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.PlaylistsUtil import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator @@ -32,7 +30,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,53 +44,49 @@ 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 - }) } private fun setUpRecyclerView() { recyclerView.layoutManager = LinearLayoutManager(requireContext()) - if (playlist is AbsCustomPlaylist) { + /*if (playlist is AbsCustomPlaylist) { adapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null) recyclerView.adapter = adapter - } else { - recyclerViewDragDropManager = RecyclerViewDragDropManager() - val animator = RefactoredDefaultItemAnimator() - adapter = OrderablePlaylistSongAdapter(requireActivity(), - ArrayList(), - R.layout.item_list, - null, - object : OrderablePlaylistSongAdapter.OnMoveItemListener { - override fun onMoveItem(fromPosition: Int, toPosition: Int) { - if (PlaylistsUtil.moveItem( - requireContext(), - playlist.id, - fromPosition, - toPosition - ) - ) { - val song = adapter.dataSet.removeAt(fromPosition) - adapter.dataSet.add(toPosition, song) - adapter.notifyItemMoved(fromPosition, toPosition) - } + } else {*/ + recyclerViewDragDropManager = RecyclerViewDragDropManager() + val animator = RefactoredDefaultItemAnimator() + adapter = OrderablePlaylistSongAdapter(requireActivity(), + ArrayList(), + R.layout.item_list, + null, + object : OrderablePlaylistSongAdapter.OnMoveItemListener { + override fun onMoveItem(fromPosition: Int, toPosition: Int) { + if (PlaylistsUtil.moveItem( + requireContext(), + playlist.playlistEntity.playListId, + fromPosition, + toPosition + ) + ) { + val song = adapter.dataSet.removeAt(fromPosition) + adapter.dataSet.add(toPosition, song) + adapter.notifyItemMoved(fromPosition, toPosition) } - }) - wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter) + } + }) + wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter) - recyclerView.adapter = wrappedAdapter - recyclerView.itemAnimator = animator + recyclerView.adapter = wrappedAdapter + recyclerView.itemAnimator = animator + + recyclerViewDragDropManager?.attachRecyclerView(recyclerView) - recyclerViewDragDropManager?.attachRecyclerView(recyclerView) - } adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onChanged() { super.onChanged() @@ -103,14 +97,14 @@ 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) } override fun onOptionsItemSelected(item: MenuItem): Boolean { - return PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item) + return true//PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item) } private fun checkForPadding() { @@ -160,11 +154,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/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt index de61bdeb..d8147f93 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt @@ -4,27 +4,26 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import code.name.monkey.retromusic.App +import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.interfaces.MusicServiceEventListener -import code.name.monkey.retromusic.model.AbsCustomPlaylist -import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository -import code.name.monkey.retromusic.util.PlaylistsUtil +import kotlinx.coroutines.Dispatchers 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 @@ -32,13 +31,13 @@ class PlaylistDetailsViewModel( loadPlaylistSongs(playlist) } - private fun loadPlaylistSongs(playlist: Playlist) = viewModelScope.launch { - val songs = realRepository.getPlaylistSongs(playlist) + private fun loadPlaylistSongs(playlist: PlaylistWithSongs) = viewModelScope.launch(Dispatchers.IO) { + val songs: List = realRepository.playlistSongs(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 +53,7 @@ class PlaylistDetailsViewModel( } } } - loadPlaylistSongs(playlist) + loadPlaylistSongs(playlist)*/ } override fun onServiceConnected() {} diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 5ebdc374..dbe85844 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -88,6 +88,8 @@ interface Repository { suspend fun playlistWithSongs(): List + suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List + fun songsFlow(): Flow>> fun albumsFlow(): Flow>> @@ -223,6 +225,12 @@ class RealRepository( override suspend fun playlistWithSongs(): List = roomPlaylistRepository.playlistWithSongs() + override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs ): List { + return playlistWithSongs.songs.map { + songRepository.song(it.songId) + } + } + override suspend fun suggestionsHome(): Home { val songs = NotPlayedPlaylist().songs().shuffled().takeIf { @@ -263,7 +271,7 @@ class RealRepository( playlistRepository.favoritePlaylist(context.getString(R.string.favorites)).take(5) val songs = if (playlists.isNotEmpty()) PlaylistSongsLoader.getPlaylistSongList(context, playlists[0]) - else emptyList() + else emptyList() return Home(songs, FAVOURITES) } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index 430401a6..e136a9b5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -151,17 +151,14 @@ class RealSongRepository(private val context: Context) : SongRepository { } selectionFinal = selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) - try { - return context.contentResolver.query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - baseProjection, - selectionFinal, - selectionValuesFinal, - sortOrder - ) - } catch (e: SecurityException) { - return null - } + + return context.contentResolver.query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + baseProjection, + selectionFinal, + selectionValuesFinal, + sortOrder + ) } private fun generateBlacklistSelection( diff --git a/app/src/main/res/layout/fragment_playlist_detail.xml b/app/src/main/res/layout/fragment_playlist_detail.xml index 8c3e7dd4..d75b5ba1 100644 --- a/app/src/main/res/layout/fragment_playlist_detail.xml +++ b/app/src/main/res/layout/fragment_playlist_detail.xml @@ -70,4 +70,12 @@ android:textColor="?android:attr/textColorSecondary" tools:visibility="visible" /> + + \ No newline at end of file diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index beead4b8..c3d3f444 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -26,7 +26,7 @@ tools:layout="@layout/fragment_playlist_detail"> + app:argType="code.name.monkey.retromusic.db.PlaylistWithSongs" /> Date: Thu, 20 Aug 2020 15:31:22 +0530 Subject: [PATCH 04/46] Updated SongEntity to Song --- .../name/monkey/retromusic/db/PlaylistDao.kt | 2 +- .../monkey/retromusic/db/PlaylistDatabase.kt | 2 +- .../name/monkey/retromusic/db/SongEntity.kt | 43 +++++++++++++++++-- .../retromusic/dialogs/AddToRetroPlaylist.kt | 6 +-- .../code/name/monkey/retromusic/model/Song.kt | 19 ++++++++ .../retromusic/repository/Repository.kt | 2 +- 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index caf41875..461e37aa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -21,7 +21,7 @@ interface PlaylistDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertSongs(songEntities: List) - @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND song_id = :songId") + @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND id = :songId") suspend fun checkSongExistsWithPlaylistName(playlistName: String, songId: Int): List @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId ORDER BY song_key") diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt index 3f8ec314..f1149c4f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt @@ -7,7 +7,7 @@ import androidx.room.RoomDatabase @Database( entities = [PlaylistEntity::class, SongEntity::class], - version = 7, + version = 8, exportSchema = false ) abstract class PlaylistDatabase : RoomDatabase() { diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt index c7410bcf..6d8b2e9d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -4,17 +4,54 @@ import android.os.Parcelable import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey +import code.name.monkey.retromusic.model.Song import kotlinx.android.parcel.Parcelize @Parcelize @Entity class SongEntity( - @ColumnInfo(name = "song_id") - val songId: Int, @ColumnInfo(name = "playlist_creator_id") - val playlistCreatorId: Int + val playlistCreatorId: Int, + val id: Int, + val title: String, + @ColumnInfo(name = "track_number") + val trackNumber: Int, + val year: Int, + val duration: Long, + val data: String, + @ColumnInfo(name = "date_modified") + val dateModified: Long, + @ColumnInfo(name = "album_id") + val albumId: Int, + @ColumnInfo(name = "album_name") + val albumName: String, + @ColumnInfo(name = "artist_id") + val artistId: Int, + @ColumnInfo(name = "artist_name") + val artistName: String, + val composer: String?, + @ColumnInfo(name = "album_artist") + val albumArtist: String? ) : Parcelable { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "song_key") var songPrimaryKey: Long = 0 + + fun toSong(): Song { + return Song( + id, + title, + trackNumber, + year, + duration, + data, + dateModified, + albumId, + albumName, + artistId, + artistName, + composer, + albumArtist + ) + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index b3c29b02..61006a57 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -53,9 +53,7 @@ class AddToRetroPlaylist : DialogFragment() { } private fun List.withPlaylistIds(playlistEntity: PlaylistEntity): List { - val songEntities = map { - SongEntity(it.id, playlistEntity.playListId) + return map { + it.toSongEntity(playlistEntity.playListId) } - println(songEntities.size) - return songEntities } diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt index 9b382295..ba3c0b97 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt @@ -14,6 +14,7 @@ package code.name.monkey.retromusic.model import android.os.Parcelable +import code.name.monkey.retromusic.db.SongEntity import kotlinx.android.parcel.Parcelize @Parcelize @@ -32,6 +33,24 @@ open class Song( val composer: String?, val albumArtist: String? ) : Parcelable { + fun toSongEntity(playListId: Int): SongEntity { + return SongEntity( + playListId, + id, + title, + trackNumber, + year, + duration, + data, + dateModified, + albumId, + albumName, + artistId, + artistName, + composer, + albumArtist + ) + } companion object { diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index dbe85844..61ed911e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -227,7 +227,7 @@ class RealRepository( override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs ): List { return playlistWithSongs.songs.map { - songRepository.song(it.songId) + it.toSong() } } From 6aa9b08ff2124dc231f2d08da227fadeed3cd655 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Thu, 20 Aug 2020 15:36:59 +0530 Subject: [PATCH 05/46] Code refactor --- app/src/main/java/code/name/monkey/retromusic/MainModule.kt | 4 ++-- .../main/java/code/name/monkey/retromusic/db/PlaylistDao.kt | 5 ++++- .../name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt | 2 +- .../name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt | 2 +- .../monkey/retromusic/fragments/library/LibraryFragment.kt | 2 +- .../code/name/monkey/retromusic/repository/Repository.kt | 1 - .../retromusic/{db => repository}/RoomPlaylistRepository.kt | 6 +++++- 7 files changed, 14 insertions(+), 8 deletions(-) rename app/src/main/java/code/name/monkey/retromusic/{db => repository}/RoomPlaylistRepository.kt (86%) diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index e1f77f0e..25aa04a5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -2,8 +2,8 @@ package code.name.monkey.retromusic import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.db.PlaylistWithSongs -import code.name.monkey.retromusic.db.RealRoomPlaylistRepository -import code.name.monkey.retromusic.db.RoomPlaylistRepository +import code.name.monkey.retromusic.repository.RealRoomPlaylistRepository +import code.name.monkey.retromusic.repository.RoomPlaylistRepository import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index 461e37aa..53f3ee65 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -24,6 +24,9 @@ interface PlaylistDao { @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND id = :songId") suspend fun checkSongExistsWithPlaylistName(playlistName: String, songId: Int): List - @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId ORDER BY song_key") + @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId ORDER BY title") suspend fun getSongs(playlistId: Int): List + + @Delete + suspend fun deletePlaylistEntity(playlistWithSongs: PlaylistWithSongs) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index 61006a57..28d351bc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -7,7 +7,7 @@ import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.db.RoomPlaylistRepository +import code.name.monkey.retromusic.repository.RoomPlaylistRepository import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt index 74402ede..1b6f9867 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -8,7 +8,7 @@ import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.db.RoomPlaylistRepository +import code.name.monkey.retromusic.repository.RoomPlaylistRepository import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index ad50073c..2868a368 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -10,7 +10,7 @@ import androidx.navigation.ui.NavigationUI import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.RoomPlaylistRepository +import code.name.monkey.retromusic.repository.RoomPlaylistRepository import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 61ed911e..ab3a05fb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -17,7 +17,6 @@ package code.name.monkey.retromusic.repository import android.content.Context import code.name.monkey.retromusic.* import code.name.monkey.retromusic.db.PlaylistWithSongs -import code.name.monkey.retromusic.db.RoomPlaylistRepository import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt similarity index 86% rename from app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt rename to app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt index bdd7e0be..d303a861 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt @@ -1,6 +1,10 @@ -package code.name.monkey.retromusic.db +package code.name.monkey.retromusic.repository import androidx.annotation.WorkerThread +import code.name.monkey.retromusic.db.PlaylistDao +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.SongEntity interface RoomPlaylistRepository { From f3988ae1d14ee4365820c975a9c863224797d2e1 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Fri, 21 Aug 2020 01:32:40 +0530 Subject: [PATCH 06/46] Playlist Add, Delete, Add Songs --- app/src/main/ic_launcher-playstore.png | Bin 44132 -> 100834 bytes .../code/name/monkey/retromusic/Constants.kt | 2 + .../adapter/playlist/PlaylistAdapter.kt | 22 +++-- .../song/OrderablePlaylistSongAdapter.kt | 4 +- .../name/monkey/retromusic/db/PlaylistDao.kt | 22 +++-- .../monkey/retromusic/db/PlaylistWithSongs.kt | 3 +- .../name/monkey/retromusic/db/SongEntity.kt | 6 ++ .../retromusic/dialogs/AddToRetroPlaylist.kt | 34 ++++++-- .../retromusic/dialogs/CreateRetroPlaylist.kt | 21 ++--- .../retromusic/dialogs/DeleteRetroPlaylist.kt | 76 +++++++++++++++++ .../dialogs/RemoveSongFromPlaylistDialog.kt | 79 ++++++++++++++++++ .../dialogs/RenameRetroPlaylistDialog.kt | 64 ++++++++++++++ .../fragments/DetailListFragment.kt | 1 + .../retromusic/fragments/LibraryViewModel.kt | 5 +- .../fragments/albums/AlbumDetailsFragment.kt | 16 +++- .../artists/ArtistDetailsFragment.kt | 16 +++- .../fragments/base/AbsPlayerFragment.kt | 14 +++- .../fragments/library/LibraryFragment.kt | 54 +++++------- .../playlists/PlaylistDetailsFragment.kt | 42 +++++----- .../fragments/playlists/PlaylistsFragment.kt | 2 +- .../settings/OtherSettingsFragment.kt | 5 ++ .../retromusic/helper/menu/GenreMenuHelper.kt | 17 +++- .../helper/menu/PlaylistMenuHelper.kt | 40 ++++++--- .../retromusic/helper/menu/SongMenuHelper.kt | 20 ++++- .../retromusic/helper/menu/SongsMenuHelper.kt | 21 +++-- .../retromusic/repository/Repository.kt | 56 +++++++++++-- .../repository/RoomPlaylistRepository.kt | 24 +++++- .../name/monkey/retromusic/util/AppRater.kt | 4 +- app/src/main/res/layout/fragment_library.xml | 14 +++- .../res/mipmap-anydpi-v26/ic_launcher.xml | 2 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 2 +- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2463 -> 5757 bytes .../mipmap-hdpi/ic_launcher_background.png | Bin 0 -> 14004 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 4830 -> 2721 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 4651 -> 6727 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1461 -> 3442 bytes .../mipmap-mdpi/ic_launcher_background.png | Bin 0 -> 8211 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 2714 -> 1703 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2687 -> 3894 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3669 -> 8641 bytes .../mipmap-xhdpi/ic_launcher_background.png | Bin 0 -> 20448 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 7432 -> 4172 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 6852 -> 10074 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6357 -> 14436 bytes .../mipmap-xxhdpi/ic_launcher_background.png | Bin 0 -> 34620 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 13244 -> 6381 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 11522 -> 16945 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9521 -> 20905 bytes .../mipmap-xxxhdpi/ic_launcher_background.png | Bin 0 -> 50987 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 19684 -> 10878 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 17132 -> 25067 bytes 51 files changed, 551 insertions(+), 137 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index f9c45db6b5a787a809e0f1d6ab9fa63dc2a282e3..94550783b3f42b39b04d2575eef3ae9823d4b7cb 100644 GIT binary patch literal 100834 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 z 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�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

LUvWonW2_)VEvo;f*!+zxvET*u+@s1 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 J{vTx8e*t|YsAd2F diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt index 0f037ba7..32e91aca 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt @@ -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" diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index a4fa0914..7f1af392 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -24,6 +24,7 @@ import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.show +import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.Playlist @@ -45,7 +46,6 @@ class PlaylistAdapter( R.menu.menu_playlists_selection ) { - init { setHasStableIds(true) } @@ -130,14 +130,14 @@ class PlaylistAdapter( private fun getSongList(playlists: List): List { val songs = ArrayList() - /* for (playlist in playlists) { - songs.addAll(playlist.songs) - if (playlist is AbsCustomPlaylist) { - songs.addAll(playlist.songs()) - } else { - songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id)) - } - }*/ + /* for (playlist in playlists) { + songs.addAll(playlist.songs) + if (playlist is AbsCustomPlaylist) { + songs.addAll(playlist.songs()) + } else { + songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id)) + } + }*/ return songs } @@ -165,7 +165,7 @@ class PlaylistAdapter( val popupMenu = PopupMenu(activity, view) popupMenu.inflate(R.menu.menu_item_playlist) popupMenu.setOnMenuItemClickListener { item -> - return@setOnMenuItemClickListener true //PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item) + PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item) } popupMenu.show() } @@ -219,7 +219,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/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt index 2b3ccc3c..77aa8eb6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R.menu import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog +import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.Song @@ -16,6 +17,7 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags class OrderablePlaylistSongAdapter( + private val playlistId: Int, activity: FragmentActivity, dataSet: ArrayList, itemLayoutRes: Int, @@ -118,7 +120,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(playlistId)) .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") return true } diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index 53f3ee65..f2266037 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -4,16 +4,21 @@ 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 renamePlaylistEntity(playlistId: Int, name: String) @Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name") suspend fun checkPlaylistExists(name: String): List - @Insert - suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long - @Query("SELECT * FROM PlaylistEntity") suspend fun playlists(): List + @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId") + suspend fun deleteSongsFromPlaylist(playlistId: Int) + @Transaction @Query("SELECT * FROM PlaylistEntity") suspend fun playlistsWithSong(): List @@ -24,9 +29,16 @@ interface PlaylistDao { @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND id = :songId") suspend fun checkSongExistsWithPlaylistName(playlistName: String, songId: Int): List - @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId ORDER BY title") + @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId") suspend fun getSongs(playlistId: Int): List @Delete - suspend fun deletePlaylistEntity(playlistWithSongs: PlaylistWithSongs) + suspend fun deletePlaylistEntity(playlistEntity: PlaylistEntity) + + @Delete + suspend fun deletePlaylistEntities(playlistEntities: List) + + @Delete + suspend fun removeSongsFromPlaylist(songs: List) + } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt index 405c7944..c69a415a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt @@ -13,4 +13,5 @@ data class PlaylistWithSongs( entityColumn = "playlist_creator_id" ) val songs: List -):Parcelable \ No newline at end of file +):Parcelable + diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt index 6d8b2e9d..715c0231 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -54,4 +54,10 @@ class SongEntity( albumArtist ) } +} + +fun List.toSongs(): List { + return map { + it.toSong() + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index 28d351bc..55519007 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -5,30 +5,46 @@ import android.os.Bundle import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.EXTRA_PLAYLISTS +import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.repository.RoomPlaylistRepository 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 import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.RealSongRepository +import code.name.monkey.retromusic.repository.RealRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import org.koin.android.ext.android.get +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class AddToRetroPlaylist : DialogFragment() { + private val repository by inject() + private val libraryViewModel by sharedViewModel() + companion object { - fun getInstance(playlistName: List): AddToRetroPlaylist { + fun create(playlistEntities: List, song: Song): AddToRetroPlaylist { + val list = mutableListOf() + list.add(song) + return create(playlistEntities, list) + } + + fun create(playlistEntities: List, songs: List): AddToRetroPlaylist { return AddToRetroPlaylist().apply { - arguments = bundleOf("playlist_names" to playlistName) + arguments = bundleOf( + EXTRA_SONG to songs, + EXTRA_PLAYLISTS to playlistEntities + ) } } } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val playlistEntities = extraNotNull>("playlist_names").value + val playlistEntities = extraNotNull>(EXTRA_PLAYLISTS).value val playlistNames = mutableListOf() playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist)) for (p in playlistEntities) { @@ -36,14 +52,14 @@ class AddToRetroPlaylist : DialogFragment() { } return materialDialog(R.string.add_playlist_title) .setItems(playlistNames.toTypedArray()) { _, which -> - val songs = RealSongRepository(requireContext()).songs() + val songs = extraNotNull>(EXTRA_SONG).value if (which == 0) { CreateRetroPlaylist().show(requireActivity().supportFragmentManager, "Dialog") } else { lifecycleScope.launch(Dispatchers.IO) { - val playlistRepository = get() val songEntities = songs.withPlaylistIds(playlistEntities[which - 1]) - playlistRepository.insertSongs(songEntities) + repository.insertSongs(songEntities) + libraryViewModel.forceReload(ReloadType.Playlists) } } dismiss() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt index 1b6f9867..6d237ebb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -4,24 +4,26 @@ import android.app.Dialog import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater +import android.widget.Toast import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.repository.RoomPlaylistRepository import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel -import code.name.monkey.retromusic.fragments.ReloadType +import code.name.monkey.retromusic.fragments.ReloadType.Playlists +import code.name.monkey.retromusic.repository.RealRepository 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.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class CreateRetroPlaylist : DialogFragment() { - private val playlistRepository by inject() + private val repository by inject() private val libraryViewModel by sharedViewModel() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null) @@ -34,14 +36,13 @@ class CreateRetroPlaylist : DialogFragment() { ) { _, _ -> val playlistName = playlistView.text.toString() if (!TextUtils.isEmpty(playlistName)) { - lifecycleScope.launch { - if (playlistRepository.checkPlaylistExists(playlistName).isEmpty()) { - val id: Long = - playlistRepository.createPlaylist(PlaylistEntity(playlistName)) - println(id) - libraryViewModel.forceReload(ReloadType.Playlists) + lifecycleScope.launch(Dispatchers.IO) { + if (repository.checkPlaylistExists(playlistName).isEmpty()) { + repository.createPlaylist(PlaylistEntity(playlistName)) + libraryViewModel.forceReload(Playlists) } else { - println("Playlist exists") + Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) + .show() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt new file mode 100644 index 00000000..3b024044 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt @@ -0,0 +1,76 @@ +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 androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.EXTRA_PLAYLIST +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.extensions.colorButtons +import code.name.monkey.retromusic.extensions.extraNotNull +import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType +import code.name.monkey.retromusic.repository.Repository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class DeleteRetroPlaylist : DialogFragment() { + private val repository by inject() + private val libraryViewModel by sharedViewModel() + + companion object { + + fun create(playlist: PlaylistEntity): DeleteRetroPlaylist { + val list = mutableListOf() + list.add(playlist) + return create(list) + } + + fun create(playlists: List): DeleteRetroPlaylist { + return DeleteRetroPlaylist().apply { + arguments = bundleOf(EXTRA_PLAYLIST to playlists) + } + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val playlists = extraNotNull>(EXTRA_PLAYLIST).value + val title: Int + val message: CharSequence + //noinspection ConstantConditions + if (playlists.size > 1) { + title = R.string.delete_playlists_title + message = HtmlCompat.fromHtml( + String.format(getString(R.string.delete_x_playlists), playlists.size), + HtmlCompat.FROM_HTML_MODE_LEGACY + ) + } else { + title = R.string.delete_playlist_title + message = HtmlCompat.fromHtml( + String.format(getString(R.string.delete_playlist_x), playlists[0].playlistName), + HtmlCompat.FROM_HTML_MODE_LEGACY + ) + } + + return materialDialog(title) + .setTitle(title) + .setMessage(message) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.action_delete) { _, _ -> + lifecycleScope.launch(Dispatchers.IO) { + repository.deleteSongsFromPlaylist(playlists) + repository.deleteRoomPlaylist(playlists) + libraryViewModel.forceReload(ReloadType.Playlists) + } + } + .create() + .colorButtons() + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt new file mode 100644 index 00000000..7193a5b3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt @@ -0,0 +1,79 @@ +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 androidx.lifecycle.lifecycleScope +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.repository.Repository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class RemoveSongFromPlaylistDialog : DialogFragment() { + private val repository by inject() + 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) { _, _ -> + lifecycleScope.launch(Dispatchers.IO) { + repository.removeSongFromPlaylist(songs) + } + /* PlaylistsUtil.removeFromPlaylist( + requireContext(), + songs as MutableList + )*/ + } + .setNegativeButton(android.R.string.cancel, null) + .create() + .colorButtons() + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt new file mode 100644 index 00000000..a12da522 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt @@ -0,0 +1,64 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import android.view.LayoutInflater +import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.extensions.accentColor +import code.name.monkey.retromusic.extensions.colorButtons +import code.name.monkey.retromusic.extensions.extraNotNull +import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType +import code.name.monkey.retromusic.repository.Repository +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class RenameRetroPlaylistDialog : DialogFragment() { + private val repository by inject() + private val libraryViewModel by sharedViewModel() + + companion object { + fun create(playlistEntity: PlaylistEntity): RenameRetroPlaylistDialog { + return RenameRetroPlaylistDialog().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) + 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()) { + lifecycleScope.launch(Dispatchers.IO) { + repository.renameRoomPlaylist(playlistEntity.playListId, name) + libraryViewModel.forceReload(ReloadType.Playlists) + } + } else { + nameContainer.error = "Playlist name should'nt be empty" + } + } + .create() + .colorButtons() + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt index 53273281..e4045edd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt @@ -34,6 +34,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) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index 53952e5c..852ccc56 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -33,7 +33,7 @@ class LibraryViewModel( val songsLiveData: LiveData> = songs val artistsLiveData: LiveData> = artists val playlisitsLiveData: LiveData> = playlists - val roomPlaylisitsLiveData: LiveData> = roomPlaylists + val roomPlaylistsLiveData: LiveData> = roomPlaylists val genresLiveData: LiveData> = genres init { @@ -43,13 +43,13 @@ class LibraryViewModel( } private fun loadLibraryContent() = viewModelScope.launch { + home.value = loadHome.await() songs.value = loadSongs.await() albums.value = loadAlbums.await() artists.value = loadArtists.await() playlists.value = loadPlaylists.await() roomPlaylists.value = loadPlaylistsWithSongs.await() //genres.value = loadGenres.await() - home.value = loadHome.await() } private val loadHome: Deferred> @@ -84,6 +84,7 @@ class LibraryViewModel( fun forceReload(reloadType: ReloadType) = viewModelScope.launch { + println(reloadType) when (reloadType) { Songs -> songs.value = loadSongs.await() Albums -> albums.value = loadAlbums.await() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 9bc60bd5..526cd5c9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -7,6 +7,7 @@ import android.view.* import androidx.appcompat.app.AppCompatActivity import androidx.core.os.bundleOf import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -22,7 +23,7 @@ import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.show @@ -35,6 +36,7 @@ import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.network.model.LastFmAlbum +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil @@ -42,6 +44,10 @@ import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.fragment_album_content.* import kotlinx.android.synthetic.main.fragment_album_details.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.koin.android.ext.android.get import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import java.util.* @@ -275,7 +281,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().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, songs) + .show(childFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_delete_from_device -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt index 8fc574eb..58d59d1d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt @@ -10,6 +10,7 @@ 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 @@ -19,7 +20,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.showToast @@ -30,6 +31,7 @@ import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.network.model.LastFmArtist +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.CustomArtistImageUtil import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.RetroUtil @@ -37,6 +39,10 @@ import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.fragment_artist_content.* import kotlinx.android.synthetic.main.fragment_artist_details.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.koin.android.ext.android.get import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf import java.util.* @@ -216,7 +222,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().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, songs) + .show(childFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_set_artist_image -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index f37423fe..ed4e7f91 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -15,6 +15,7 @@ import android.widget.Toast import androidx.annotation.LayoutRes import androidx.appcompat.widget.Toolbar import androidx.core.os.bundleOf +import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.EXTRA_ARTIST_ID @@ -29,8 +30,13 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.PaletteColorHolder import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.lyrics.Lyrics +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.* import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.* +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.sharedViewModel import java.io.FileNotFoundException @@ -64,7 +70,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(Dispatchers.IO) { + val playlists = get().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, song) + .show(childFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_clear_playing_queue -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index 2868a368..6a4b9f0d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -4,20 +4,15 @@ import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.ui.NavigationUI import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.repository.RoomPlaylistRepository -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.CreateRetroPlaylist import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment -import com.google.android.material.appbar.AppBarLayout import kotlinx.android.synthetic.main.fragment_library.* -import kotlinx.coroutines.launch -import org.koin.android.ext.android.get class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { @@ -34,12 +29,29 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { navOptions ) } + addPlaylist.setOnClickListener { + CreateRetroPlaylist().show(childFragmentManager, "ShowCreatePlaylistDialog") + } setupNavigationController() } private fun setupNavigationController() { val navController = findNavController(R.id.fragment_container) NavigationUI.setupWithNavController(mainActivity.getBottomNavigationView(), navController) + navController.addOnDestinationChangedListener { _, destination, _ -> + if (destination.id in arrayOf( + R.id.action_album, + R.id.action_artist, + R.id.action_home, + R.id.action_song, + R.id.action_genre + ) + ) { + addPlaylist.hide() + } else { + addPlaylist.show() + } + } } override fun onPrepareOptionsMenu(menu: Menu) { @@ -60,32 +72,12 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_settings -> - //CreateRetroPlaylist().show(childFragmentManager, "Dialog") - lifecycleScope.launch { - val playlistRepository = get() - AddToRetroPlaylist.getInstance(playlistRepository.playlists()) - .show(childFragmentManager, "PlaylistDialog") - } - - /*findNavController().navigate( - R.id.settingsActivity, - null, - navOptions - )*/ + R.id.action_settings -> findNavController().navigate( + R.id.settingsActivity, + null, + navOptions + ) } 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/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index e8b65a1e..beaedd5a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -15,6 +15,7 @@ import code.name.monkey.retromusic.adapter.song.SongAdapter import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.extensions.dipToPix import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment +import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.PlaylistsUtil import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator @@ -61,25 +62,28 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } else {*/ recyclerViewDragDropManager = RecyclerViewDragDropManager() val animator = RefactoredDefaultItemAnimator() - adapter = OrderablePlaylistSongAdapter(requireActivity(), - ArrayList(), - R.layout.item_list, - null, - object : OrderablePlaylistSongAdapter.OnMoveItemListener { - override fun onMoveItem(fromPosition: Int, toPosition: Int) { - if (PlaylistsUtil.moveItem( - requireContext(), - playlist.playlistEntity.playListId, - fromPosition, - toPosition - ) - ) { - val song = adapter.dataSet.removeAt(fromPosition) - adapter.dataSet.add(toPosition, song) - adapter.notifyItemMoved(fromPosition, toPosition) + adapter = + OrderablePlaylistSongAdapter( + playlist.playlistEntity.playListId, + requireActivity(), + ArrayList(), + R.layout.item_list, + null, + object : OrderablePlaylistSongAdapter.OnMoveItemListener { + override fun onMoveItem(fromPosition: Int, toPosition: Int) { + if (PlaylistsUtil.moveItem( + requireContext(), + playlist.playlistEntity.playListId, + fromPosition, + toPosition + ) + ) { + val song = adapter.dataSet.removeAt(fromPosition) + adapter.dataSet.add(toPosition, song) + adapter.notifyItemMoved(fromPosition, toPosition) + } } - } - }) + }) wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter) recyclerView.adapter = wrappedAdapter @@ -104,7 +108,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } override fun onOptionsItemSelected(item: MenuItem): Boolean { - return true//PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item) + return PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item) } private fun checkForPadding() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 6659fca1..cd3a2f60 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -19,7 +19,7 @@ class PlaylistsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - libraryViewModel.roomPlaylisitsLiveData.observe(viewLifecycleOwner, Observer { + libraryViewModel.roomPlaylistsLiveData.observe(viewLifecycleOwner, Observer { if (it.isNotEmpty()) adapter?.swapDataSet(it) else diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt index 2338c6f7..c52d4adb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 code.name.monkey.retromusic.R +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.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/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt index 08b9c3a2..df43e38d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt @@ -17,12 +17,18 @@ package code.name.monkey.retromusic.helper.menu import android.view.MenuItem import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.GenreRepository +import code.name.monkey.retromusic.repository.RealRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.koin.core.KoinComponent +import org.koin.core.get import org.koin.core.inject object GenreMenuHelper : KoinComponent { @@ -38,8 +44,13 @@ object GenreMenuHelper : KoinComponent { return true } R.id.action_add_to_playlist -> { - AddToPlaylistDialog.create(getGenreSongs(genre)) - .show(activity.supportFragmentManager, "ADD_PLAYLIST") + CoroutineScope(Dispatchers.IO).launch { + val playlists = get().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, getGenreSongs(genre)) + .show(activity.supportFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_add_to_current_playing -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt index 37e5e3d1..9314e4ee 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt @@ -22,53 +22,67 @@ import android.widget.Toast import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog -import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog -import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog +import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.toSongs +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.DeleteRetroPlaylist +import code.name.monkey.retromusic.dialogs.RenameRetroPlaylistDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.misc.WeakContextAsyncTask import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.PlaylistsUtil +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.koin.core.KoinComponent +import org.koin.core.get -object PlaylistMenuHelper { +object PlaylistMenuHelper : KoinComponent { fun handleMenuClick( activity: FragmentActivity, - playlist: Playlist, item: MenuItem + playlistWithSongs: PlaylistWithSongs, item: MenuItem ): Boolean { when (item.itemId) { R.id.action_play -> { - MusicPlayerRemote.openQueue(getPlaylistSongs(activity, playlist), 9, true) + MusicPlayerRemote.openQueue(playlistWithSongs.songs.toSongs(), 0, true) return true } R.id.action_play_next -> { - MusicPlayerRemote.playNext(getPlaylistSongs(activity, playlist)) + MusicPlayerRemote.playNext(playlistWithSongs.songs.toSongs()) return true } R.id.action_add_to_playlist -> { - AddToPlaylistDialog.create(getPlaylistSongs(activity, playlist)) - .show(activity.supportFragmentManager, "ADD_PLAYLIST") + CoroutineScope(Dispatchers.IO).launch { + val playlists = get().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, playlistWithSongs.songs.toSongs()) + .show(activity.supportFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_add_to_current_playing -> { - MusicPlayerRemote.enqueue(getPlaylistSongs(activity, playlist)) + MusicPlayerRemote.enqueue(playlistWithSongs.songs.toSongs()) return true } R.id.action_rename_playlist -> { - RenamePlaylistDialog.create(playlist.id.toLong()) + RenameRetroPlaylistDialog.create(playlistWithSongs.playlistEntity ) .show(activity.supportFragmentManager, "RENAME_PLAYLIST") return true } R.id.action_delete_playlist -> { - DeletePlaylistDialog.create(playlist) + DeleteRetroPlaylist.create(playlistWithSongs.playlistEntity) .show(activity.supportFragmentManager, "DELETE_PLAYLIST") return true } R.id.action_save_playlist -> { - SavePlaylistAsyncTask(activity).execute(playlist) + //SavePlaylistAsyncTask(activity).execute(playlistWithSongs.songs.toSongs()) return true } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt index 0fb27c98..115926de 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt @@ -26,16 +26,23 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.dialogs.SongDetailDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.PaletteColorHolder import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.RingtoneManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.koin.core.KoinComponent +import org.koin.core.get -object SongMenuHelper { +object SongMenuHelper : KoinComponent { const val MENU_RES = R.menu.menu_item_song fun handleMenuClick(activity: FragmentActivity, song: Song, menuItemId: Int): Boolean { @@ -63,8 +70,13 @@ object SongMenuHelper { return true } R.id.action_add_to_playlist -> { - AddToPlaylistDialog.create(song) - .show(activity.supportFragmentManager, "ADD_PLAYLIST") + CoroutineScope(Dispatchers.IO).launch { + val playlists = get().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, song) + .show(activity.supportFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_play_next -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt index 871619e1..058de45f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt @@ -16,13 +16,19 @@ package code.name.monkey.retromusic.helper.menu import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.repository.RealRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.koin.core.KoinComponent +import org.koin.core.get - -object SongsMenuHelper { +object SongsMenuHelper : KoinComponent { fun handleMenuClick( activity: FragmentActivity, songs: List, @@ -38,8 +44,13 @@ object SongsMenuHelper { return true } R.id.action_add_to_playlist -> { - AddToPlaylistDialog.create(songs) - .show(activity.supportFragmentManager, "ADD_PLAYLIST") + CoroutineScope(Dispatchers.IO).launch { + val playlists = get().roomPlaylists() + withContext(Dispatchers.Main) { + AddToRetroPlaylist.create(playlists, songs) + .show(activity.supportFragmentManager, "ADD_PLAYLIST") + } + } return true } R.id.action_delete_from_device -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index ab3a05fb..dab9e818 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -16,7 +16,9 @@ package code.name.monkey.retromusic.repository import android.content.Context import code.name.monkey.retromusic.* +import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService @@ -29,6 +31,17 @@ import kotlinx.coroutines.flow.flow interface Repository { + fun songsFlow(): Flow>> + + fun albumsFlow(): Flow>> + + fun artistsFlow(): Flow>> + + fun playlistsFlow(): Flow>> + + fun genresFlow(): Flow>> + + suspend fun allAlbums(): List suspend fun albumById(albumId: Int): Album @@ -89,16 +102,21 @@ interface Repository { suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List - fun songsFlow(): Flow>> + suspend fun insertSongs(songs: List) - fun albumsFlow(): Flow>> + suspend fun checkPlaylistExists(playlistName: String): List - fun artistsFlow(): Flow>> + suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long - fun playlistsFlow(): Flow>> + suspend fun roomPlaylists(): List - fun genresFlow(): Flow>> + suspend fun deleteRoomPlaylist(playlists: List) + suspend fun renameRoomPlaylist(playlistId: Int, name: String) + + suspend fun removeSongFromPlaylist(songs: List) + + suspend fun deleteSongsFromPlaylist(playlists: List) } class RealRepository( @@ -206,7 +224,6 @@ class RealRepository( ) for (section in sections) { if (section.arrayList.isNotEmpty()) { - println("${section.homeSection} -> ${section.arrayList.size}") homeSections.add(section) } } @@ -224,12 +241,35 @@ class RealRepository( override suspend fun playlistWithSongs(): List = roomPlaylistRepository.playlistWithSongs() - override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs ): List { + override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List { return playlistWithSongs.songs.map { - it.toSong() + it.toSong() } } + override suspend fun insertSongs(songs: List) = + roomPlaylistRepository.insertSongs(songs) + + override suspend fun checkPlaylistExists(playlistName: String): List = + roomPlaylistRepository.checkPlaylistExists(playlistName) + + override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = + roomPlaylistRepository.createPlaylist(playlistEntity) + + override suspend fun roomPlaylists(): List = roomPlaylistRepository.playlists() + + override suspend fun deleteRoomPlaylist(playlists: List) = + roomPlaylistRepository.deletePlaylistEntities(playlists) + + override suspend fun renameRoomPlaylist(playlistId: Int, name: String) = + roomPlaylistRepository.renamePlaylistEntity(playlistId, name) + + override suspend fun removeSongFromPlaylist(songs: List) = + roomPlaylistRepository.removeSongsFromPlaylist(songs) + + override suspend fun deleteSongsFromPlaylist(playlists: List) = + roomPlaylistRepository.deleteSongsFromPlaylist(playlists) + override suspend fun suggestionsHome(): Home { val songs = NotPlayedPlaylist().songs().shuffled().takeIf { diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt index d303a861..b7b8e009 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt @@ -14,9 +14,15 @@ interface RoomPlaylistRepository { suspend fun playlistWithSongs(): List suspend fun insertSongs(songs: List) suspend fun getSongs(playlistEntity: PlaylistEntity): List + suspend fun deletePlaylistEntities(playlistEntities: List) + suspend fun renamePlaylistEntity(playlistId: Int, name: String) + suspend fun removeSongsFromPlaylist(songs: List) + suspend fun deleteSongsFromPlaylist(playlists: List) } -class RealRoomPlaylistRepository(private val playlistDao: PlaylistDao) : RoomPlaylistRepository { +class RealRoomPlaylistRepository( + private val playlistDao: PlaylistDao +) : RoomPlaylistRepository { @WorkerThread override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = playlistDao.createPlaylist(playlistEntity) @@ -46,4 +52,20 @@ class RealRoomPlaylistRepository(private val playlistDao: PlaylistDao) : RoomPla override suspend fun getSongs(playlistEntity: PlaylistEntity): List { return playlistDao.getSongs(playlistEntity.playListId) } + + override suspend fun deletePlaylistEntities(playlistEntities: List) = + playlistDao.deletePlaylistEntities(playlistEntities) + + override suspend fun renamePlaylistEntity(playlistId: Int, name: String) = + playlistDao.renamePlaylistEntity(playlistId, name) + + override suspend fun removeSongsFromPlaylist(songs: List) = + playlistDao.removeSongsFromPlaylist(songs) + + override suspend fun deleteSongsFromPlaylist(playlists: List) { + playlists.forEach { + playlistDao.deleteSongsFromPlaylist(it.playListId) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt b/app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt index 6cbeb1fb..8b12c41e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt @@ -19,7 +19,6 @@ import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.Uri -import android.widget.Toast import code.name.monkey.retromusic.R import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.play.core.review.ReviewManagerFactory @@ -71,8 +70,7 @@ object AppRater { val reviewInfo = request.result manager.launchReviewFlow(context as Activity, reviewInfo).addOnCompleteListener { if (it.isSuccessful) { - Toast.makeText(context, "Thanks for the feedback", Toast.LENGTH_SHORT) - .show() + //Toast.makeText(context, "Thanks for the feedback", Toast.LENGTH_SHORT).show() } } } diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index bc0ec2a8..5d61e740 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -32,8 +32,8 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/app_name" - android:textStyle="bold" - android:textAppearance="@style/TextViewHeadline6" /> + android:textAppearance="@style/TextViewHeadline6" + android:textStyle="bold" /> + + - + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 036d09bc..4ae7d123 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index ef3cfc0aa34c1aef2dfa02eb15ef19ac8a4f65e7..b5c2dab14bd7bfe8d4e13b0f6c29f78f701cbf0b 100644 GIT binary patch literal 5757 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 delta 2454 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 Ujt_rjS^xk507*qoM6N<$g8NmRZ~y=R diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..94cbef3c0cec4f5c20787fb0a2c1f6d4b8c66bee GIT binary patch literal 14004 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 GhW!tiB7t52 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png index ba6874195b76fcdf64fefa2e509d145271e4e954..a7a2521b1441a93ad72a4d12086a873e75fe338b 100644 GIT binary patch literal 2721 zcmbtWi8mCA7gn~hmCzs(V~Q7L8QErxFk>6rL{bgP`kS#c#@0l#&LF0-H_5(4uMshb zo}IBilwBfZ-IS^S!N}v+XcqDoNuy?`i)XuB%C)I}9j>dmf~$4B=)S z5<4JKgcWUe*}m}LocUHwieKmP_T!mD+VPPX{|Su$XbBvKSW&hX(ECADn&Q^Gdli3< zdA`rlqV*+`@;r-Itm~TB2!|UN&lnk_P|Ri)ixq#gCn&!O%=f_IB8^=x?eFas0%XRc z!{m4Of=ph8`*?VS@#S$m4Qx`G57m`ZxlAbuZ57P@@dsGtcy_$n= zvcuY%d;V5U_O%>;ZuQ1_c+Ajum}yS`S(Mu8zv*pGKh-&(pP9|a}vjb&6<@5yFH zFX6QzONU~yh13S!sxi+Tref>KX08MH+x+|f?J4VdrjVH>${{`zcT3uc?E$oMKdY24kI$2o_RIRVCXTx7o>&>nV zWoKMmuD>IBNmy98$N8M&`L8XpXIlhn3yY6AddZKDe-ot^S(9|UmzS5^_Z{;aUmljG zpz|2VWo2dK-<*lFd#=p150MmDrK#GCYPJI!P46&51Yc8A!@p0XpeaTfVj)&X{@&i} zjwS9k4phJ;-N%yeoZ3it1S|=oH=|_j5{Bl!ew_}|rkS_ANJ55${A@{8xbs-p0)TN1 zT`n@up02!C!PA02dv|_*e$xOQ8EHK|^7_tVt`f&DY}T7s85tQf?`vw(VZ{@KuYWz| z20`xK<5LH!GB~B=WSZ5XZuh29U;22Qn+McXnV?i{JXwk@I(>6qn1&uA;52TRQr-LdIY{3(uQu=+?e86y+zXrOS=>y%EQC+ z$T0Cl3$1As`($<=axyKMiN|6~OUlbdMn*>R8XFzdZrs>vLE}g#l(R*$bahIn+}`~< z<1}0|k+}V8ml4^6vU#aNVIQxB<>-bxw03lmTU!y;Ht+aCLHg^mTAld7KtC;@C7#4Nyt2c za?-2(<9(H%rR<}FgZl+k>JHkm#TK;jEE;X?%LL)a`cwc^=6MNM7CS;D<+1dHch9WU}Zq{0;QjQyv+Czhi&LU4Am8{x}b$e;?3LdN1 z)>w~^XmEMYG!kV}U3aA0)uaqej?8yS@b#GCKZ#FKtAak~6zFuitfuAqUs!&q)b7X(<14lf{hgtq8mwKk^}t|F zjte&Nb;33C;B9y?mVT@r*GAY&v=$Z;(k}tm@T<${&eduI20O%2A4VT4c|G{mqg*RH zi)q>T$j*J{C_<9{F&pF}52$!5NW{cZEfS~gRu>i)Ecp$f*~!tW*tPNMfKK}lA!;xE zmj-e_56T|Y3SI*;xqQkANMu`>gYU(42{{ffuD+6riW{MGA-Jo1eu}<5LPS_O0)co$ zqm(+A#Jaq3Y8Duym~>0&4TL-wrrIzyxc+~{GUp%)Si=RCMJa_rYGJhtTJ ztm#5lvuS%uC@8fXG&@2hK(r59xWeFye*ZL>INydVRapE7v(IL0{n+u9-{YV4q9{<=90f?=Y;&~Ui2}VQ zkx1~eH*eH|K%lod3U&CcA!Ns4q5r28&g%@ej$|M5Tj|9HfUBW^Xp<1{_{T>QTs6Ql*=jsAnke*n4P B48#Bc literal 4830 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 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 6c46ac4cb68f1f54b5a2501bd44005d0897a9237..e79f3cbbc2d250332ea49883a0d95f85c62f6614 100644 GIT binary patch literal 6727 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 literal 4651 zcmV+`64dR9P)UByd^MwyI6BEXg zQ3LUTihzoO0vf)uMnfsbOhjIayyX2n=d6AB&+mWE+MLY+yujHg&OM*c|8ow9z1Lam zdw&1NT6^tt&pmhWK|~#-IW=LH|KIcf$5!Q*HTX0_8IsbCNq!M^=PEGv(KG?&s z$6-%NdtAPEUu)XDTfkVpb-VX|1#^eZgKdYMhNZy@Yinz(U`A>Dx={Y_v^;jMJoi_2 zZMH~_?Ey?DtsCI=ZxltDh5;Wio6Y%nO>9Dl7MXe;w}G~zxlL}{&V4(zcf~kq{vLqA zgusgJpqNc2lfs7A{A}j;V6}E;mj6>U$Jc6saohYE{8@JH*RkEHMtzOWyWtx?f{tsU zr~@>&R5^{9S%s^G#h=Na-B_RQbO3geue+m@5n3?z-+CKZt^5ovs0i+hegEzRoX+ZN zK$#7zkzi_X1DK{jSw0heF>s$6>+5ZWgXdoWN{mJ^;xu9O zf-tpbQ~QW#Dk>@(-zG{@8-#Ma?j|@|NUU~zxs;omJ5pCjswB}k#~j1m2FD&!O-+p< zBO~KEUEEDm<2ZA$lQHM6gJTb=qM{<}!i5VDYRBjhAT%D+76I8*BdEGm(9KJNGL8sJ ziBjmNaD`I#DU^9kP*J*|nhG3e)IV_Fym|95hSs6gfHWCvmfmm-<%06g2>M~YLdX9{ zp(B4(C~mSshbAc$J5iy7ZzvQ!UZH)j<9+-;X%mkBQIOG~8z=!+qs+|A4_oDG>SPa% zJPA0}YHgv1VhYX+I=@<>6YnbY)fB*a6A&281chP%<^Z7VAE(gXu?j{0L7_dbDHQ&y zLQ#NtIzXYqG_+-MyiVd|Q(9VDot&Kf@7gi92oO{gu9tcYRe~~O1$_-g9QzaCV896g za|nuw1(<^X6AdVP0VNVZBE|sBD+=xQQD`S@`^yS#gYBIT_dCO`;<&4E>d(o^*(+VG zV~bo1>KP(ay2Ep-nleF`HbOOTE0j1DaG;uafH?%!!~)DgfY}c)d!d#nfQbN@a0UY) zJ4OS}NWg(@9idPNY%2gJM<@=*CXBDPva*scUcBhtY*$l*7U(AEk+lp6vRAeXIyFNo z2eBrB;k;pk6D{HF1)NC0*#kJc04Hn|00GFhmlWCp3x;j>wpu8TzZCCS09VI`+9b#=9iS`a#_pzN=#aE=2`B9xN=)f|>^Vi0Q%0MI@L^r}rgy8&k>loJNkYzLIB z0P-cn@lt4$r$QS&6bc#!U^qATvSX_NJkIj+ayozh{E+`M7HQn;OFh(6az)VDc{Vsl zCR*Vf0-RV0N9$S^^{8+(>Iso>HUrKkfY|_B@2=2aVf*JQR9WnpiZ~Xfr>AefrJJep zg4`a#iG>blE(Fn(5J4xW0S>a&QNW3ZdJc`Z!m+s4Set7_0Zzor4b>CM>hYFvpq#$} z&gTrr4K`GvFYx}4@s4LS%+rc??AY;Glf|P-uB4>oEvX)d(t1UXpwsUo?o5?&rxDlM zueuiCMEcZM55w68Fd^PjJ;UKztR8o%9smjipwC=!&U=cZSfB zg8&KOaxOa_tkcrc4uL_#MSt}&%{SkC^AIMbxsJM*p;FL4*2|PWS-KVg#i;55oc*ua z)Dz)jb*(VFz#MF+o-bHE5>DU{h1Nnnp90WoJf8_y9Cow3yuAE%>(+JAGO3rn5P#g& zb!A7~tExcI-{)J4K}%qspi$2sG_Ezq>RRFUftl4K)48giAXblrqpD{O;CwPrA;12B zzFZ+gjbk+tXS2k_#8J%R*s)`s8pNOC;^Mh_WUulYf=(bV9Gz?n%&Kd#diF{6s5Q@S zt!v4^T&ErnsUA0*dIDHIgRSaWH9(=|{c!$lWV2F-;*i4gv!tY?#j+;qWUnA65ZtcE zdQVxFu(;QeNt(bs)~22)wdT>NX9ox75mwg<@v^xVr}ZGMYpLpiTdfA56;RJo01Czw zq^!{KbbtBsdoaWQ7A)?q9`p}lSEb6h#T6O9fE!D&GD^Htx7>=bV)Tn3O5Swdp zaOT*v1aKDo9?+LL7NpfomY<(rFmK*GTfwLTI(+yrul758 zLk4C`S_hb5FI(2yXs4dKz^qZvGPu?v!1)-EzTU0qvPM)`SXdqq5YV#$pxD^hXEcjr zjxBMZP)t22EPxKmnkPy#ou~`UBW>#0;wj~B-g zUtR#rw-r5B8S4P8UAwkV13+P6VLfnAxn9ew+~M;z>6>&qq+t0=#!VUZ2a=4Cv;~n-#vkzW=2KWXWQFetumL$@6ss#8(a=`@=JA z_0Dd9**U6y&9lX;;W`fo=0H_FgKcTu;#&Q!f%#*oXYTWeTgYA&CHeuvY@*=Zci(+d zo5d`E9)9@Y2T%v;lIFE`HBQi;F}7l`F7C*hCs>6u-0E5l0<)`CJ?fNVsf#sh&4X(# z!@1d)b-Ns70hE=MmG129{7^kW64Jk+lKxunE2n&2>+B|BS$N;Zs*zI(R!*>|4Ng7v z$jPYcTA#>@*;j=FCcW~LU3DJdyuz{0uS9&K4x{~R?ySX*3Lt}YXF(jQ<( z$W*SX2KG0=3G%2Pck0cx2HL@aau(o!CwDo#2Gr|V@67Pi&p zWxnilAxcmvGFlLzYygzchgppmz${>7KwcwN;|Dm)I3NSge1?Od{3(Kd%9%E~G_CNW zS$ur_N;%bNFj?&s7Z*3GHCuF>YkXxi?Q0Y5o^GJeJxrEBypEy3{D(+)a6Mb_2y6Ju_KjR+wd= zxD_Q7;88;ULk;xlV5u0`GNf_e{#Mm+h5Y9iD(SsG`E)9(QqN1zO$F$@kt0VwBWLsV zZ+Vc!et|T1@OEr*F;<)CTzD~UnRK1jdS0UyLvv`!pgda8KcD{Ml0$#)n??WqTq;d} z_6kkwb(LnjW>b7}sWnv;{(1#%^C_nk=0U?hM;=dL^qCEudrq(z%VVyJE>UKt?f&J z%h5(U@RosgjxkW^=oPKO^~h2|5ub;Bt;wPfRK154x)!5QR4P0LesKN1JG~w~4;6lm#ZZoCz7vM9caMlmLR}z98t+ahTGaZ+To&$9Cq- znNt{Z7diG@KP15i)~{bbuDZIqRVv~gWH*ihOah=lHP>Td2LNZE6;2l5WP~YHaJuPb z3U;}FL<)+UisEv#piSNakOT#|3Diu2Rt*xg6p$7G(udCrT8?9`Uv9a23JMBn>C&Zd z@|ZVn+}OOGuT!T^{TZHqd-3AMXik4E-9S}SYE{m4=~CCC8^X!hs!;y%TTd4_j%9r# zX#abHLPiPNh`6(Um_R&&Y6c4wl!BJ@6ZBDEL9_Y@I`G$)ZNrnXhp(poR*t!O4+JWX zMGs7vFu}E`sHj}3$lQ`8*IW$#+CeLvti7-ZxYcgh4lA7W5QU18o4LkaEGQ9Gbm$mC zK~Pd4Agu+YPh17!kySg(&L;nV9jLjSiCs$WjZny_x)7zNbmC2cKyM&|$WR5v-tMd8t=d*Hp3>Ywg z7v$UQMqein4-fw3gYJ_jPxe6}nJ%ksv#!e{I?T|yPrTpf`|rO`A2)8?tK4VV_cp%^ z+R5A7o4)1y=-apN{oT5C z<4upxxVyW1;~R^~%geLe`Y1suZRvXIPglsS%9}9xszj`tn;YN2`waJu`*K*I0VMdcX6|JCkE#V)mq_rsnbG6jfF7rz;fAkCvG6KeHToooU{)9Lo>& zd~U0>w3N7Q{*39q5$ed3z+Sz2 zv7#P_@s6!$@$C-&;DZm|4hacalaP=Qm6Vk9?WIeXt{}kYppYwqtCX?v>x_(yoS%OB z=?Wi%*cKHU8oGwhW1*UXA-uw3y>_0gBb?)5x zdDx3Q=z#+VdJP*kYy=y>=J)Ww-}5nitUQO$eT>`UHo5KFnY!B?7F^<9{&N26i4OQgSB*)y^YEjJS`tBD3*p hevkhrVcfBR`%i6UAD@X)L!STu002ovPDHLkV1ffo3jhEB diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 4e45638f7487c018e8d685f6d02da220e7cf9da5..6dff60806c73115a2fbbed366984ebc25fd1e3d4 100644 GIT binary patch delta 3440 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 O571K6RjpRGj{F}$A5#nf literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png index 5fe585e364764d329cc68ac71c697518b9fc2cde..1f9c1cef172f9708aa8a7070adc7ebe756c09761 100644 GIT binary patch delta 1688 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 bh^_&n6H8&3QrDm@%?Y?4_BvGRLZJTz(`z73 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index 00668b42b0705b0e09e2f72c49ab7823da765223..989a7c1331fcc3d90ceaa292268ce4b410a6b8d7 100644 GIT binary patch literal 3894 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 Eg0x$TlK=n! delta 2679 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 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 23394228c45f3bca760e66d07079c43388ecadfb..2670ecb019dcda75a6da196c774993cad9009cba 100644 GIT binary patch literal 8641 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 TqYRl&00000NkvXXu0mjfHe@bs literal 3669 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 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..c775d1c80ff790cb613ea7f5784f9e0b5e19966f GIT binary patch literal 20448 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 Q#(yCreX|F(x~}p62Ub7~XaE2J literal 7432 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 WK(s1n^PNDz=aRYI1%jD-(tiLXNYpz3 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index c998e2065f3b5aff9142fdad78be4a8b1d24143f..23ab41683d48d53c6866b289c68cc86a54add7b1 100644 GIT binary patch literal 10074 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 literal 6852 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 P`hR6!?taL6S6uqPS0OHD literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png index 451e815e3db06d9e9753996a7f7ee49332e0a699..40e35c0a93e056b670449a9cba5271630b72b367 100644 GIT binary patch literal 6381 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 literal 13244 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 E04LC@od5s; diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index 663d2450fd8fd7ea5cccf28a0d2c73d333384681..c974019287045fba05c8dac6948be8249301f0f6 100644 GIT binary patch literal 16945 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 IM6N<$g7J*#v;Y7A literal 11522 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 literal 9521 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 j$^V1u(g4d8OLO1N;8~0okrO diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..0282220d304c2b716ff629a1e46d0322b5b43819 GIT binary patch literal 50987 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 E0I{N6?EnA( literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png index 3f076e2d060f28d5e9444a80e74991e5c0996e1c..055c6ed82310ac9cc29e15034603f9f457c50bda 100644 GIT binary patch literal 10878 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 b@-zS0Mb}>Nf0pa-2lBqBtDnm{r-UW|J-Hop diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index 8b5d5d8ddebee82f7a3ccad2e505259f873ba4d6..471bfebef458175c326e4738db1de39cd16263e7 100644 GIT binary patch literal 25067 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 Eg3ANH-~a#s From 1941086b4aa8e2d06c7f1079144bb4de51ed0db7 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Fri, 21 Aug 2020 09:53:01 +0530 Subject: [PATCH 07/46] Added debug font --- .gitignore | 6 +- app/src/debug/res/font/bold.ttf | Bin 0 -> 92096 bytes app/src/debug/res/font/medium.ttf | Bin 0 -> 92312 bytes app/src/debug/res/font/regular.ttf | Bin 0 -> 109128 bytes app/src/debug/res/font/sans.xml | 13 +++++ app/src/debug/res/values/styles.xml | 57 +++++++++++++++++++ app/src/main/res/layout/fragment_library.xml | 7 ++- 7 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 app/src/debug/res/font/bold.ttf create mode 100644 app/src/debug/res/font/medium.ttf create mode 100644 app/src/debug/res/font/regular.ttf create mode 100644 app/src/debug/res/font/sans.xml create mode 100644 app/src/debug/res/values/styles.xml diff --git a/.gitignore b/.gitignore index 37f05b7f..6a32941f 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/src/debug/res/font/bold.ttf b/app/src/debug/res/font/bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..96619df92e347c5852b6c50d71c362e4404c4c3c GIT binary patch literal 92096 zcmcG%33wdEnKxe5b4xR$IW&jn?3tcJ(r9$dNSe`MX)If^Z26FE$(C$mOSZ7_*cc-l zYz~9LfQ>jpNWvzBBy51dLY9>wOB`~Mgb=bJ2_bCACgdQ=?y`Jg!;)i(gJ=G~s_v0S z!esaPp6@TIyZWeltLnY#t+(E45lRTL;iM+wz`*Fb6OX4qLg?NH@zl3!W&ePAxn(t> z)oXFTX4UY9OWyZ;*pyYT*_gy??0VN+8o-yrTFgg%1≤gS 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 F>3?g0VA}uy literal 0 HcmV?d00001 diff --git a/app/src/debug/res/font/regular.ttf b/app/src/debug/res/font/regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e2c69c3fb94651237de80e67a69d458c55b45649 GIT binary patch literal 109128 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 B-RJ-S literal 0 HcmV?d00001 diff --git a/app/src/debug/res/font/sans.xml b/app/src/debug/res/font/sans.xml new file mode 100644 index 00000000..f824169f --- /dev/null +++ b/app/src/debug/res/font/sans.xml @@ -0,0 +1,13 @@ + + + + + + \ 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 00000000..8409642c --- /dev/null +++ b/app/src/debug/res/values/styles.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 5d61e740..6f2b92c2 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -47,11 +47,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" - android:layout_marginBottom="72dp" + android:layout_marginBottom="16dp" android:layout_marginEnd="16dp" android:id="@+id/addPlaylist" android:src="@drawable/ic_playlist_add" - app:useCompatPadding="true" /> + app:useCompatPadding="true" + app:layout_anchor="@id/fragment_container" + app:layout_anchorGravity="end|bottom" + android:contentDescription="@string/add_playlist_title" /> Date: Fri, 21 Aug 2020 10:31:53 +0530 Subject: [PATCH 08/46] Code refactor --- app/release/output-metadata.json | 20 ----------------- app/src/debug/res/values/styles.xml | 22 +++++++++++++++++++ .../base/AbsSlidingMusicPanelActivity.kt | 7 ------ .../monkey/retromusic/extensions/ColorExt.kt | 10 +++++++++ .../fragments/library/LibraryFragment.kt | 8 +++++-- .../res/layout/fragment_album_details.xml | 7 +++--- .../res/layout/fragment_artist_details.xml | 5 ++--- app/src/main/res/layout/fragment_library.xml | 11 +++++----- .../fragment_main_activity_recycler_view.xml | 1 + app/src/main/res/layout/item_artist.xml | 10 ++++----- app/src/main/res/layout/item_image.xml | 7 +++--- .../res/layout/sliding_music_panel_layout.xml | 7 ------ app/src/main/res/values/styles.xml | 1 + 13 files changed, 58 insertions(+), 58 deletions(-) delete mode 100644 app/release/output-metadata.json diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json deleted file mode 100644 index b45c7e16..00000000 --- a/app/release/output-metadata.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": 1, - "artifactType": { - "type": "APK", - "kind": "Directory" - }, - "applicationId": "code.name.monkey.retromusic", - "variantName": "release", - "elements": [ - { - "type": "SINGLE", - "filters": [], - "properties": [], - "versionCode": 10438, - "versionName": "3.5.650_0812", - "enabled": true, - "outputFile": "app-release.apk" - } - ] -} \ No newline at end of file diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml index 8409642c..7f4fe30c 100644 --- a/app/src/debug/res/values/styles.xml +++ b/app/src/debug/res/values/styles.xml @@ -10,6 +10,11 @@ @font/sans + + @@ -54,4 +59,21 @@ @font/sans + + + + + + \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt index d0dbdb34..2d6283cf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt @@ -15,7 +15,6 @@ import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.R import code.name.monkey.retromusic.RetroBottomSheetBehavior import code.name.monkey.retromusic.extensions.hide -import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.whichFragment import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.MiniPlayerFragment @@ -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 -> { @@ -81,9 +77,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() { 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() diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt index cee067c2..f4e02de3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt @@ -33,6 +33,7 @@ import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import com.google.android.material.button.MaterialButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout @@ -107,6 +108,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( diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index 6a4b9f0d..d7d8cad3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -10,6 +10,7 @@ import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackg import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.dialogs.CreateRetroPlaylist +import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import kotlinx.android.synthetic.main.fragment_library.* @@ -29,8 +30,11 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { navOptions ) } - addPlaylist.setOnClickListener { - CreateRetroPlaylist().show(childFragmentManager, "ShowCreatePlaylistDialog") + addPlaylist.apply { + accentColor() + setOnClickListener { + CreateRetroPlaylist().show(childFragmentManager, "ShowCreatePlaylistDialog") + } } setupNavigationController() } diff --git a/app/src/main/res/layout/fragment_album_details.xml b/app/src/main/res/layout/fragment_album_details.xml index b81d1c65..fdf856db 100644 --- a/app/src/main/res/layout/fragment_album_details.xml +++ b/app/src/main/res/layout/fragment_album_details.xml @@ -69,7 +69,7 @@ android:layout_width="52dp" android:layout_height="52dp" android:layout_marginStart="16dp" - android:layout_marginTop="16dp" + android:layout_marginTop="24dp" android:scaleType="centerCrop" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/albumCoverContainer" @@ -83,7 +83,7 @@ android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:maxLines="3" - android:textAppearance="@style/TextViewHeadline5" + android:textAppearance="@style/TextViewHeadline4.Compress" android:textColor="?android:attr/textColorPrimary" android:textStyle="bold" app:layout_constrainedWidth="true" @@ -98,10 +98,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:layout_marginTop="4dp" android:layout_marginEnd="16dp" android:singleLine="true" - android:textAppearance="@style/TextViewSubtitle2" + android:textAppearance="@style/TextViewHeadline6" android:textColor="?android:attr/textColorSecondary" app:layout_constrainedWidth="true" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/fragment_artist_details.xml b/app/src/main/res/layout/fragment_artist_details.xml index 817c0003..ff56c67f 100644 --- a/app/src/main/res/layout/fragment_artist_details.xml +++ b/app/src/main/res/layout/fragment_artist_details.xml @@ -71,7 +71,7 @@ android:layout_marginTop="24dp" android:layout_marginEnd="16dp" android:maxLines="2" - android:textAppearance="@style/TextViewHeadline5" + android:textAppearance="@style/TextViewHeadline4.Compress" android:textColor="?android:attr/textColorPrimary" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" @@ -85,9 +85,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:layout_marginTop="4dp" android:layout_marginEnd="16dp" - android:textAppearance="@style/TextViewSubtitle2" + android:textAppearance="@style/TextViewHeadline6" android:textColor="?android:attr/textColorSecondary" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 6f2b92c2..36953b29 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -44,17 +44,16 @@ + app:layout_dodgeInsetEdges="all" + app:useCompatPadding="true" /> + tools:text="@tools:sample/full_names" /> \ No newline at end of file diff --git a/app/src/main/res/layout/sliding_music_panel_layout.xml b/app/src/main/res/layout/sliding_music_panel_layout.xml index b5348fae..95f8457d 100644 --- a/app/src/main/res/layout/sliding_music_panel_layout.xml +++ b/app/src/main/res/layout/sliding_music_panel_layout.xml @@ -11,13 +11,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - 16sp + bold - - + + + + + + + + From bbfec6f489b689fbf55ad005c3c326051ffaa55b Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Mon, 24 Aug 2020 21:57:08 +0530 Subject: [PATCH 21/46] old Changes --- .../monkey/retromusic/activities/MainActivity.kt | 6 +----- .../adapter/song/OrderablePlaylistSongAdapter.kt | 10 +++++----- .../retromusic/dialogs/AddToRetroPlaylist.kt | 4 ++-- .../dialogs/RemoveSongFromPlaylistDialog.kt | 6 ++---- .../fragments/albums/AlbumsFragment.kt | 5 ++--- .../fragments/library/LibraryFragment.kt | 14 ++++---------- .../player/classic/ClassicPlayerFragment.kt | 15 +++++---------- .../player/gradient/GradientPlayerFragment.kt | 16 +++++----------- .../playlists/PlaylistDetailsFragment.kt | 2 +- .../fragment_main_activity_recycler_view.xml | 1 - 10 files changed, 27 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 16491acc..5567745d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -5,13 +5,11 @@ import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.os.Bundle import android.provider.MediaStore -import android.util.Log import android.view.View import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.extensions.findNavController -import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue import code.name.monkey.retromusic.helper.MusicPlayerRemote.playFromUri @@ -36,7 +34,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis } private val repository by inject() - private val libraryViewModel by inject() private var blockRequestPermissions = false @@ -53,7 +50,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis setTaskDescriptionColorAuto() hideStatusBar() appLaunched(this) - addMusicServiceEventListener(libraryViewModel) updateTabs() } @@ -167,7 +163,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/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt index 77aa8eb6..7013d44f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt @@ -5,7 +5,7 @@ import android.view.View import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R.menu -import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog +import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.PlaylistSong @@ -17,7 +17,7 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags class OrderablePlaylistSongAdapter( - private val playlistId: Int, + private val playlist: PlaylistEntity, activity: FragmentActivity, dataSet: ArrayList, itemLayoutRes: Int, @@ -56,8 +56,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.to(playlist.playListId)) + .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") return } } @@ -120,7 +120,7 @@ class OrderablePlaylistSongAdapter( override fun onSongMenuItemClick(item: MenuItem): Boolean { when (item.itemId) { R.id.action_remove_from_playlist -> { - RemoveSongFromPlaylistDialog.create( song.toSongEntity(playlistId)) + RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId)) .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") return true } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index dca9ebb1..bb0bfa7b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -3,7 +3,6 @@ package code.name.monkey.retromusic.dialogs import android.app.Dialog import android.os.Bundle import androidx.core.os.bundleOf -import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_PLAYLISTS import code.name.monkey.retromusic.EXTRA_SONG @@ -17,12 +16,13 @@ import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository +import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel -class AddToRetroPlaylist : DialogFragment() { +class AddToRetroPlaylist : BottomSheetDialogFragment() { private val repository by inject() private val libraryViewModel by sharedViewModel() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt index 7193a5b3..6d76e8ad 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt @@ -13,6 +13,7 @@ import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.repository.Repository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -66,11 +67,8 @@ class RemoveSongFromPlaylistDialog : DialogFragment() { .setPositiveButton(R.string.remove_action) { _, _ -> lifecycleScope.launch(Dispatchers.IO) { repository.removeSongFromPlaylist(songs) + libraryViewModel.forceReload(Playlists) } - /* PlaylistsUtil.removeFromPlaylist( - requireContext(), - songs as MutableList - )*/ } .setNegativeButton(android.R.string.cancel, null) .create() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index 47c060da..d9f383ec 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -4,12 +4,12 @@ import android.os.Bundle import android.view.View import androidx.core.os.bundleOf import androidx.lifecycle.Observer -import androidx.navigation.findNavController import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.recyclerview.widget.GridLayoutManager import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.album.AlbumAdapter +import code.name.monkey.retromusic.extensions.findActivityNavController import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment import code.name.monkey.retromusic.util.PreferenceUtil @@ -95,8 +95,7 @@ class AlbumsFragment : } override fun onAlbumClick(albumId: Int, view: View) { - val controller = requireActivity().findNavController(R.id.fragment_container) - controller.navigate( + findActivityNavController(R.id.fragment_container).navigate( R.id.albumDetailsFragment, bundleOf(EXTRA_ALBUM_ID to albumId), null, diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index d7d8cad3..b47e3e50 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -20,6 +20,7 @@ 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 @@ -43,17 +44,10 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { val navController = findNavController(R.id.fragment_container) NavigationUI.setupWithNavController(mainActivity.getBottomNavigationView(), navController) navController.addOnDestinationChangedListener { _, destination, _ -> - if (destination.id in arrayOf( - R.id.action_album, - R.id.action_artist, - R.id.action_home, - R.id.action_song, - R.id.action_genre - ) - ) { - addPlaylist.hide() - } else { + if (destination.id == R.id.action_playlist) { addPlaylist.show() + } else { + addPlaylist.hide() } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt index 323c89b4..c4748128 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt @@ -20,7 +20,6 @@ import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.RetroBottomSheetBehavior -import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.show @@ -69,9 +68,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { - (requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior() - .setAllowDragging(false) - + mainActivity.getBottomSheetBehavior().setAllowDragging(false) playerQueueSheet.setContentPadding( playerQueueSheet.contentPaddingLeft, (slideOffset * status_bar.height).toInt(), @@ -83,18 +80,17 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player } override fun onStateChanged(bottomSheet: View, newState: Int) { - val activity = requireActivity() as AbsSlidingMusicPanelActivity when (newState) { BottomSheetBehavior.STATE_EXPANDED, BottomSheetBehavior.STATE_DRAGGING -> { - activity.getBottomSheetBehavior().setAllowDragging(false) + mainActivity.getBottomSheetBehavior().setAllowDragging(false) } BottomSheetBehavior.STATE_COLLAPSED -> { resetToCurrentPosition() - activity.getBottomSheetBehavior().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().setAllowDragging(true) } else -> { - activity.getBottomSheetBehavior().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().setAllowDragging(true) } } } @@ -132,8 +128,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player playerQueueSheet.background = shapeDrawable playerQueueSheet.setOnTouchListener { _, _ -> - (requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior() - .setAllowDragging(false) + mainActivity.getBottomSheetBehavior().setAllowDragging(false) getQueuePanel().setAllowDragging(true) return@setOnTouchListener false } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt index f51b1c75..41d52255 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt @@ -21,7 +21,6 @@ import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.RetroBottomSheetBehavior -import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.ripAlpha @@ -67,9 +66,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { - (requireActivity() as AbsSlidingMusicPanelActivity).getBottomSheetBehavior() - .setAllowDragging(false) - + mainActivity.getBottomSheetBehavior().setAllowDragging(false) playerQueueSheet.setPadding( playerQueueSheet.paddingLeft, (slideOffset * status_bar.height).toInt(), @@ -79,18 +76,17 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play } override fun onStateChanged(bottomSheet: View, newState: Int) { - val activity = requireActivity() as AbsSlidingMusicPanelActivity when (newState) { BottomSheetBehavior.STATE_EXPANDED, BottomSheetBehavior.STATE_DRAGGING -> { - activity.getBottomSheetBehavior().setAllowDragging(false) + mainActivity.getBottomSheetBehavior().setAllowDragging(false) } BottomSheetBehavior.STATE_COLLAPSED -> { resetToCurrentPosition() - activity.getBottomSheetBehavior().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().setAllowDragging(true) } else -> { - activity.getBottomSheetBehavior().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().setAllowDragging(true) } } } @@ -139,8 +135,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 +154,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play recyclerViewDragDropManager?.cancelDrag() super.onPause() progressViewUpdateHelper.stop() - } override fun playerToolbar(): Toolbar? { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index beaedd5a..8b5ca227 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -64,7 +64,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli val animator = RefactoredDefaultItemAnimator() adapter = OrderablePlaylistSongAdapter( - playlist.playlistEntity.playListId, + playlist.playlistEntity, requireActivity(), ArrayList(), R.layout.item_list, diff --git a/app/src/main/res/layout/fragment_main_activity_recycler_view.xml b/app/src/main/res/layout/fragment_main_activity_recycler_view.xml index 9a925d89..d546767b 100644 --- a/app/src/main/res/layout/fragment_main_activity_recycler_view.xml +++ b/app/src/main/res/layout/fragment_main_activity_recycler_view.xml @@ -11,7 +11,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" - android:layoutAnimation="@anim/layout_animation_fall_down" android:overScrollMode="never" android:scrollbars="none" app:layout_dodgeInsetEdges="bottom" From c379342f6a7a78115e8af88d126e5f72bf9c5101 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Mon, 24 Aug 2020 22:00:53 +0530 Subject: [PATCH 22/46] Update SongExtension.kt --- .../java/code/name/monkey/retromusic/db/SongExtension.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt index f1df038d..617e3a71 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt @@ -8,6 +8,12 @@ fun List.toSongs(): List { } } +fun List.toSongs(playlistId: Int): List { + return map { + it.toSongEntity(playlistId) + } +} + fun SongEntity.toSong(): Song { return Song( id, From 2854b33d56e73599fed9f254b2a1176274af72b1 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 30 Aug 2020 00:23:15 +0530 Subject: [PATCH 23/46] Refactor code Moving business logic from UI to ViewModel class --- .../retromusic/activities/MainActivity.kt | 109 +++++++++--------- .../base/AbsSlidingMusicPanelActivity.kt | 3 +- .../retromusic/dialogs/AddToRetroPlaylist.kt | 5 +- .../retromusic/dialogs/DeleteRetroPlaylist.kt | 15 +-- .../dialogs/RemoveSongFromPlaylistDialog.kt | 13 +-- .../dialogs/RenameRetroPlaylistDialog.kt | 13 +-- .../monkey/retromusic/extensions/ColorExt.kt | 12 ++ .../retromusic/fragments/LibraryViewModel.kt | 34 ++++++ .../fragments/MiniPlayerFragment.kt | 12 +- .../fragments/base/AbsPlayerFragment.kt | 61 +++++----- .../retromusic/fragments/home/HomeFragment.kt | 22 +--- .../player/gradient/GradientPlayerFragment.kt | 41 +------ .../repository/PlaylistSongsLoader.kt | 5 +- .../res/layout/fragment_gradient_player.xml | 8 +- 14 files changed, 155 insertions(+), 198 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 2f0df045..c772c320 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -10,21 +10,15 @@ import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.extensions.findNavController -import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue -import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue -import code.name.monkey.retromusic.helper.MusicPlayerRemote.playFromUri -import code.name.monkey.retromusic.helper.MusicPlayerRemote.shuffleMode +import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.PlaylistSongsLoader.getPlaylistSongList -import code.name.monkey.retromusic.repository.Repository +import code.name.monkey.retromusic.repository.PlaylistSongsLoader import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.AppRater.appLaunched import code.name.monkey.retromusic.util.PreferenceUtil -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject -import java.util.* class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener { companion object { @@ -33,8 +27,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis const val APP_UPDATE_REQUEST_CODE = 9002 } - private val repository by inject() - private var blockRequestPermissions = false override fun createContentView(): View { @@ -95,61 +87,68 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis override fun onServiceConnected() { super.onServiceConnected() - handlePlaybackIntent(intent) - } - - private fun handlePlaybackIntent(intent: Intent?) { if (intent == null) { return } - val uri = intent.data - val mimeType = intent.type - var handled = false - if (intent.action != null && (intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) - ) { - val songs: List = - getSongs(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) + handlePlaybackIntent(intent) + } + + private fun handlePlaybackIntent(intent: Intent) { + lifecycleScope.launch(IO) { + 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(intent.extras!!) + if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) { + MusicPlayerRemote.openAndShuffleQueue(songs, true) + } else { + MusicPlayerRemote.openQueue(songs, 0, true) + } handled = true } - } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) { - val id = parseIdFromIntent(intent, "albumId", "album").toInt() - if (id >= 0) { - lifecycleScope.launch(Dispatchers.Main) { + if (uri != null && uri.toString().isNotEmpty()) { + MusicPlayerRemote.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) - openQueue(repository.albumById(id).songs!!, position, true) + 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 = parseIdFromIntent(intent, "albumId", "album").toInt() + if (id >= 0) { + val position = intent.getIntExtra("position", 0) + MusicPlayerRemote.openQueue( + libraryViewModel.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) { + val position = intent.getIntExtra("position", 0) + MusicPlayerRemote.openQueue( + libraryViewModel.artistById(id).songs, + position, + true + ) handled = true } } - } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { - val id = parseIdFromIntent(intent, "artistId", "artist").toInt() - if (id >= 0) { - lifecycleScope.launch { - val position = intent.getIntExtra("position", 0) - openQueue(repository.artistById(id).songs, position, true) - handled = true - } + if (handled) { + setIntent(Intent()) } } - if (handled) { - setIntent(Intent()) - } + } private fun parseIdFromIntent( diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt index 57c27f92..d81485a0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt @@ -33,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 @@ -79,6 +79,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { libraryViewModel.paletteColorLiveData.observe(this, Observer { this.paletteColor = it + miniPlayerFragment?.updateProgressBar(it) onPaletteColorChanged() }) } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index a4275ba1..e00ec73b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -15,15 +15,12 @@ import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.RealRepository import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class AddToRetroPlaylist : BottomSheetDialogFragment() { - private val repository by inject() private val libraryViewModel by sharedViewModel() companion object { @@ -58,7 +55,7 @@ class AddToRetroPlaylist : BottomSheetDialogFragment() { } else { lifecycleScope.launch(Dispatchers.IO) { val songEntities = songs.toSongEntity(playlistEntities[which - 1]) - repository.insertSongs(songEntities) + libraryViewModel.insertSongs(songEntities) libraryViewModel.forceReload(Playlists) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt index 3b024044..1888d287 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt @@ -5,7 +5,6 @@ import android.os.Bundle import androidx.core.os.bundleOf import androidx.core.text.HtmlCompat import androidx.fragment.app.DialogFragment -import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_PLAYLIST import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity @@ -14,14 +13,10 @@ 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 -import code.name.monkey.retromusic.repository.Repository -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class DeleteRetroPlaylist : DialogFragment() { - private val repository by inject() + private val libraryViewModel by sharedViewModel() companion object { @@ -63,11 +58,9 @@ class DeleteRetroPlaylist : DialogFragment() { .setMessage(message) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.action_delete) { _, _ -> - lifecycleScope.launch(Dispatchers.IO) { - repository.deleteSongsFromPlaylist(playlists) - repository.deleteRoomPlaylist(playlists) - libraryViewModel.forceReload(ReloadType.Playlists) - } + libraryViewModel.deleteSongsFromPlaylist(playlists) + libraryViewModel.deleteRoomPlaylist(playlists) + libraryViewModel.forceReload(ReloadType.Playlists) } .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt index 9bf9cfdf..b52e9fef 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveSongFromPlaylistDialog.kt @@ -5,7 +5,6 @@ import android.os.Bundle import androidx.core.os.bundleOf import androidx.core.text.HtmlCompat import androidx.fragment.app.DialogFragment -import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.SongEntity @@ -14,14 +13,9 @@ import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.Playlists -import code.name.monkey.retromusic.repository.Repository -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class RemoveSongFromPlaylistDialog : DialogFragment() { - private val repository by inject() private val libraryViewModel by sharedViewModel() companion object { @@ -65,11 +59,8 @@ class RemoveSongFromPlaylistDialog : DialogFragment() { return materialDialog(pair.first) .setMessage(pair.second) .setPositiveButton(R.string.remove_action) { _, _ -> - lifecycleScope.launch(Dispatchers.IO) { - //repository.removeSongFromPlaylist(songs) - repository.deleteSongsInPlaylist(songs) - libraryViewModel.forceReload(Playlists) - } + libraryViewModel.deleteSongsInPlaylist(songs) + libraryViewModel.forceReload(Playlists) } .setNegativeButton(android.R.string.cancel, null) .create() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt index a12da522..9c2601ad 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt @@ -5,7 +5,6 @@ import android.os.Bundle import android.view.LayoutInflater import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment -import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity @@ -15,16 +14,12 @@ 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 -import code.name.monkey.retromusic.repository.Repository import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class RenameRetroPlaylistDialog : DialogFragment() { - private val repository by inject() + private val libraryViewModel by sharedViewModel() companion object { @@ -50,10 +45,8 @@ class RenameRetroPlaylistDialog : DialogFragment() { .setPositiveButton(R.string.action_rename) { _, _ -> val name = inputEditText.text.toString() if (name.isNotEmpty()) { - lifecycleScope.launch(Dispatchers.IO) { - repository.renameRoomPlaylist(playlistEntity.playListId, name) - libraryViewModel.forceReload(ReloadType.Playlists) - } + libraryViewModel.renameRoomPlaylist(playlistEntity.playListId, name) + libraryViewModel.forceReload(ReloadType.Playlists) } else { nameContainer.error = "Playlist name should'nt be empty" } diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt index 2059d929..fc08d6e7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt @@ -35,6 +35,7 @@ import code.name.monkey.retromusic.R import com.google.android.material.button.MaterialButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton +import com.google.android.material.progressindicator.ProgressIndicator import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout @@ -145,6 +146,17 @@ 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() { } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index cefe5c70..e531b510 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -4,7 +4,9 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.db.toPlayCount import code.name.monkey.retromusic.fragments.ReloadType.* import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -151,6 +153,38 @@ class LibraryViewModel( println("onShuffleModeChanged") } + fun shuffleSongs() = viewModelScope.launch(IO) { + val songs = repository.allSongs() + MusicPlayerRemote.openAndShuffleQueue( + songs, + true + ) + } + + fun renameRoomPlaylist(playListId: Int, name: String) = viewModelScope.launch(IO) { + repository.renameRoomPlaylist(playListId, name) + } + + fun deleteSongsInPlaylist(songs: List) = viewModelScope.launch(IO) { + repository.deleteSongsInPlaylist(songs) + } + + fun deleteSongsFromPlaylist(playlists: List) = viewModelScope.launch(IO) { + repository.deleteSongsFromPlaylist(playlists) + } + + fun deleteRoomPlaylist(playlists: List) = viewModelScope.launch(IO) { + repository.deleteRoomPlaylist(playlists) + } + + suspend fun albumById(id: Int) = repository.albumById(id) + suspend fun artistById(id: Int) = repository.artistById(id) + suspend fun favoritePlaylist() = repository.favoritePlaylist() + suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song) + suspend fun insertSongs(songs: List) = repository.insertSongs(songs) + suspend fun removeSongFromPlaylist(songEntity: SongEntity) = + repository.removeSongFromPlaylist(songEntity) + } enum class ReloadType { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/MiniPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/MiniPlayerFragment.kt index 9f05dc43..9a16d656 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/MiniPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 code.name.monkey.retromusic.R -import code.name.monkey.retromusic.extensions.show -import code.name.monkey.retromusic.extensions.textColorPrimary -import code.name.monkey.retromusic.extensions.textColorSecondary +import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil -import code.name.monkey.retromusic.util.ViewUtil import kotlinx.android.synthetic.main.fragment_mini_player.* import kotlin.math.abs @@ -67,7 +63,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p private fun setUpMiniPlayer() { setUpPlayPauseButton() - ViewUtil.setProgressDrawable(progressBar, ThemeStore.accentColor(requireContext())) + progressBar.accentColor() } private fun setUpPlayPauseButton() { @@ -129,6 +125,10 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p } } + fun updateProgressBar(paletteColor: Int) { + progressBar.applyColor(paletteColor) + } + class FlingPlayBackController(context: Context) : View.OnTouchListener { private var flingPlayBackController: GestureDetector diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index 975443f7..1aa7dc14 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -25,7 +25,7 @@ import code.name.monkey.retromusic.dialogs.* import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.whichFragment import code.name.monkey.retromusic.fragments.LibraryViewModel -import code.name.monkey.retromusic.fragments.ReloadType.Playlists +import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.PaletteColorHolder @@ -35,13 +35,11 @@ import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.* import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.* -import kotlinx.coroutines.Dispatchers 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.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel import java.io.FileNotFoundException @@ -75,7 +73,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme R.id.action_add_to_playlist -> { lifecycleScope.launch(IO) { val playlists = get().roomPlaylists() - withContext(Dispatchers.Main) { + withContext(Main) { AddToRetroPlaylist.create(playlists, song) .show(childFragmentManager, "ADD_PLAYLIST") } @@ -161,20 +159,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme return false } - protected open fun toggleFavorite(song: Song) { - lifecycleScope.launch(IO) { - val playlist: PlaylistEntity = repository.favoritePlaylist().first() - val songEntity = song.toSongEntity(playlist.playListId) - val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty() - if (isFavorite) { - repository.removeSongFromPlaylist(songEntity) - } else { - repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) - libraryViewModel.forceReload(Playlists) - } - requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED)) - } - } abstract fun playerToolbar(): Toolbar? @@ -196,15 +180,35 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme updateLyrics() } + protected open fun toggleFavorite(song: Song) { + lifecycleScope.launch(IO) { + val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist().first() + 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)) + } + } + fun updateIsFavorite() { lifecycleScope.launch(IO) { - val playlist: PlaylistEntity = repository.favoritePlaylist().first() + val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist().first() val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId) - val isFavorite = repository.isFavoriteSong(song).isNotEmpty() - withContext(Dispatchers.Main) { - val icon = if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border + val isFavorite = libraryViewModel.isFavoriteSong(song).isNotEmpty() + withContext(Main) { + val icon = + if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border val drawable = - RetroUtil.getTintedVectorDrawable(requireContext(), icon, toolbarIconColor()) + RetroUtil.getTintedVectorDrawable( + requireContext(), + icon, + toolbarIconColor() + ) if (playerToolbar() != null) { playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite) ?.setIcon(drawable)?.title = @@ -241,17 +245,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme open fun setLyrics(l: Lyrics?) { } - private val repository by inject() - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - lifecycleScope.launch(IO) { - if (repository.checkPlaylistExists(getString(R.string.favorites)).isEmpty()) { - repository.createPlaylist(PlaylistEntity(getString(R.string.favorites))) - } - } - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if (PreferenceUtil.isFullScreenMode && diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt index 47d0918f..20932004 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt @@ -16,11 +16,9 @@ package code.name.monkey.retromusic.fragments.home import android.app.ActivityOptions import android.os.Bundle -import android.util.DisplayMetrics import android.view.View import androidx.core.os.bundleOf import androidx.lifecycle.Observer -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.retromusic.HISTORY_PLAYLIST import code.name.monkey.retromusic.LAST_ADDED_PLAYLIST @@ -32,32 +30,19 @@ import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest import code.name.monkey.retromusic.glide.UserProfileGlideRequest -import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.repository.Repository import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.abs_playlists.* import kotlinx.android.synthetic.main.fragment_banner_home.* import kotlinx.android.synthetic.main.home_content.* -import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class HomeFragment : AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) { - private val repository by inject() 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) @@ -85,12 +70,7 @@ class HomeFragment : } actionShuffle.setOnClickListener { - lifecycleScope.launch { - MusicPlayerRemote.openAndShuffleQueue( - repository.allSongs(), - true - ) - } + libraryViewModel.shuffleSongs() } history.setOnClickListener { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt index 41d52255..0eacbb9a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 @@ -18,7 +17,6 @@ import androidx.core.view.ViewCompat import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import code.name.monkey.appthemehelper.util.ColorUtil -import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.RetroBottomSheetBehavior import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter @@ -61,7 +59,6 @@ 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() { @@ -218,9 +215,8 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play override fun toggleFavorite(song: Song) { super.toggleFavorite(song) - MusicUtil.toggleFavorite(requireContext(), song) if (song.id == MusicPlayerRemote.currentSong.id) { - updateFavorite() + updateIsFavorite() } } @@ -268,6 +264,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play override fun onQueueChanged() { super.onQueueChanged() updateLabel() + playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue) } private fun updateSong() { @@ -366,7 +363,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play } else { val title = MusicPlayerRemote.playingQueue[MusicPlayerRemote.position + 1].title nextSong.apply { - text = "Next: $title" + text = title show() } } @@ -472,36 +469,4 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) } - - @SuppressLint("StaticFieldLeak") - private fun updateFavorite() { - if (updateIsFavoriteTask != null) { - updateIsFavoriteTask?.cancel(false) - } - updateIsFavoriteTask = - object : AsyncTask() { - 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/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt index 383785b8..96f86d37 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt @@ -23,7 +23,6 @@ import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.Song -import java.util.* /** * Created by hemanths on 16/08/17. @@ -43,8 +42,8 @@ object PlaylistSongsLoader { } @JvmStatic - fun getPlaylistSongList(context: Context, playlistId: Int): ArrayList { - val songs = arrayListOf() + fun getPlaylistSongList(context: Context, playlistId: Int): List { + val songs = mutableListOf() val cursor = makePlaylistSongCursor( context, diff --git a/app/src/main/res/layout/fragment_gradient_player.xml b/app/src/main/res/layout/fragment_gradient_player.xml index 2aa519ef..6c6a3bfc 100644 --- a/app/src/main/res/layout/fragment_gradient_player.xml +++ b/app/src/main/res/layout/fragment_gradient_player.xml @@ -12,7 +12,7 @@ android:layout_height="match_parent" android:paddingBottom="48dp"> - + app:layout_constraintWidth_default="spread" + tools:background="@color/md_red_500"> + app:layout_constraintTop_toTopOf="@id/queueIcon" /> Date: Sun, 30 Aug 2020 22:23:09 +0530 Subject: [PATCH 24/46] Remove MainActivityFragmentCallbacks --- .../code/name/monkey/retromusic/db/RetroDatabase.kt | 2 +- .../retromusic/fragments/albums/AlbumsFragment.kt | 3 +-- .../retromusic/fragments/artists/ArtistsFragment.kt | 11 ++--------- .../retromusic/fragments/genres/GenresFragment.kt | 8 +------- .../fragments/playlists/PlaylistsFragment.kt | 9 +-------- .../fragments/queue/PlayingQueueFragment.kt | 9 +-------- .../retromusic/fragments/songs/SongsFragment.kt | 10 +--------- 7 files changed, 8 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt index 713fe635..8ef2f0d2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt @@ -5,7 +5,7 @@ import androidx.room.RoomDatabase @Database( entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class], - version = 18, + version = 20, exportSchema = false ) abstract class RetroDatabase : RoomDatabase() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index d9f383ec..5b4a30b6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -14,8 +14,7 @@ import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment import code.name.monkey.retromusic.util.PreferenceUtil -class AlbumsFragment : - AbsRecyclerViewCustomGridSizeFragment(), +class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment(), AlbumClickListener { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt index 6f2d91a1..30e188e6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt @@ -12,17 +12,10 @@ import code.name.monkey.retromusic.adapter.artist.ArtistAdapter import code.name.monkey.retromusic.extensions.findActivityNavController import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment -import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks import code.name.monkey.retromusic.util.PreferenceUtil -class ArtistsFragment : - AbsRecyclerViewCustomGridSizeFragment(), - MainActivityFragmentCallbacks, ArtistClickListener { - - override fun handleBackPress(): Boolean { - return false - } - +class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment(), + ArtistClickListener { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt index e4017e57..93af4203 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt @@ -21,14 +21,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.GenreAdapter import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment -import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks -class GenresFragment : AbsRecyclerViewFragment(), - MainActivityFragmentCallbacks { - - override fun handleBackPress(): Boolean { - return false - } +class GenresFragment : AbsRecyclerViewFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index cd3a2f60..6c094048 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -7,15 +7,8 @@ import androidx.recyclerview.widget.GridLayoutManager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment -import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks -class PlaylistsFragment : - AbsRecyclerViewFragment(), - MainActivityFragmentCallbacks { - - override fun handleBackPress(): Boolean { - return false - } +class PlaylistsFragment : AbsRecyclerViewFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt index f829f985..6376420c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/queue/PlayingQueueFragment.kt @@ -22,7 +22,6 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager @@ -33,13 +32,7 @@ import kotlinx.android.synthetic.main.activity_playing_queue.* /** * Created by hemanths on 2019-12-08. */ -class PlayingQueueFragment : - AbsRecyclerViewFragment(), - 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/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index 3db01eb7..51dd9d8c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -9,17 +9,9 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.SongAdapter import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment -import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks import code.name.monkey.retromusic.util.PreferenceUtil -class SongsFragment : - AbsRecyclerViewCustomGridSizeFragment(), - MainActivityFragmentCallbacks { - - override fun handleBackPress(): Boolean { - return false - } - +class SongsFragment : AbsRecyclerViewCustomGridSizeFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer { From 6881e9a4c1f1b13963a59ebca358e8d9bb3d6441 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Mon, 31 Aug 2020 18:00:07 +0530 Subject: [PATCH 25/46] Code refactor --- README.md | 2 +- .../code/name/monkey/retromusic/MainModule.kt | 21 ++++- .../retromusic/activities/MainActivity.kt | 3 +- .../base/AbsMusicServiceActivity.kt | 24 +++++- .../base/AbsSlidingMusicPanelActivity.kt | 1 - .../tageditor/AbsTagEditorActivity.kt | 11 +-- .../tageditor/AlbumTagEditorActivity.kt | 2 +- .../tageditor/SongTagEditorActivity.kt | 2 +- .../adapter/playlist/PlaylistAdapter.kt | 2 - .../monkey/retromusic/db/BlackListStoreDao.kt | 21 +++++ .../name/monkey/retromusic/db/PlayCountDao.kt | 21 +++++ .../name/monkey/retromusic/db/PlaylistDao.kt | 24 ------ .../monkey/retromusic/db/RetroDatabase.kt | 4 +- .../retromusic/dialogs/AddToRetroPlaylist.kt | 2 +- .../retromusic/dialogs/CreateRetroPlaylist.kt | 25 +++++- .../monkey/retromusic/extensions/ColorExt.kt | 5 -- .../fragments/CoroutineViewModel.kt | 23 ++++++ .../fragments/DetailListFragment.kt | 4 +- .../retromusic/fragments/LibraryViewModel.kt | 22 +----- .../fragments/albums/AlbumDetailsFragment.kt | 20 +++-- .../fragments/albums/AlbumDetailsViewModel.kt | 28 ++++--- .../artists/ArtistDetailsFragment.kt | 22 +++--- .../fragments/base/AbsPlayerFragment.kt | 36 +++++---- .../retromusic/fragments/home/HomeFragment.kt | 8 -- .../playlists/PlaylistDetailsViewModel.kt | 3 +- .../fragments/songs/SongsFragment.kt | 1 - .../fragments/songs/SongsViewModel.kt | 31 ++++++++ .../retromusic/glide/SingleColorTarget.kt | 39 ++++++++++ .../retromusic/repository/Repository.kt | 40 +++++----- ...laylistRepository.kt => RoomRepository.kt} | 77 +++++++++++++------ .../monkey/retromusic/util/ColorUtil.java | 58 ++++++++++++++ gradle.properties | 2 +- 32 files changed, 411 insertions(+), 173 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/BlackListStoreDao.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/fragments/CoroutineViewModel.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/glide/SingleColorTarget.kt rename app/src/main/java/code/name/monkey/retromusic/repository/{RoomPlaylistRepository.kt => RoomRepository.kt} (67%) create mode 100644 app/src/main/java/code/name/monkey/retromusic/util/ColorUtil.java diff --git a/README.md b/README.md index 147dc995..66b64c0d 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ favorite songs. No other music player has this feature. We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features. -### FAQ +### ❓ FAQ Please read the FAQ here: https://del.dog/RetroFaq In any case, you find or notice any bugs please report them by diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index 25367b22..40a296ba 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -3,8 +3,8 @@ package code.name.monkey.retromusic import androidx.room.Room import androidx.room.RoomDatabase import androidx.sqlite.db.SupportSQLiteDatabase +import code.name.monkey.retromusic.db.BlackListStoreDao import code.name.monkey.retromusic.db.BlackListStoreEntity -import code.name.monkey.retromusic.db.PlaylistDao import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.RetroDatabase import code.name.monkey.retromusic.fragments.LibraryViewModel @@ -13,6 +13,7 @@ import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.search.SearchViewModel +import code.name.monkey.retromusic.fragments.songs.SongsViewModel import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.network.networkModule import code.name.monkey.retromusic.repository.* @@ -35,7 +36,7 @@ private val roomModule = module { super.onOpen(db) GlobalScope.launch(IO) { FilePathUtil.blacklistFilePaths().map { - get().insertBlacklistPath(BlackListStoreEntity(it)) + get().insertBlacklistPath(BlackListStoreEntity(it)) } } } @@ -48,9 +49,17 @@ private val roomModule = module { get().playlistDao() } + factory { + get().blackListStore() + } + + factory { + get().playCountDao() + } + single { - RealRoomRepository(get()) - } bind RoomPlaylistRepository::class + RealRoomRepository(get(), get(), get()) + } bind RoomRepository::class } private val mainModule = module { single { @@ -143,6 +152,10 @@ private val viewModules = module { viewModel { SearchViewModel(get()) } + + viewModel { + SongsViewModel(get()) + } } val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 2f0df045..92682de7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -34,7 +34,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis } private val repository by inject() - private var blockRequestPermissions = false override fun createContentView(): View { @@ -133,7 +132,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis if (id >= 0) { lifecycleScope.launch(Dispatchers.Main) { val position = intent.getIntExtra("position", 0) - openQueue(repository.albumById(id).songs!!, position, true) + openQueue(repository.albumByIdAsync(id).songs!!, position, true) handled = true } } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt index 9057625f..1e9efee8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsMusicServiceActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.toPlayCount import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.MusicServiceEventListener +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.service.MusicService.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject import java.lang.ref.WeakReference import java.util.* abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener { private val mMusicServiceEventListeners = ArrayList() - + 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/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt index 57c27f92..5ad965b3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt @@ -73,7 +73,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { setContentView(createContentView()) chooseFragmentForTheme() setupSlidingUpPanel() - addMusicServiceEventListener(libraryViewModel) setupBottomSheet() diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt index d9f006e7..1571e07a 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 @@ -182,11 +181,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { saveFab = findViewById(R.id.saveTags) getIntentExtras() - lifecycleScope.launchWhenCreated { - songPaths = getSongPaths() - if (songPaths!!.isEmpty()) { - finish() - } + songPaths = getSongPaths() + if (songPaths!!.isEmpty()) { + finish() } setUpViews() } @@ -258,7 +255,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { } } - protected abstract suspend fun getSongPaths(): List + protected abstract fun getSongPaths(): List protected fun searchWebFor(vararg keys: String) { val stringBuilder = StringBuilder() diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt index 8c3e142b..8a908dd6 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt @@ -167,7 +167,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher { ) } - override suspend fun getSongPaths(): List { + override fun getSongPaths(): List { val songs = repository.albumById(id).songs val paths = ArrayList(songs!!.size) for (song in songs) { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt index 5e3d5909..35b02bda 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index 7f1af392..17f0d78d 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -154,13 +154,11 @@ class PlaylistAdapter( 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) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/BlackListStoreDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/BlackListStoreDao.kt new file mode 100644 index 00000000..db0dd0f6 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/db/PlayCountDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt new file mode 100644 index 00000000..9c22d4da --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt @@ -0,0 +1,21 @@ +package code.name.monkey.retromusic.db + +import androidx.room.* + +@Dao +interface PlayCountDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertSongInPlayCount(playCountEntity: PlayCountEntity) + + @Update + fun updateSongInPlayCount(playCountEntity: PlayCountEntity) + + @Delete + fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) + + @Query("SELECT * FROM PlayCountEntity WHERE id =:songId") + fun checkSongExistInPlayCount(songId: Int): List + + @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC") + fun playCountSongs(): List +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index 1e4356c9..c3b7f801 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -63,30 +63,6 @@ interface PlaylistDao { @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") fun favoritesSongs(playlistId: Int): List - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insertSongInPlayCount(playCountEntity: PlayCountEntity) - @Update - fun updateSongInPlayCount(playCountEntity: PlayCountEntity) - @Delete - fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) - - @Query("SELECT * FROM PlayCountEntity WHERE id =:songId") - fun checkSongExistInPlayCount(songId: Int): List - - @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC") - fun playCountSongs(): List - - @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() } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt index 713fe635..2a2d15a5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt @@ -5,9 +5,11 @@ import androidx.room.RoomDatabase @Database( entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class], - version = 18, + version = 19, exportSchema = false ) abstract class RetroDatabase : RoomDatabase() { abstract fun playlistDao(): PlaylistDao + abstract fun blackListStore(): BlackListStoreDao + abstract fun playCountDao(): PlayCountDao } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index a4275ba1..b604a80e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -54,7 +54,7 @@ class AddToRetroPlaylist : BottomSheetDialogFragment() { return materialDialog(R.string.add_playlist_title) .setItems(playlistNames.toTypedArray()) { _, which -> if (which == 0) { - CreateRetroPlaylist().show(requireActivity().supportFragmentManager, "Dialog") + CreateRetroPlaylist.create(songs).show(requireActivity().supportFragmentManager, "Dialog") } else { lifecycleScope.launch(Dispatchers.IO) { val songEntities = songs.toSongEntity(playlistEntities[which - 1]) diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt index 6d237ebb..bb975366 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -5,14 +5,18 @@ 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 androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.extensions.colorButtons +import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.Playlists +import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout @@ -25,8 +29,24 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel class CreateRetroPlaylist : DialogFragment() { private val repository by inject() private val libraryViewModel by sharedViewModel() + + companion object { + fun create(song: Song): CreateRetroPlaylist { + val list = mutableListOf() + list.add(song) + return create(list) + } + + fun create(songs: List): CreateRetroPlaylist { + return CreateRetroPlaylist().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 = extraNotNull>(EXTRA_SONG).value val playlistView: TextInputEditText = view.actionNewPlaylist val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer return materialDialog(R.string.new_playlist_title) @@ -38,13 +58,14 @@ class CreateRetroPlaylist : DialogFragment() { if (!TextUtils.isEmpty(playlistName)) { lifecycleScope.launch(Dispatchers.IO) { if (repository.checkPlaylistExists(playlistName).isEmpty()) { - repository.createPlaylist(PlaylistEntity(playlistName)) + val playlistId = repository.createPlaylist(PlaylistEntity(playlistName)) + println(playlistId) + repository.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) libraryViewModel.forceReload(Playlists) } else { Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) .show() } - } } else { playlistContainer.error = "Playlist is can't be empty" diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt index 2059d929..0ff25d80 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt @@ -35,7 +35,6 @@ import code.name.monkey.retromusic.R import com.google.android.material.button.MaterialButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton -import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout fun Int.ripAlpha(): Int { @@ -145,10 +144,6 @@ fun TextInputLayout.accentColor() { isHintAnimationEnabled = true } -fun TextInputEditText.accentColor() { - -} - fun AppCompatImageView.accentColor(): Int { return ThemeStore.accentColor(context) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/CoroutineViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/CoroutineViewModel.kt new file mode 100644 index 00000000..9b6a5ca4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/fragments/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt index 57e11cdd..c71bcceb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt @@ -85,7 +85,9 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de layoutManager = linearLayoutManager() } lifecycleScope.launch(IO) { - val songs = repository.recentSongs() + val songs = repository.playCountSongs().map { + it.toSong() + } withContext(Main) { songAdapter.swapDataSet(songs) } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index cefe5c70..c0066d81 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -5,9 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import code.name.monkey.retromusic.db.PlaylistWithSongs -import code.name.monkey.retromusic.db.toPlayCount import code.name.monkey.retromusic.fragments.ReloadType.* -import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.repository.RealRepository @@ -51,7 +49,7 @@ class LibraryViewModel( artists.value = loadArtists.await() playlists.value = loadPlaylists.await() roomPlaylists.value = loadPlaylistsWithSongs.await() - genres.value = loadGenres.await() + //genres.value = loadGenres.await() } private val loadHome: Deferred> @@ -86,7 +84,6 @@ class LibraryViewModel( fun forceReload(reloadType: ReloadType) = viewModelScope.launch { - println(reloadType) when (reloadType) { Songs -> songs.value = loadSongs.await() Albums -> albums.value = loadAlbums.await() @@ -121,22 +118,7 @@ class LibraryViewModel( override fun onPlayingMetaChanged() { println("onPlayingMetaChanged") - viewModelScope.launch(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 += playCount + 1 - }) - } else { - repository.insertSongInPlayCount(MusicPlayerRemote.currentSong.toPlayCount()) - } - } + } override fun onPlayStateChanged() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 95b0a33e..bd9516fb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -14,6 +14,7 @@ import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager +import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.EXTRA_ALBUM_ID @@ -32,6 +33,7 @@ import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.glide.AlbumGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.RetroMusicColoredTarget +import code.name.monkey.retromusic.glide.SingleColorTarget import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.model.Album @@ -77,9 +79,9 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det toolbar.title = null postponeEnterTransition() - detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer { - showAlbum(it) + detailsViewModel.getAlbum2().observe(viewLifecycleOwner, Observer { startPostponedEnterTransition() + showAlbum(it) }) detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer { loadArtistImage(it) @@ -232,16 +234,18 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det .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.applyOutlineColor(color.backgroundColor) + private fun setColors(color: Int) { + val finalColor = + if (PreferenceUtil.isAdaptiveColor) color else ThemeStore.accentColor(requireContext()) + shuffleAction.applyColor(finalColor) + playAction.applyOutlineColor(finalColor) } override fun onAlbumClick(albumId: Int, view: View) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt index a951531f..f698f882 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt @@ -1,16 +1,13 @@ package code.name.monkey.retromusic.fragments.albums -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.* import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.repository.RealRepository import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -24,7 +21,11 @@ class AlbumDetailsViewModel( private val _lastFmAlbum = MutableLiveData() private val _moreAlbums = MutableLiveData>() - fun getAlbum(): LiveData = _album + fun getAlbum(): LiveData = liveData(IO) { + val album = realRepository.albumByIdAsync(albumId) + emit(album) + } + fun getArtist(): LiveData = _artist fun getAlbumInfo(): LiveData = _lastFmAlbum fun getMoreAlbums(): LiveData> = _moreAlbums @@ -33,17 +34,22 @@ class AlbumDetailsViewModel( loadAlbumDetails() } - private fun loadAlbumDetails() = viewModelScope.launch { + fun getAlbum2() = liveData(context = viewModelScope.coroutineContext + IO) { + val album = realRepository.albumByIdAsync(albumId) + emit(album) + } + + private fun loadAlbumDetails() = viewModelScope.launch(IO) { val album = loadAlbumAsync.await() ?: throw NullPointerException("Album couldn't found") _album.postValue(album) } - fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) { + fun loadAlbumInfo(album: Album) = viewModelScope.launch(IO) { val lastFmAlbum = realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-") _lastFmAlbum.postValue(lastFmAlbum) } - fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) { + fun loadArtist(artistId: Int) = viewModelScope.launch(IO) { val artist = realRepository.artistById(artistId) _artist.postValue(artist) @@ -53,8 +59,8 @@ class AlbumDetailsViewModel( } private val loadAlbumAsync: Deferred - get() = viewModelScope.async(Dispatchers.IO) { - realRepository.albumById(albumId) + get() = viewModelScope.async(IO) { + realRepository.albumByIdAsync(albumId) } override fun onMediaStoreChanged() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt index 90049d7c..4d540e02 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt @@ -17,6 +17,7 @@ import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager +import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter @@ -28,15 +29,15 @@ import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.fragments.albums.AlbumClickListener import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.glide.ArtistGlideRequest -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget +import code.name.monkey.retromusic.glide.SingleColorTarget import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.network.model.LastFmArtist import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.CustomArtistImageUtil import code.name.monkey.retromusic.util.MusicUtil +import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil -import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.fragment_artist_content.* import kotlinx.android.synthetic.main.fragment_artist_details.* @@ -181,19 +182,22 @@ 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.applyOutlineColor(color.backgroundColor) + private fun setColors(color: Int) { + val finalColor = if (PreferenceUtil.isAdaptiveColor) color + else ThemeStore.accentColor(requireContext()) + shuffleAction.applyColor(finalColor) + playAction.applyOutlineColor(finalColor) } + override fun onAlbumClick(albumId: Int, view: View) { findNavController().navigate( R.id.albumDetailsFragment, diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index 975443f7..b0b9c458 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -35,7 +35,6 @@ import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.* import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.* -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch @@ -75,7 +74,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme R.id.action_add_to_playlist -> { lifecycleScope.launch(IO) { val playlists = get().roomPlaylists() - withContext(Dispatchers.Main) { + withContext(Main) { AddToRetroPlaylist.create(playlists, song) .show(childFragmentManager, "ADD_PLAYLIST") } @@ -87,7 +86,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme return true } R.id.action_save_playing_queue -> { - CreatePlaylistDialog.create(ArrayList(MusicPlayerRemote.playingQueue)) + CreateRetroPlaylist.create(ArrayList(MusicPlayerRemote.playingQueue)) .show(childFragmentManager, "ADD_TO_PLAYLIST") return true } @@ -163,15 +162,17 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme protected open fun toggleFavorite(song: Song) { lifecycleScope.launch(IO) { - val playlist: PlaylistEntity = repository.favoritePlaylist().first() - val songEntity = song.toSongEntity(playlist.playListId) - val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty() - if (isFavorite) { - repository.removeSongFromPlaylist(songEntity) - } else { - repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) - libraryViewModel.forceReload(Playlists) + val playlist: PlaylistEntity? = repository.favoritePlaylist() + if (playlist != null) { + val songEntity = song.toSongEntity(playlist.playListId) + val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty() + if (isFavorite) { + repository.removeSongFromPlaylist(songEntity) + } else { + repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) + } } + libraryViewModel.forceReload(Playlists) requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED)) } } @@ -198,13 +199,18 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme fun updateIsFavorite() { lifecycleScope.launch(IO) { - val playlist: PlaylistEntity = repository.favoritePlaylist().first() + val playlist: PlaylistEntity = repository.favoritePlaylist() val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId) val isFavorite = repository.isFavoriteSong(song).isNotEmpty() - withContext(Dispatchers.Main) { - val icon = if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border + withContext(Main) { + val icon = if (isFavorite) R.drawable.ic_favorite + else R.drawable.ic_favorite_border val drawable = - RetroUtil.getTintedVectorDrawable(requireContext(), icon, toolbarIconColor()) + RetroUtil.getTintedVectorDrawable( + requireContext(), + icon, + toolbarIconColor() + ) if (playerToolbar() != null) { playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite) ?.setIcon(drawable)?.title = diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt index 47d0918f..3fa46622 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt @@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments.home import android.app.ActivityOptions import android.os.Bundle -import android.util.DisplayMetrics import android.view.View import androidx.core.os.bundleOf import androidx.lifecycle.Observer @@ -50,13 +49,6 @@ class HomeFragment : 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) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt index 1532b895..cc13bad2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository @@ -33,7 +34,7 @@ class PlaylistDetailsViewModel( private fun loadPlaylistSongs(playlist: PlaylistWithSongs) = viewModelScope.launch(Dispatchers.IO) { - val songs: List = realRepository.playlistSongs(playlist) + val songs: List = playlist.songs.toSongs() withContext(Main) { _playListSongs.postValue(songs) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index 3db01eb7..e5ab4c05 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -15,7 +15,6 @@ import code.name.monkey.retromusic.util.PreferenceUtil class SongsFragment : AbsRecyclerViewCustomGridSizeFragment(), MainActivityFragmentCallbacks { - override fun handleBackPress(): Boolean { return false } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt new file mode 100644 index 00000000..3ec068fc --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt @@ -0,0 +1,31 @@ +package code.name.monkey.retromusic.fragments.songs + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.repository.SongRepository +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.launch + +class SongsViewModel( + private val songRepository: SongRepository +) : ViewModel() { + init { + update() + } + + private val songsData = MutableLiveData>().apply { value = mutableListOf() } + + fun getSongList(): LiveData> { + return songsData + } + + fun update() { + viewModelScope.launch(IO) { + val songs = songRepository.songs() + songsData.postValue(songs) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/SingleColorTarget.kt b/app/src/main/java/code/name/monkey/retromusic/glide/SingleColorTarget.kt new file mode 100644 index 00000000..d4b2db1c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 5bf16d0f..a3575a6e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -35,9 +35,11 @@ interface Repository { fun artistsFlow(): Flow>> fun playlistsFlow(): Flow>> fun genresFlow(): Flow>> - + fun historySong(): LiveData> + fun favorites(): LiveData> suspend fun allAlbums(): List - suspend fun albumById(albumId: Int): Album + suspend fun albumByIdAsync(albumId: Int): Album + fun albumById(albumId: Int): Album suspend fun allSongs(): List suspend fun allArtists(): List suspend fun albumArtists(): List @@ -75,7 +77,7 @@ interface Repository { suspend fun deleteSongsInPlaylist(songs: List) suspend fun removeSongFromPlaylist(songEntity: SongEntity) suspend fun deleteSongsFromPlaylist(playlists: List) - suspend fun favoritePlaylist(): List + suspend fun favoritePlaylist(): PlaylistEntity suspend fun isFavoriteSong(songEntity: SongEntity): List suspend fun addSongToHistory(currentSong: Song) suspend fun songPresentInHistory(currentSong: Song): HistoryEntity? @@ -88,8 +90,7 @@ interface Repository { suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun checkSongExistInPlayCount(songId: Int): List suspend fun playCountSongs(): List - fun historySong(): LiveData> - fun favorites(): LiveData> + suspend fun blackListPaths(): List } class RealRepository( @@ -103,13 +104,13 @@ class RealRepository( private val playlistRepository: PlaylistRepository, private val searchRepository: RealSearchRepository, private val topPlayedRepository: TopPlayedRepository, - private val roomRepository: RoomPlaylistRepository + private val roomRepository: RoomRepository ) : Repository { override suspend fun allAlbums(): List = albumRepository.albums() - override suspend fun albumById(albumId: Int): Album = albumRepository.album(albumId) - + override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) + override fun albumById(albumId: Int): Album = albumRepository.album(albumId) override suspend fun allArtists(): List = artistRepository.artists() override suspend fun albumArtists(): List = artistRepository.albumArtists() @@ -130,28 +131,24 @@ class RealRepository( override suspend fun allSongs(): List = songRepository.songs() - override suspend fun search(query: String?): MutableList = searchRepository.searchAll(context, query) - override suspend fun getPlaylistSongs(playlist: Playlist): List { - return if (playlist is AbsCustomPlaylist) { + override suspend fun getPlaylistSongs(playlist: Playlist): List = + if (playlist is AbsCustomPlaylist) { playlist.songs() } else { PlaylistSongsLoader.getPlaylistSongList(context, playlist.id) } - } override suspend fun getGenre(genreId: Int): List = genreRepository.songs(genreId) - override suspend fun artistInfo( name: String, lang: String?, cache: String? ): LastFmArtist = lastFMService.artistInfo(name, lang, cache) - override suspend fun albumInfo( artist: String, album: String @@ -193,8 +190,8 @@ class RealRepository( topAlbumsHome(), recentArtistsHome(), recentAlbumsHome(), - favoritePlaylistHome(), - genresHome() + favoritePlaylistHome() + // genresHome() ) for (section in sections) { if (section.arrayList.isNotEmpty()) { @@ -211,11 +208,10 @@ class RealRepository( override suspend fun playlistWithSongs(): List = roomRepository.playlistWithSongs() - override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List { - return playlistWithSongs.songs.map { + override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List = + playlistWithSongs.songs.map { it.toSong() } - } override suspend fun insertSongs(songs: List) = roomRepository.insertSongs(songs) @@ -243,7 +239,7 @@ class RealRepository( override suspend fun deleteSongsFromPlaylist(playlists: List) = roomRepository.deleteSongsFromPlaylist(playlists) - override suspend fun favoritePlaylist(): List = + override suspend fun favoritePlaylist(): PlaylistEntity = roomRepository.favoritePlaylist(context.getString(R.string.favorites)) override suspend fun isFavoriteSong(songEntity: SongEntity): List = @@ -280,6 +276,9 @@ class RealRepository( override suspend fun playCountSongs(): List = roomRepository.playCountSongs() + override suspend fun blackListPaths(): List = + roomRepository.blackListPaths() + override fun historySong(): LiveData> = roomRepository.historySongs() @@ -328,7 +327,6 @@ class RealRepository( val songs = favoritePlaylistSongs().map { it.toSong() } - println(songs.size) return Home(songs, FAVOURITES, R.string.favorites) } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt similarity index 67% rename from app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt rename to app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index 4bafb945..a523883d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomPlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -6,7 +6,10 @@ import code.name.monkey.retromusic.db.* import code.name.monkey.retromusic.model.Song -interface RoomPlaylistRepository { +interface RoomRepository { + fun historySongs(): LiveData> + fun favoritePlaylistLiveData(favorite: String): LiveData> + fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity) suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun checkPlaylistExists(playlistName: String): List suspend fun playlists(): List @@ -17,7 +20,7 @@ interface RoomPlaylistRepository { suspend fun renamePlaylistEntity(playlistId: Int, name: String) suspend fun deleteSongsInPlaylist(songs: List) suspend fun deleteSongsFromPlaylist(playlists: List) - suspend fun favoritePlaylist(favorite: String): List + suspend fun favoritePlaylist(favorite: String): PlaylistEntity suspend fun isFavoriteSong(songEntity: SongEntity): List suspend fun removeSongFromPlaylist(songEntity: SongEntity) suspend fun addSongToHistory(currentSong: Song) @@ -29,13 +32,18 @@ interface RoomPlaylistRepository { suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun checkSongExistInPlayCount(songId: Int): List suspend fun playCountSongs(): List - fun historySongs(): LiveData> - fun favoritePlaylistLiveData(favorite: String): LiveData> + suspend fun insertBlacklistPath(blackListStoreEntities: List) + suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) + suspend fun clearBlacklist() + suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity) + suspend fun blackListPaths(): List } class RealRoomRepository( - private val playlistDao: PlaylistDao -) : RoomPlaylistRepository { + private val playlistDao: PlaylistDao, + private val blackListStoreDao: BlackListStoreDao, + private val playCountDao: PlayCountDao +) : RoomRepository { @WorkerThread override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = playlistDao.createPlaylist(playlistEntity) @@ -51,20 +59,18 @@ class RealRoomRepository( override suspend fun playlistWithSongs(): List = playlistDao.playlistsWithSongs() - @WorkerThread - override suspend fun insertSongs(songs: List) { - /* val tempList = ArrayList(songs) + /* val tempList = ArrayList(songs) val existingSongs = songs.map { playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId) }.first() println("Existing ${existingSongs.size}") tempList.removeAll(existingSongs)*/ + @WorkerThread + override suspend fun insertSongs(songs: List) = playlistDao.insertSongsToPlaylist(songs) - } - override suspend fun getSongs(playlistEntity: PlaylistEntity): List { - return playlistDao.songsFromPlaylist(playlistEntity.playListId) - } + override suspend fun getSongs(playlistEntity: PlaylistEntity): List = + playlistDao.songsFromPlaylist(playlistEntity.playListId) override suspend fun deletePlaylistEntities(playlistEntities: List) = playlistDao.deletePlaylists(playlistEntities) @@ -75,14 +81,21 @@ class RealRoomRepository( override suspend fun deleteSongsInPlaylist(songs: List) = playlistDao.deleteSongsInPlaylist(songs) - override suspend fun deleteSongsFromPlaylist(playlists: List) { + override suspend fun deleteSongsFromPlaylist(playlists: List) = playlists.forEach { playlistDao.deleteSongsInPlaylist(it.playListId) } + + override suspend fun favoritePlaylist(favorite: String): PlaylistEntity { + val playlist: PlaylistEntity? = playlistDao.isPlaylistExists(favorite).firstOrNull() + return if (playlist != null) { + playlist + } else { + createPlaylist(PlaylistEntity(favorite)) + playlistDao.isPlaylistExists(favorite).first() + } } - override suspend fun favoritePlaylist(favorite: String): List = - playlistDao.isPlaylistExists(favorite) override suspend fun isFavoriteSong(songEntity: SongEntity): List = playlistDao.isSongExistsInPlaylist( @@ -111,25 +124,41 @@ class RealRoomRepository( playlistDao.isPlaylistExists(favorite).first().playListId ) - override suspend fun favoritePlaylistSongs(favorite: String): List { - return if (playlistDao.isPlaylistExists(favorite).isNotEmpty()) + override suspend fun favoritePlaylistSongs(favorite: String): List = + if (playlistDao.isPlaylistExists(favorite).isNotEmpty()) playlistDao.favoritesSongs( playlistDao.isPlaylistExists(favorite).first().playListId ) else emptyList() - } override suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) = - playlistDao.insertSongInPlayCount(playCountEntity) + playCountDao.insertSongInPlayCount(playCountEntity) override suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) = - playlistDao.updateSongInPlayCount(playCountEntity) + playCountDao.updateSongInPlayCount(playCountEntity) override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) = - playlistDao.deleteSongInPlayCount(playCountEntity) + playCountDao.deleteSongInPlayCount(playCountEntity) override suspend fun checkSongExistInPlayCount(songId: Int): List = - playlistDao.checkSongExistInPlayCount(songId) + playCountDao.checkSongExistInPlayCount(songId) override suspend fun playCountSongs(): List = - playlistDao.playCountSongs() + playCountDao.playCountSongs() + + override fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity) = + blackListStoreDao.insertBlacklistPath(blackListStoreEntity) + + override suspend fun insertBlacklistPath(blackListStoreEntities: List) = + blackListStoreDao.insertBlacklistPath(blackListStoreEntities) + + override suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity) = + blackListStoreDao.insertBlacklistPath(blackListStoreEntity) + + override suspend fun blackListPaths(): List = + blackListStoreDao.blackListPaths() + + override suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) = + blackListStoreDao.deleteBlacklistPath(blackListStoreEntity) + + override suspend fun clearBlacklist() = blackListStoreDao.clearBlacklist() } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ColorUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/ColorUtil.java new file mode 100644 index 00000000..e4133392 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/ColorUtil.java @@ -0,0 +1,58 @@ +package code.name.monkey.retromusic.util; + +import android.graphics.Bitmap; + +import androidx.annotation.ColorInt; +import androidx.annotation.Nullable; +import androidx.palette.graphics.Palette; + +import java.util.Collections; +import java.util.Comparator; + +public class ColorUtil { + + @Nullable + public static Palette generatePalette(Bitmap bitmap) { + if (bitmap == null) return null; + return Palette.from(bitmap).generate(); + } + + @ColorInt + public static int getColor(@Nullable Palette palette, int fallback) { + if (palette != null) { + if (palette.getVibrantSwatch() != null) { + return palette.getVibrantSwatch().getRgb(); + } else if (palette.getMutedSwatch() != null) { + return palette.getMutedSwatch().getRgb(); + } else if (palette.getDarkVibrantSwatch() != null) { + return palette.getDarkVibrantSwatch().getRgb(); + } else if (palette.getDarkMutedSwatch() != null) { + return palette.getDarkMutedSwatch().getRgb(); + } else if (palette.getLightVibrantSwatch() != null) { + return palette.getLightVibrantSwatch().getRgb(); + } else if (palette.getLightMutedSwatch() != null) { + return palette.getLightMutedSwatch().getRgb(); + } else if (!palette.getSwatches().isEmpty()) { + return Collections.max(palette.getSwatches(), SwatchComparator.getInstance()).getRgb(); + } + } + return fallback; + } + + private static class SwatchComparator implements Comparator { + private static SwatchComparator sInstance; + + static SwatchComparator getInstance() { + if (sInstance == null) { + sInstance = new SwatchComparator(); + } + return sInstance; + } + + @Override + public int compare(Palette.Swatch lhs, Palette.Swatch rhs) { + return lhs.getPopulation() - rhs.getPopulation(); + } + } + +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 181b62cc..a25e163f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx2048M +org.gradle.jvmargs=-Xmx4608m org.gradle.daemon=true org.gradle.parallel=true jvmArgs='-Xmx2048m' From ffa07498496b8f49bd3589f2af1b83db693d6a71 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Mon, 31 Aug 2020 18:42:03 +0530 Subject: [PATCH 26/46] Added List sort, grid size, layout changes --- .../retromusic/fragments/LibraryViewModel.kt | 2 +- .../fragments/albums/AlbumsFragment.kt | 181 ++++++++++++++- .../fragments/artists/ArtistsFragment.kt | 160 ++++++++++++- .../fragments/songs/SongsFragment.kt | 214 +++++++++++++++++- app/src/main/res/menu/menu_main.xml | 76 ++++++- 5 files changed, 626 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index 18353d23..8a4c8cac 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -52,7 +52,7 @@ class LibraryViewModel( artists.value = loadArtists.await() playlists.value = loadPlaylists.await() roomPlaylists.value = loadPlaylistsWithSongs.await() - //genres.value = loadGenres.await() + genres.value = loadGenres.await() } private val loadHome: Deferred> diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index 5b4a30b6..be1da592 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -1,7 +1,7 @@ package code.name.monkey.retromusic.fragments.albums import android.os.Bundle -import android.view.View +import android.view.* import androidx.core.os.bundleOf import androidx.lifecycle.Observer import androidx.navigation.fragment.FragmentNavigatorExtras @@ -12,7 +12,11 @@ import code.name.monkey.retromusic.adapter.album.AlbumAdapter import code.name.monkey.retromusic.extensions.findActivityNavController import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment +import code.name.monkey.retromusic.helper.SortOrder +import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.util.RetroUtil + class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment(), AlbumClickListener { @@ -103,6 +107,181 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment 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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt index 30e188e6..f0889914 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt @@ -1,7 +1,7 @@ package code.name.monkey.retromusic.fragments.artists import android.os.Bundle -import android.view.View +import android.view.* import android.widget.ImageView import androidx.core.os.bundleOf import androidx.lifecycle.Observer @@ -12,7 +12,10 @@ import code.name.monkey.retromusic.adapter.artist.ArtistAdapter import code.name.monkey.retromusic.extensions.findActivityNavController import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment +import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.util.RetroUtil + class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment(), ArtistClickListener { @@ -97,6 +100,161 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment 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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index b6d7783f..06d7f45c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -1,7 +1,7 @@ package code.name.monkey.retromusic.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,7 +9,10 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.SongAdapter import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment +import code.name.monkey.retromusic.helper.SortOrder.SongSortOrder import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.util.RetroUtil + class SongsFragment : AbsRecyclerViewCustomGridSizeFragment() { @@ -35,7 +38,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment 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/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 1458c415..83b9ea93 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -16,10 +16,82 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context=".DrawerActivity"> - + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + app:showAsAction="never" /> \ No newline at end of file From 9da8cb99cec71d037ae5c3aa217207bcf12359c8 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Wed, 2 Sep 2020 20:50:38 +0530 Subject: [PATCH 27/46] Code refactor --- .../fragments/base/AbsPlayerFragment.kt | 36 ++++++++++--------- app/src/main/res/navigation/main_graph.xml | 13 +------ 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index 1aa7dc14..55405bd9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -197,23 +197,25 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme fun updateIsFavorite() { lifecycleScope.launch(IO) { - val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist().first() - val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId) - val isFavorite = libraryViewModel.isFavoriteSong(song).isNotEmpty() - withContext(Main) { - val icon = - if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border - val 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) + val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist().firstOrNull() + if (playlist != null) { + val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId) + val isFavorite = libraryViewModel.isFavoriteSong(song).isNotEmpty() + withContext(Main) { + val icon = + if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border + val 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) + } } } } diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index c3d3f444..009217c2 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -5,10 +5,6 @@ android:id="@+id/retro_graph" app:startDestination="@id/libraryFragment"> - - - - - - - + tools:layout="@layout/fragment_library" /> Date: Sat, 5 Sep 2020 19:33:12 +0530 Subject: [PATCH 28/46] Code refactor --- .../code/name/monkey/retromusic/Constants.kt | 7 +- .../code/name/monkey/retromusic/MainModule.kt | 5 - .../retromusic/dialogs/AddToRetroPlaylist.kt | 3 +- .../retromusic/fragments/LibraryViewModel.kt | 120 ++++++++++-------- .../retromusic/fragments/NowPlayingScreen.kt | 1 - .../fragments/albums/AlbumDetailsFragment.kt | 2 +- .../fragments/albums/AlbumsFragment.kt | 2 +- .../artists/ArtistDetailsFragment.kt | 2 +- .../fragments/artists/ArtistsFragment.kt | 2 +- .../fragments/base/AbsPlayerFragment.kt | 2 +- .../fragments/genres/GenresFragment.kt | 2 +- .../retromusic/fragments/home/HomeFragment.kt | 2 +- .../fragments/playlists/PlaylistsFragment.kt | 2 +- .../fragments/songs/SongsFragment.kt | 4 +- .../fragments/songs/SongsViewModel.kt | 31 ----- .../retromusic/helper/menu/GenreMenuHelper.kt | 2 +- .../helper/menu/PlaylistMenuHelper.kt | 2 +- .../retromusic/helper/menu/SongMenuHelper.kt | 2 +- .../retromusic/helper/menu/SongsMenuHelper.kt | 2 +- .../retromusic/network/RetrofitClient.kt | 4 +- .../retromusic/repository/Repository.kt | 20 +-- .../retromusic/service/MusicService.java | 8 +- .../monkey/retromusic/util/PreferenceUtil.kt | 6 +- app/src/main/res/layout/abs_playlists.xml | 1 - 24 files changed, 108 insertions(+), 126 deletions(-) delete mode 100644 app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt index 32e91aca..4e3a7a24 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt @@ -31,7 +31,7 @@ object Constants { const val APP_TWITTER_LINK = "https://twitter.com/retromusicapp" const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md" const val PINTEREST = "https://in.pinterest.com/retromusicapp/" - const val BASE_URL = "https://ws.audioscrobbler.com/2.0/" + const val AUDIO_SCROBBLER_URL = "https://ws.audioscrobbler.com/2.0/" const val IS_MUSIC = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''" @@ -70,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" @@ -92,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/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index 40a296ba..aae0ed48 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -13,7 +13,6 @@ import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.search.SearchViewModel -import code.name.monkey.retromusic.fragments.songs.SongsViewModel import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.network.networkModule import code.name.monkey.retromusic.repository.* @@ -152,10 +151,6 @@ private val viewModules = module { viewModel { SearchViewModel(get()) } - - viewModel { - SongsViewModel(get()) - } } val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt index 52859a57..0e3debaf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -51,7 +51,8 @@ class AddToRetroPlaylist : BottomSheetDialogFragment() { return materialDialog(R.string.add_playlist_title) .setItems(playlistNames.toTypedArray()) { _, which -> if (which == 0) { - CreateRetroPlaylist.create(songs).show(requireActivity().supportFragmentManager, "Dialog") + CreateRetroPlaylist.create(songs) + .show(requireActivity().supportFragmentManager, "Dialog") } else { lifecycleScope.launch(Dispatchers.IO) { val songEntities = songs.toSongEntity(playlistEntities[which - 1]) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index 8a4c8cac..3392ccb8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -12,9 +12,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.repository.RealRepository -import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.async import kotlinx.coroutines.launch class LibraryViewModel( @@ -25,75 +23,95 @@ class LibraryViewModel( private val albums = MutableLiveData>() private val songs = MutableLiveData>() private val artists = MutableLiveData>() - private val playlists = MutableLiveData>() - private val roomPlaylists = MutableLiveData>() + private val playlists = 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 roomPlaylistsLiveData: LiveData> = roomPlaylists - val genresLiveData: LiveData> = genres - init { - viewModelScope.launch { - loadLibraryContent() + private fun loadLibraryContent() = viewModelScope.launch(IO) { + fetchSongs() + fetchAlbums() + fetchArtists() + fetchGenres() + fetchHomeSections() + 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 getGenre(): LiveData> { + fetchGenres() + return genres + } + + fun getHome(): LiveData> { + fetchHomeSections() + return home + } + + private fun fetchSongs() { + viewModelScope.launch(IO) { + songs.postValue(repository.allSongs()) } } - private fun loadLibraryContent() = viewModelScope.launch { - home.value = loadHome.await() - songs.value = loadSongs.await() - albums.value = loadAlbums.await() - artists.value = loadArtists.await() - playlists.value = loadPlaylists.await() - roomPlaylists.value = loadPlaylistsWithSongs.await() - genres.value = loadGenres.await() + private fun fetchAlbums() { + viewModelScope.launch(IO) { + albums.postValue(repository.fetchAlbums()) + } } - private val loadHome: Deferred> - get() = viewModelScope.async { repository.homeSections() } - - private val loadSongs: Deferred> - get() = viewModelScope.async(IO) { repository.allSongs() } - - private val loadAlbums: Deferred> - get() = viewModelScope.async(IO) { - repository.allAlbums() + private fun fetchArtists() { + viewModelScope.launch(IO) { + artists.postValue(repository.fetchArtists()) } + } - private val loadArtists: Deferred> - get() = viewModelScope.async(IO) { - repository.albumArtists() + private fun fetchPlaylists() { + viewModelScope.launch(IO) { + playlists.postValue(repository.fetchPlaylistWithSongs()) } + } - private val loadPlaylists: Deferred> - get() = viewModelScope.async(IO) { - repository.allPlaylists() - } - private val loadPlaylistsWithSongs: Deferred> - get() = viewModelScope.async(IO) { - repository.playlistWithSongs() + private fun fetchGenres() { + viewModelScope.launch(IO) { + genres.postValue(repository.fetchGenres()) } + } - private val loadGenres: Deferred> - get() = viewModelScope.async(IO) { - repository.allGenres() + 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 -> home.value = loadHome.await() - Playlists -> roomPlaylists.value = loadPlaylistsWithSongs.await() - Genres -> genres.value = loadGenres.await() + Songs -> fetchSongs() + Albums -> fetchAlbums() + Artists -> fetchArtists() + HomeSections -> fetchHomeSections() + Playlists -> fetchPlaylists() + Genres -> fetchGenres() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt index dacaff2d..19e08522 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/NowPlayingScreen.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index bd9516fb..351d0ff6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -287,7 +287,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det } R.id.action_add_to_playlist -> { lifecycleScope.launch(Dispatchers.IO) { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { AddToRetroPlaylist.create(playlists, songs) .show(childFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index be1da592..9f7b7ce0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -23,7 +23,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment { lifecycleScope.launch(Dispatchers.IO) { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { AddToRetroPlaylist.create(playlists, songs) .show(childFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt index f0889914..b39909d3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt @@ -22,7 +22,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment { lifecycleScope.launch(IO) { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Main) { AddToRetroPlaylist.create(playlists, song) .show(childFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt index 93af4203..568da54a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt @@ -26,7 +26,7 @@ class GenresFragment : AbsRecyclerViewFragment() { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer { + libraryViewModel.getSongs().observe(viewLifecycleOwner, Observer { + println(Thread.currentThread().name) if (it.isNotEmpty()) adapter?.swapDataSet(it) else diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt deleted file mode 100644 index 3ec068fc..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsViewModel.kt +++ /dev/null @@ -1,31 +0,0 @@ -package code.name.monkey.retromusic.fragments.songs - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.SongRepository -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch - -class SongsViewModel( - private val songRepository: SongRepository -) : ViewModel() { - init { - update() - } - - private val songsData = MutableLiveData>().apply { value = mutableListOf() } - - fun getSongList(): LiveData> { - return songsData - } - - fun update() { - viewModelScope.launch(IO) { - val songs = songRepository.songs() - songsData.postValue(songs) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt index df43e38d..c5a6af03 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt @@ -45,7 +45,7 @@ object GenreMenuHelper : KoinComponent { } R.id.action_add_to_playlist -> { CoroutineScope(Dispatchers.IO).launch { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { AddToRetroPlaylist.create(playlists, getGenreSongs(genre)) .show(activity.supportFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt index 535804fe..6dccf62f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt @@ -58,7 +58,7 @@ object PlaylistMenuHelper : KoinComponent { } R.id.action_add_to_playlist -> { CoroutineScope(Dispatchers.IO).launch { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { AddToRetroPlaylist.create(playlists, playlistWithSongs.songs.toSongs()) .show(activity.supportFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt index 115926de..58182efb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt @@ -71,7 +71,7 @@ object SongMenuHelper : KoinComponent { } R.id.action_add_to_playlist -> { CoroutineScope(Dispatchers.IO).launch { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { AddToRetroPlaylist.create(playlists, song) .show(activity.supportFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt index 058de45f..243d22fd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt @@ -45,7 +45,7 @@ object SongsMenuHelper : KoinComponent { } R.id.action_add_to_playlist -> { CoroutineScope(Dispatchers.IO).launch { - val playlists = get().roomPlaylists() + val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { AddToRetroPlaylist.create(playlists, songs) .show(activity.supportFragmentManager, "ADD_PLAYLIST") diff --git a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt index afaaeb67..affb3823 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt @@ -1,7 +1,7 @@ package code.name.monkey.retromusic.network import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.Constants.BASE_URL +import code.name.monkey.retromusic.Constants.AUDIO_SCROBBLER_URL import com.google.gson.Gson import okhttp3.Cache import okhttp3.ConnectionPool @@ -37,7 +37,7 @@ fun provideLastFmService(retrofit: Retrofit): LastFMService = retrofit.create(LastFMService::class.java) fun providerRetrofit(okHttpClient: OkHttpClient.Builder): Retrofit = Retrofit.Builder() - .baseUrl(BASE_URL) + .baseUrl(AUDIO_SCROBBLER_URL) .callFactory(okHttpClient.build()) .addConverterFactory(GsonConverterFactory.create(Gson())) .build() diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index a3575a6e..a89223e8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -37,14 +37,14 @@ interface Repository { fun genresFlow(): Flow>> fun historySong(): LiveData> fun favorites(): LiveData> - suspend fun allAlbums(): List + suspend fun fetchAlbums(): List suspend fun albumByIdAsync(albumId: Int): Album fun albumById(albumId: Int): Album suspend fun allSongs(): List - suspend fun allArtists(): List + suspend fun fetchArtists(): List suspend fun albumArtists(): List suspend fun allPlaylists(): List - suspend fun allGenres(): List + suspend fun fetchGenres(): List suspend fun search(query: String?): MutableList suspend fun getPlaylistSongs(playlist: Playlist): List suspend fun getGenre(genreId: Int): List @@ -66,12 +66,12 @@ interface Repository { suspend fun homeSections(): List suspend fun homeSectionsFlow(): Flow>> suspend fun playlist(playlistId: Int): Playlist - suspend fun playlistWithSongs(): List + suspend fun fetchPlaylistWithSongs(): List suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List suspend fun insertSongs(songs: List) suspend fun checkPlaylistExists(playlistName: String): List suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long - suspend fun roomPlaylists(): List + suspend fun fetchPlaylists(): List suspend fun deleteRoomPlaylist(playlists: List) suspend fun renameRoomPlaylist(playlistId: Int, name: String) suspend fun deleteSongsInPlaylist(songs: List) @@ -107,11 +107,11 @@ class RealRepository( private val roomRepository: RoomRepository ) : Repository { - override suspend fun allAlbums(): List = albumRepository.albums() + override suspend fun fetchAlbums(): List = albumRepository.albums() override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) override fun albumById(albumId: Int): Album = albumRepository.album(albumId) - override suspend fun allArtists(): List = artistRepository.artists() + override suspend fun fetchArtists(): List = artistRepository.artists() override suspend fun albumArtists(): List = artistRepository.albumArtists() @@ -127,7 +127,7 @@ class RealRepository( override suspend fun allPlaylists(): List = playlistRepository.playlists() - override suspend fun allGenres(): List = genreRepository.genres() + override suspend fun fetchGenres(): List = genreRepository.genres() override suspend fun allSongs(): List = songRepository.songs() @@ -205,7 +205,7 @@ class RealRepository( override suspend fun playlist(playlistId: Int) = playlistRepository.playlist(playlistId) - override suspend fun playlistWithSongs(): List = + override suspend fun fetchPlaylistWithSongs(): List = roomRepository.playlistWithSongs() override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List = @@ -222,7 +222,7 @@ class RealRepository( override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = roomRepository.createPlaylist(playlistEntity) - override suspend fun roomPlaylists(): List = roomRepository.playlists() + override suspend fun fetchPlaylists(): List = roomRepository.playlists() override suspend fun deleteRoomPlaylist(playlists: List) = roomRepository.deletePlaylistEntities(playlists) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java index 64dfe785..eff55a60 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -84,11 +84,11 @@ import code.name.monkey.retromusic.util.MusicUtil; import code.name.monkey.retromusic.util.PreferenceUtil; import code.name.monkey.retromusic.util.RetroUtil; -import static code.name.monkey.retromusic.ConstantsKt.ALBUM_ART_ON_LOCKSCREEN; +import static code.name.monkey.retromusic.ConstantsKt.ALBUM_ART_ON_LOCK_SCREEN; import static code.name.monkey.retromusic.ConstantsKt.BLURRED_ALBUM_ART; import static code.name.monkey.retromusic.ConstantsKt.CLASSIC_NOTIFICATION; import static code.name.monkey.retromusic.ConstantsKt.COLORED_NOTIFICATION; -import static code.name.monkey.retromusic.ConstantsKt.GAPLESS_PLAYBACK; +import static code.name.monkey.retromusic.ConstantsKt.GAP_LESS_PLAYBACK; import static code.name.monkey.retromusic.ConstantsKt.TOGGLE_HEADSET; /** @@ -727,7 +727,7 @@ public class MusicService extends Service implements @Override public void onSharedPreferenceChanged(@NonNull SharedPreferences sharedPreferences, @NonNull String key) { switch (key) { - case GAPLESS_PLAYBACK: + case GAP_LESS_PLAYBACK: if (sharedPreferences.getBoolean(key, false)) { prepareNext(); } else { @@ -736,7 +736,7 @@ public class MusicService extends Service implements } } break; - case ALBUM_ART_ON_LOCKSCREEN: + case ALBUM_ART_ON_LOCK_SCREEN: case BLURRED_ALBUM_ART: updateMediaSessionMetaData(); break; diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index 5ee2ac60..9b4d427e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -243,7 +243,7 @@ object PreferenceUtil { val isAlbumArtOnLockScreen get() = sharedPreferences.getBoolean( - ALBUM_ART_ON_LOCKSCREEN, false + ALBUM_ART_ON_LOCK_SCREEN, false ) val isAudioDucking @@ -292,7 +292,7 @@ object PreferenceUtil { val isGapLessPlayback get() = sharedPreferences.getBoolean( - GAPLESS_PLAYBACK, false + GAP_LESS_PLAYBACK, false ) val isAdaptiveColor @@ -471,7 +471,7 @@ object PreferenceUtil { var artistGridSizeLand get() = sharedPreferences.getInt( - ALBUM_GRID_SIZE_LAND, + ARTIST_GRID_SIZE_LAND, App.getContext().getIntRes(R.integer.default_grid_columns_land) ) set(value) = sharedPreferences.edit { diff --git a/app/src/main/res/layout/abs_playlists.xml b/app/src/main/res/layout/abs_playlists.xml index a0b8d1d2..73df4233 100644 --- a/app/src/main/res/layout/abs_playlists.xml +++ b/app/src/main/res/layout/abs_playlists.xml @@ -6,7 +6,6 @@ android:orientation="vertical" android:paddingBottom="12dp"> - Date: Sat, 5 Sep 2020 21:22:10 +0530 Subject: [PATCH 29/46] Code refactor --- .../retromusic/adapter/SearchAdapter.kt | 2 +- .../retromusic/adapter/album/AlbumAdapter.kt | 3 +-- .../adapter/album/HorizontalAlbumAdapter.kt | 2 +- .../fragments/albums/AlbumDetailsFragment.kt | 23 ++++++++----------- .../retromusic/fragments/home/HomeFragment.kt | 11 +++++++++ .../retromusic/glide/AlbumGlideRequest.java | 2 +- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt index c372b45c..97e2ada1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt index 73c8b09e..8cb9f9d8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt index 043f5ecd..8198a957 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt @@ -36,7 +36,7 @@ class HorizontalAlbumAdapter( 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/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 351d0ff6..6919e2a4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -79,7 +79,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det toolbar.title = null postponeEnterTransition() - detailsViewModel.getAlbum2().observe(viewLifecycleOwner, Observer { + detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer { startPostponedEnterTransition() showAlbum(it) }) @@ -149,12 +149,11 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det this.album = album albumTitle.text = album.title - val songText = - resources.getQuantityString( - R.plurals.albumSongs, - album.songCount, - album.songCount - ) + val songText = resources.getQuantityString( + R.plurals.albumSongs, + album.songCount, + album.songCount + ) songTitle.text = songText if (MusicUtil.getYearString(album.year) == "-") { @@ -171,7 +170,7 @@ 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) @@ -216,6 +215,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det private fun loadArtistImage(artist: Artist) { ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist) + .forceDownload(PreferenceUtil.isAllowedToDownloadMetadata()) .generatePalette(requireContext()) .build() .dontAnimate() @@ -226,14 +226,11 @@ 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 : SingleColorTarget(image) { override fun onColorReady(color: Int) { setColors(color) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt index c6f297d9..460731af 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt @@ -16,6 +16,9 @@ package code.name.monkey.retromusic.fragments.home import android.app.ActivityOptions import android.os.Bundle +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 @@ -116,6 +119,14 @@ class HomeFragment : ).build().into(userImage) } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + menu.removeItem(R.id.action_grid_size) + menu.removeItem(R.id.action_layout_type) + menu.removeItem(R.id.action_sort_order) + menu.findItem(R.id.action_settings).setShowAsAction(SHOW_AS_ACTION_IF_ROOM) + } + companion object { const val TAG: String = "BannerHomeFragment" diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/AlbumGlideRequest.java b/app/src/main/java/code/name/monkey/retromusic/glide/AlbumGlideRequest.java index fab61c61..82e65da2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/AlbumGlideRequest.java +++ b/app/src/main/java/code/name/monkey/retromusic/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()); } From cf3db7a76bb9a6606816bb13db24c91d474c0817 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sat, 5 Sep 2020 21:24:16 +0530 Subject: [PATCH 30/46] Code refactor --- .../monkey/retromusic/extensions/ColorExt.kt | 27 ++++++++++++++++--- .../retromusic/extensions/FragmentExt.kt | 11 ++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt index fc08d6e7..8d2d56e4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt @@ -18,13 +18,16 @@ 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.ColorInt +import androidx.annotation.* +import androidx.appcompat.content.res.AppCompatResources 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 @@ -163,4 +166,22 @@ fun TextInputEditText.accentColor() { fun AppCompatImageView.accentColor(): Int { return ThemeStore.accentColor(context) -} \ No newline at end of file +} + +@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/code/name/monkey/retromusic/extensions/FragmentExt.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExt.kt index 876e549f..a826d153 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExt.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExt.kt @@ -2,12 +2,15 @@ package code.name.monkey.retromusic.extensions import android.content.Context import android.content.res.Configuration +import android.graphics.drawable.Drawable import android.os.PowerManager import android.widget.Toast +import androidx.annotation.DrawableRes import androidx.annotation.IdRes import androidx.annotation.IntegerRes import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.content.res.AppCompatResources import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.navigation.fragment.NavHostFragment @@ -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 From 25fbbce11efbec8c08dd44d901a94bd9f69a2d96 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sat, 5 Sep 2020 23:46:44 +0530 Subject: [PATCH 31/46] =?UTF-8?q?Don't=20update=20Material=20lib=20to=20al?= =?UTF-8?q?pha02=20=F0=9F=99=86=F0=9F=8F=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 91 ++++++++----------- .../adapter/song/PlayingQueueAdapter.kt | 16 ++-- 2 files changed, 46 insertions(+), 61 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c89ce22d..d928d693 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -102,68 +102,50 @@ static def getDate() { dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':appthemehelper') implementation 'androidx.multidex:multidex:2.0.1' - implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.cardview:cardview:1.0.0" - implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01" implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.annotation:annotation:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' + implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.core:core-ktx:1.3.1' implementation 'androidx.fragment:fragment-ktx:1.2.5' implementation 'androidx.palette:palette-ktx:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8' - implementation 'androidx.recyclerview:recyclerview:1.1.0' + def nav_version = "2.3.0" + implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" + implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - implementation 'com.google.android.material:material:1.3.0-alpha01' - - def retrofit_version = '2.9.0' - implementation "com.squareup.retrofit2:retrofit:$retrofit_version" - implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" - - def material_dialog_version = "0.9.6.0" - implementation "com.afollestad.material-dialogs:core:$material_dialog_version" - implementation "com.afollestad.material-dialogs:commons:$material_dialog_version" - implementation 'com.afollestad:material-cab:0.1.12' - implementation 'com.afollestad:recyclical:1.1.1' - - implementation 'com.github.bumptech.glide:glide:3.8.0' - implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0' - implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0' - - implementation('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') { - transitive = true - } - - def kotlin_coroutines_version = "1.3.8" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" - - implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r' - - implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' - implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod' - - implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3' - - implementation 'com.anjlab.android.iab.v3:library:1.1.0' - implementation 'com.r0adkll:slidableactivity:2.1.0' - implementation 'com.heinrichreimersoftware:material-intro:1.6' - implementation 'me.zhanghai.android.fastscroll:library:1.1.0' + def room_version = "2.2.5" + implementation "androidx.room:room-runtime:$room_version" + implementation "androidx.room:room-ktx:$room_version" + kapt "androidx.room:room-compiler:$room_version" def lifecycle_version = "2.2.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" - implementation 'com.google.android.play:core:1.8.0' - implementation 'me.jorgecastillo:androidcolorx:0.2.0' - 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.0" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" def koin_version = "2.1.5" implementation "org.koin:koin-core:$koin_version" @@ -173,16 +155,23 @@ 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' - def room_version = "2.2.5" - implementation "androidx.room:room-runtime:$room_version" - kapt "androidx.room:room-compiler:$room_version" - implementation "androidx.room:room-ktx:$room_version" + implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0' + implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r' + implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' + implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod' + implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3' + implementation 'com.anjlab.android.iab.v3:library:1.1.0' + implementation 'com.r0adkll:slidableactivity:2.1.0' + implementation 'com.heinrichreimersoftware:material-intro:1.6' + implementation 'com.github.dhaval2404:imagepicker:1.7.1' + + implementation 'me.zhanghai.android.fastscroll:library:1.1.0' + implementation 'me.jorgecastillo:androidcolorx:0.2.0' debugImplementation 'com.amitshekhar.android:debug-db:1.0.6' } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt index c49389bd..2b1b9198 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt @@ -20,7 +20,6 @@ import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstant import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem -import com.h6ah4i.android.widget.advrecyclerview.swipeable.annotation.SwipeableItemResults import me.zhanghai.android.fastscroll.PopupTextProvider class PlayingQueueAdapter( @@ -153,8 +152,8 @@ class PlayingQueueAdapter( mDragStateFlags = flags } - override fun getSwipeableContainerView(): View? { - return dummyContainer + override fun getSwipeableContainerView(): View { + return dummyContainer!! } } @@ -165,10 +164,7 @@ class PlayingQueueAdapter( private const val UP_NEXT = 2 } - override fun onSwipeItem( - holder: ViewHolder?, - position: Int, @SwipeableItemResults result: Int - ): SwipeResultAction { + override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int): SwipeResultAction? { return if (result == SwipeableItemConstants.RESULT_CANCELED) { SwipeResultActionDefault() } else { @@ -176,7 +172,7 @@ class PlayingQueueAdapter( } } - 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( From 41e8aa8a03cd05ecf719cd1f259d770ce6d9e823 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sat, 5 Sep 2020 23:54:05 +0530 Subject: [PATCH 32/46] =?UTF-8?q?=F0=9F=97=91Deleted=20unwanted=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../retromusic/dialogs/AddToPlaylistDialog.kt | 96 +++++++++---------- .../retromusic/dialogs/AddToRetroPlaylist.kt | 73 -------------- .../dialogs/CreatePlaylistDialog.kt | 93 ++++++++---------- .../retromusic/dialogs/CreateRetroPlaylist.kt | 77 --------------- .../dialogs/DeletePlaylistDialog.kt | 62 ++++++------ .../retromusic/dialogs/DeleteRetroPlaylist.kt | 69 ------------- .../dialogs/RemoveFromPlaylistDialog.kt | 84 ---------------- .../dialogs/RenamePlaylistDialog.kt | 72 ++++++-------- .../dialogs/RenameRetroPlaylistDialog.kt | 57 ----------- .../dialogs/RetroSingleCheckedListAdapter.kt | 11 --- .../retromusic/dialogs/SavePlaylistDialog.kt | 4 + .../fragments/albums/AlbumDetailsFragment.kt | 4 +- .../artists/ArtistDetailsFragment.kt | 4 +- .../fragments/base/AbsPlayerFragment.kt | 16 ++-- .../fragments/library/LibraryFragment.kt | 4 +- .../retromusic/helper/menu/GenreMenuHelper.kt | 4 +- .../helper/menu/PlaylistMenuHelper.kt | 13 +-- .../retromusic/helper/menu/SongMenuHelper.kt | 4 +- .../retromusic/helper/menu/SongsMenuHelper.kt | 4 +- 19 files changed, 172 insertions(+), 579 deletions(-) delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/RetroSingleCheckedListAdapter.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt index c4d54ef0..4faa019a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt @@ -1,77 +1,73 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - package code.name.monkey.retromusic.dialogs import android.app.Dialog import android.os.Bundle -import androidx.fragment.app.DialogFragment +import androidx.core.os.bundleOf +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.EXTRA_PLAYLISTS import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.PlaylistRepository -import code.name.monkey.retromusic.util.PlaylistsUtil -import org.koin.android.ext.android.inject +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.androidx.viewmodel.ext.android.sharedViewModel +class AddToPlaylistDialog : BottomSheetDialogFragment() { + private val libraryViewModel by sharedViewModel() -class AddToPlaylistDialog : DialogFragment() { - private val playlistRepository by inject() - override fun onCreateDialog( - savedInstanceState: Bundle? - ): Dialog { - val playlists = playlistRepository.playlists() + companion object { + fun create(playlistEntities: List, song: Song): AddToPlaylistDialog { + val list = 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 = extraNotNull>(EXTRA_PLAYLISTS).value + val songs = extraNotNull>(EXTRA_SONG).value val playlistNames = mutableListOf() playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist)) - for (p in playlists) { - playlistNames.add(p.name) + for (p in playlistEntities) { + playlistNames.add(p.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 = songs.toSongEntity(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 - } +private fun List.toSongEntity(playlistEntity: PlaylistEntity): List { + return map { + it.toSongEntity(playlistEntity.playListId) } -} \ No newline at end of file +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt deleted file mode 100644 index 0e3debaf..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt +++ /dev/null @@ -1,73 +0,0 @@ -package code.name.monkey.retromusic.dialogs - -import android.app.Dialog -import android.os.Bundle -import androidx.core.os.bundleOf -import androidx.lifecycle.lifecycleScope -import code.name.monkey.retromusic.EXTRA_PLAYLISTS -import code.name.monkey.retromusic.EXTRA_SONG -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.db.SongEntity -import code.name.monkey.retromusic.extensions.colorButtons -import code.name.monkey.retromusic.extensions.extraNotNull -import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.fragments.LibraryViewModel -import code.name.monkey.retromusic.fragments.ReloadType.Playlists -import code.name.monkey.retromusic.model.Song -import com.google.android.material.bottomsheet.BottomSheetDialogFragment -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -class AddToRetroPlaylist : BottomSheetDialogFragment() { - private val libraryViewModel by sharedViewModel() - - companion object { - fun create(playlistEntities: List, song: Song): AddToRetroPlaylist { - val list = mutableListOf() - list.add(song) - return create(playlistEntities, list) - } - - fun create(playlistEntities: List, songs: List): AddToRetroPlaylist { - return AddToRetroPlaylist().apply { - arguments = bundleOf( - EXTRA_SONG to songs, - EXTRA_PLAYLISTS to playlistEntities - ) - } - } - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val playlistEntities = extraNotNull>(EXTRA_PLAYLISTS).value - val songs = extraNotNull>(EXTRA_SONG).value - val playlistNames = mutableListOf() - playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist)) - for (p in playlistEntities) { - playlistNames.add(p.playlistName) - } - return materialDialog(R.string.add_playlist_title) - .setItems(playlistNames.toTypedArray()) { _, which -> - if (which == 0) { - CreateRetroPlaylist.create(songs) - .show(requireActivity().supportFragmentManager, "Dialog") - } else { - lifecycleScope.launch(Dispatchers.IO) { - val songEntities = songs.toSongEntity(playlistEntities[which - 1]) - libraryViewModel.insertSongs(songEntities) - libraryViewModel.forceReload(Playlists) - } - } - dismiss() - } - .create().colorButtons() - } -} - -private fun List.toSongEntity(playlistEntity: PlaylistEntity): List { - return map { - it.toSongEntity(playlistEntity.playListId) - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt index d4eeb9eb..a2c6eedb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt @@ -1,88 +1,77 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - package code.name.monkey.retromusic.dialogs -import android.annotation.SuppressLint import android.app.Dialog import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater +import android.widget.Toast +import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment -import code.name.monkey.appthemehelper.util.MaterialUtil +import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.repository.RealRepository 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.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class CreatePlaylistDialog : DialogFragment() { + private val repository by inject() + 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 = extraNotNull>(EXTRA_SONG).value 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 (repository.checkPlaylistExists(playlistName).isEmpty()) { + val playlistId = repository.createPlaylist(PlaylistEntity(playlistName)) + println(playlistId) + repository.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) + libraryViewModel.forceReload(Playlists) + } else { + Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) + .show() + } } + } else { + playlistContainer.error = "Playlist is can't be empty" } } .create() .colorButtons() } - - companion object { - @JvmOverloads - @JvmStatic - fun create(song: Song? = null): CreatePlaylistDialog { - val list = ArrayList() - 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/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt deleted file mode 100644 index bb975366..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt +++ /dev/null @@ -1,77 +0,0 @@ -package code.name.monkey.retromusic.dialogs - -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 androidx.lifecycle.lifecycleScope -import code.name.monkey.retromusic.EXTRA_SONG -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.extensions.colorButtons -import code.name.monkey.retromusic.extensions.extraNotNull -import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.fragments.LibraryViewModel -import code.name.monkey.retromusic.fragments.ReloadType.Playlists -import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.RealRepository -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.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -class CreateRetroPlaylist : DialogFragment() { - private val repository by inject() - private val libraryViewModel by sharedViewModel() - - companion object { - fun create(song: Song): CreateRetroPlaylist { - val list = mutableListOf() - list.add(song) - return create(list) - } - - fun create(songs: List): CreateRetroPlaylist { - return CreateRetroPlaylist().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 = extraNotNull>(EXTRA_SONG).value - val playlistView: TextInputEditText = view.actionNewPlaylist - val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer - return materialDialog(R.string.new_playlist_title) - .setView(view) - .setPositiveButton( - R.string.create_action - ) { _, _ -> - val playlistName = playlistView.text.toString() - if (!TextUtils.isEmpty(playlistName)) { - lifecycleScope.launch(Dispatchers.IO) { - if (repository.checkPlaylistExists(playlistName).isEmpty()) { - val playlistId = repository.createPlaylist(PlaylistEntity(playlistName)) - println(playlistId) - repository.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) - libraryViewModel.forceReload(Playlists) - } else { - Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) - .show() - } - } - } else { - playlistContainer.error = "Playlist is can't be empty" - } - } - .create() - .colorButtons() - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt index 7a548de4..1ee8953a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 code.name.monkey.retromusic.dialogs import android.app.Dialog import android.os.Bundle +import androidx.core.os.bundleOf import androidx.core.text.HtmlCompat import androidx.fragment.app.DialogFragment import code.name.monkey.retromusic.EXTRA_PLAYLIST import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.model.Playlist -import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class DeletePlaylistDialog : DialogFragment() { + private val libraryViewModel by sharedViewModel() + + 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/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt deleted file mode 100644 index 1888d287..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteRetroPlaylist.kt +++ /dev/null @@ -1,69 +0,0 @@ -package code.name.monkey.retromusic.dialogs - -import android.app.Dialog -import android.os.Bundle -import androidx.core.os.bundleOf -import androidx.core.text.HtmlCompat -import androidx.fragment.app.DialogFragment -import code.name.monkey.retromusic.EXTRA_PLAYLIST -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.extensions.colorButtons -import code.name.monkey.retromusic.extensions.extraNotNull -import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.fragments.LibraryViewModel -import code.name.monkey.retromusic.fragments.ReloadType -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -class DeleteRetroPlaylist : DialogFragment() { - - private val libraryViewModel by sharedViewModel() - - companion object { - - fun create(playlist: PlaylistEntity): DeleteRetroPlaylist { - val list = mutableListOf() - list.add(playlist) - return create(list) - } - - fun create(playlists: List): DeleteRetroPlaylist { - return DeleteRetroPlaylist().apply { - arguments = bundleOf(EXTRA_PLAYLIST to playlists) - } - } - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val playlists = extraNotNull>(EXTRA_PLAYLIST).value - val title: Int - val message: CharSequence - //noinspection ConstantConditions - if (playlists.size > 1) { - title = R.string.delete_playlists_title - message = HtmlCompat.fromHtml( - String.format(getString(R.string.delete_x_playlists), playlists.size), - HtmlCompat.FROM_HTML_MODE_LEGACY - ) - } else { - title = R.string.delete_playlist_title - message = HtmlCompat.fromHtml( - String.format(getString(R.string.delete_playlist_x), playlists[0].playlistName), - HtmlCompat.FROM_HTML_MODE_LEGACY - ) - } - - return materialDialog(title) - .setTitle(title) - .setMessage(message) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(R.string.action_delete) { _, _ -> - libraryViewModel.deleteSongsFromPlaylist(playlists) - libraryViewModel.deleteRoomPlaylist(playlists) - libraryViewModel.forceReload(ReloadType.Playlists) - } - .create() - .colorButtons() - } - -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt deleted file mode 100644 index dc193398..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.dialogs - -import android.app.Dialog -import android.os.Bundle -import androidx.core.text.HtmlCompat -import androidx.fragment.app.DialogFragment -import code.name.monkey.retromusic.EXTRA_SONG -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.R.string -import code.name.monkey.retromusic.extensions.colorButtons -import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.model.PlaylistSong -import code.name.monkey.retromusic.util.PlaylistsUtil - -class RemoveFromPlaylistDialog : DialogFragment() { - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val songs = requireArguments().getParcelableArrayList(EXTRA_SONG) - - var title = 0 - var message: CharSequence = "" - if (songs != null) { - if (songs.size > 1) { - title = R.string.remove_songs_from_playlist_title - message = HtmlCompat.fromHtml( - String.format(getString(string.remove_x_songs_from_playlist), songs.size), - HtmlCompat.FROM_HTML_MODE_LEGACY - ) - } else { - title = R.string.remove_song_from_playlist_title - message = HtmlCompat.fromHtml( - String.format( - getString(string.remove_song_x_from_playlist), - songs[0].title - ), - HtmlCompat.FROM_HTML_MODE_LEGACY - ) - } - } - - return materialDialog(title) - .setMessage(message) - .setPositiveButton(R.string.remove_action) { _, _ -> - PlaylistsUtil.removeFromPlaylist( - requireContext(), - songs as MutableList - ) - } - .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/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt index 78912d2a..6aa6939a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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 code.name.monkey.retromusic.dialogs -import android.annotation.SuppressLint import android.app.Dialog import android.os.Bundle -import android.provider.MediaStore.Audio.Playlists.Members.PLAYLIST_ID import android.view.LayoutInflater +import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment -import code.name.monkey.appthemehelper.util.MaterialUtil +import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.ReloadType import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class RenamePlaylistDialog : DialogFragment() { + private val libraryViewModel by sharedViewModel() - @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/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt deleted file mode 100644 index 9c2601ad..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenameRetroPlaylistDialog.kt +++ /dev/null @@ -1,57 +0,0 @@ -package code.name.monkey.retromusic.dialogs - -import android.app.Dialog -import android.os.Bundle -import android.view.LayoutInflater -import androidx.core.os.bundleOf -import androidx.fragment.app.DialogFragment -import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.db.PlaylistEntity -import code.name.monkey.retromusic.extensions.accentColor -import code.name.monkey.retromusic.extensions.colorButtons -import code.name.monkey.retromusic.extensions.extraNotNull -import code.name.monkey.retromusic.extensions.materialDialog -import code.name.monkey.retromusic.fragments.LibraryViewModel -import code.name.monkey.retromusic.fragments.ReloadType -import com.google.android.material.textfield.TextInputEditText -import com.google.android.material.textfield.TextInputLayout -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -class RenameRetroPlaylistDialog : DialogFragment() { - - private val libraryViewModel by sharedViewModel() - - companion object { - fun create(playlistEntity: PlaylistEntity): RenameRetroPlaylistDialog { - return RenameRetroPlaylistDialog().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) - 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()) { - libraryViewModel.renameRoomPlaylist(playlistEntity.playListId, name) - libraryViewModel.forceReload(ReloadType.Playlists) - } else { - nameContainer.error = "Playlist name should'nt be empty" - } - } - .create() - .colorButtons() - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RetroSingleCheckedListAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RetroSingleCheckedListAdapter.kt deleted file mode 100644 index 789639e5..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RetroSingleCheckedListAdapter.kt +++ /dev/null @@ -1,11 +0,0 @@ -package code.name.monkey.retromusic.dialogs - -import android.content.Context -import android.widget.ArrayAdapter -import code.name.monkey.retromusic.R - -class RetroSingleCheckedListAdapter( - context: Context, - resource: Int = R.layout.dialog_list_item, - objects: MutableList -) : ArrayAdapter(context, resource, objects) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt new file mode 100644 index 00000000..b392f61b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt @@ -0,0 +1,4 @@ +package code.name.monkey.retromusic.dialogs + +class SavePlaylistDialog { +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 6919e2a4..c047f6c3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -24,7 +24,7 @@ import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.applyOutlineColor @@ -286,7 +286,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det lifecycleScope.launch(Dispatchers.IO) { val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { - AddToRetroPlaylist.create(playlists, songs) + AddToPlaylistDialog.create(playlists, songs) .show(childFragmentManager, "ADD_PLAYLIST") } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt index 2ef8f6db..f9db60bf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt @@ -21,7 +21,7 @@ import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.applyOutlineColor import code.name.monkey.retromusic.extensions.show @@ -229,7 +229,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d lifecycleScope.launch(Dispatchers.IO) { val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { - AddToRetroPlaylist.create(playlists, songs) + AddToPlaylistDialog.create(playlists, songs) .show(childFragmentManager, "ADD_PLAYLIST") } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index c08d903d..59875b4f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -76,7 +76,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme lifecycleScope.launch(IO) { val playlists = get().fetchPlaylists() withContext(Main) { - AddToRetroPlaylist.create(playlists, song) + AddToPlaylistDialog.create(playlists, song) .show(childFragmentManager, "ADD_PLAYLIST") } } @@ -87,7 +87,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme return true } R.id.action_save_playing_queue -> { - CreateRetroPlaylist.create(ArrayList(MusicPlayerRemote.playingQueue)) + CreatePlaylistDialog.create(ArrayList(MusicPlayerRemote.playingQueue)) .show(childFragmentManager, "ADD_TO_PLAYLIST") return true } @@ -209,13 +209,11 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme withContext(Main) { val icon = if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border - val drawable: Drawable? = - - RetroUtil.getTintedVectorDrawable( - requireContext(), - icon, - toolbarIconColor() - ) + val drawable: Drawable? = RetroUtil.getTintedVectorDrawable( + requireContext(), + icon, + toolbarIconColor() + ) if (playerToolbar() != null) { playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite) ?.setIcon(drawable)?.title = diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index b47e3e50..c856c062 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -9,7 +9,7 @@ import androidx.navigation.ui.NavigationUI import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.CreateRetroPlaylist +import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment @@ -34,7 +34,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { addPlaylist.apply { accentColor() setOnClickListener { - CreateRetroPlaylist().show(childFragmentManager, "ShowCreatePlaylistDialog") + CreatePlaylistDialog().show(childFragmentManager, "ShowCreatePlaylistDialog") } } setupNavigationController() diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt index c5a6af03..8f40adb5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt @@ -17,7 +17,7 @@ package code.name.monkey.retromusic.helper.menu import android.view.MenuItem import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Song @@ -47,7 +47,7 @@ object GenreMenuHelper : KoinComponent { CoroutineScope(Dispatchers.IO).launch { val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { - AddToRetroPlaylist.create(playlists, getGenreSongs(genre)) + AddToPlaylistDialog.create(playlists, getGenreSongs(genre)) .show(activity.supportFragmentManager, "ADD_PLAYLIST") } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt index 6dccf62f..1640fe4e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt @@ -23,9 +23,9 @@ import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.toSongs -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist -import code.name.monkey.retromusic.dialogs.DeleteRetroPlaylist -import code.name.monkey.retromusic.dialogs.RenameRetroPlaylistDialog +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog +import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog +import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.misc.WeakContextAsyncTask import code.name.monkey.retromusic.model.AbsCustomPlaylist @@ -60,7 +60,7 @@ object PlaylistMenuHelper : KoinComponent { CoroutineScope(Dispatchers.IO).launch { val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { - AddToRetroPlaylist.create(playlists, playlistWithSongs.songs.toSongs()) + AddToPlaylistDialog.create(playlists, playlistWithSongs.songs.toSongs()) .show(activity.supportFragmentManager, "ADD_PLAYLIST") } } @@ -71,17 +71,18 @@ object PlaylistMenuHelper : KoinComponent { return true } R.id.action_rename_playlist -> { - RenameRetroPlaylistDialog.create(playlistWithSongs.playlistEntity) + RenamePlaylistDialog.create(playlistWithSongs.playlistEntity) .show(activity.supportFragmentManager, "RENAME_PLAYLIST") return true } R.id.action_delete_playlist -> { - DeleteRetroPlaylist.create(playlistWithSongs.playlistEntity) + DeletePlaylistDialog.create(playlistWithSongs.playlistEntity) .show(activity.supportFragmentManager, "DELETE_PLAYLIST") return true } R.id.action_save_playlist -> { //SavePlaylistAsyncTask(activity).execute(playlistWithSongs.songs.toSongs()) + Toast.makeText(activity, "Coming soon", Toast.LENGTH_SHORT).show() return true } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt index 58182efb..07e590a6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt @@ -26,7 +26,7 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.dialogs.SongDetailDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -73,7 +73,7 @@ object SongMenuHelper : KoinComponent { CoroutineScope(Dispatchers.IO).launch { val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { - AddToRetroPlaylist.create(playlists, song) + AddToPlaylistDialog.create(playlists, song) .show(activity.supportFragmentManager, "ADD_PLAYLIST") } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt index 243d22fd..912e3c81 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongsMenuHelper.kt @@ -16,7 +16,7 @@ package code.name.monkey.retromusic.helper.menu import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist +import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song @@ -47,7 +47,7 @@ object SongsMenuHelper : KoinComponent { CoroutineScope(Dispatchers.IO).launch { val playlists = get().fetchPlaylists() withContext(Dispatchers.Main) { - AddToRetroPlaylist.create(playlists, songs) + AddToPlaylistDialog.create(playlists, songs) .show(activity.supportFragmentManager, "ADD_PLAYLIST") } } From 6e8ff6ab7179a0c57e661011b957cbbd8507fed4 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 00:21:44 +0530 Subject: [PATCH 33/46] =?UTF-8?q?Add=20save=20playlist=20=F0=9F=92=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monkey/retromusic/db/SongExtension.kt | 8 ++- .../retromusic/dialogs/AddToPlaylistDialog.kt | 29 +++++----- .../retromusic/dialogs/SavePlaylistDialog.kt | 53 ++++++++++++++++++- .../monkey/retromusic/helper/M3UWriter.kt | 24 +++++++++ .../helper/menu/PlaylistMenuHelper.kt | 44 ++------------- .../monkey/retromusic/util/PlaylistsUtil.java | 5 ++ app/src/main/res/layout/loading.xml | 2 +- 7 files changed, 105 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt index 617e3a71..d5f009e0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongExtension.kt @@ -86,4 +86,10 @@ fun Song.toPlayCount(): PlayCountEntity { System.currentTimeMillis(), 1 ) -} \ No newline at end of file +} + +fun List.toSongsEntity(playlistEntity: PlaylistEntity): List { + return map { + it.toSongEntity(playlistEntity.playListId) + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt index 4faa019a..53acaa25 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt @@ -3,29 +3,30 @@ package code.name.monkey.retromusic.dialogs import android.app.Dialog import android.os.Bundle import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.EXTRA_PLAYLISTS import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.SongEntity +import code.name.monkey.retromusic.db.toSongsEntity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.model.Song -import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.koin.androidx.viewmodel.ext.android.sharedViewModel -class AddToPlaylistDialog : BottomSheetDialogFragment() { +class AddToPlaylistDialog : DialogFragment() { private val libraryViewModel by sharedViewModel() companion object { fun create(playlistEntities: List, song: Song): AddToPlaylistDialog { - val list = mutableListOf() + val list: MutableList = mutableListOf() list.add(song) return create(playlistEntities, list) } @@ -41,12 +42,13 @@ class AddToPlaylistDialog : BottomSheetDialogFragment() { } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val playlistEntities = extraNotNull>(EXTRA_PLAYLISTS).value - val songs = extraNotNull>(EXTRA_SONG).value - val playlistNames = mutableListOf() + 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 playlistEntities) { - playlistNames.add(p.playlistName) + for (entity: PlaylistEntity in playlistEntities) { + playlistNames.add(entity.playlistName) } return materialDialog(R.string.add_playlist_title) .setItems(playlistNames.toTypedArray()) { _, which -> @@ -55,7 +57,8 @@ class AddToPlaylistDialog : BottomSheetDialogFragment() { .show(requireActivity().supportFragmentManager, "Dialog") } else { lifecycleScope.launch(Dispatchers.IO) { - val songEntities = songs.toSongEntity(playlistEntities[which - 1]) + val songEntities: List = + songs.toSongsEntity(playlistEntities[which - 1]) libraryViewModel.insertSongs(songEntities) libraryViewModel.forceReload(Playlists) } @@ -64,10 +67,4 @@ class AddToPlaylistDialog : BottomSheetDialogFragment() { } .create().colorButtons() } -} - -private fun List.toSongEntity(playlistEntity: PlaylistEntity): List { - return map { - it.toSongEntity(playlistEntity.playListId) - } -} +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt index b392f61b..dd92a9a2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt @@ -1,4 +1,55 @@ package code.name.monkey.retromusic.dialogs -class SavePlaylistDialog { +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/code/name/monkey/retromusic/helper/M3UWriter.kt b/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt index daf0102a..35e87d80 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt @@ -13,7 +13,10 @@ */ package code.name.monkey.retromusic.helper +import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.model.Playlist +import code.name.monkey.retromusic.model.Song import java.io.BufferedWriter import java.io.File import java.io.FileWriter @@ -42,4 +45,25 @@ object M3UWriter : M3UConstants { } return file } + + @JvmStatic + @Throws(IOException::class) + fun writeIO(dir: File, playlistWithSongs: PlaylistWithSongs): File { + if (!dir.exists()) dir.mkdirs() + val fileName = "${playlistWithSongs.playlistEntity.playlistName}.${M3UConstants.EXTENSION}" + val file = File(dir, fileName) + val songs: List = playlistWithSongs.songs.toSongs() + if (songs.isNotEmpty()) { + val bufferedWriter = BufferedWriter(FileWriter(file)) + bufferedWriter.write(M3UConstants.HEADER) + songs.forEach { + bufferedWriter.newLine() + bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title) + bufferedWriter.newLine() + bufferedWriter.write(it.data) + } + bufferedWriter.close() + } + return file + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt index 1640fe4e..971193e0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt @@ -15,24 +15,17 @@ package code.name.monkey.retromusic.helper.menu -import android.content.Context import android.view.MenuItem -import android.widget.Toast import androidx.fragment.app.FragmentActivity -import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog +import code.name.monkey.retromusic.dialogs.SavePlaylistDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.misc.WeakContextAsyncTask -import code.name.monkey.retromusic.model.AbsCustomPlaylist -import code.name.monkey.retromusic.model.Playlist -import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository -import code.name.monkey.retromusic.util.PlaylistsUtil import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -81,42 +74,11 @@ object PlaylistMenuHelper : KoinComponent { return true } R.id.action_save_playlist -> { - //SavePlaylistAsyncTask(activity).execute(playlistWithSongs.songs.toSongs()) - Toast.makeText(activity, "Coming soon", Toast.LENGTH_SHORT).show() + SavePlaylistDialog.create(playlistWithSongs) + .show(activity.supportFragmentManager, "SavePlaylist") return true } } return false } - - private fun getPlaylistSongs( - playlist: Playlist - ): List { - return if (playlist is AbsCustomPlaylist) { - playlist.songs() - } else { - playlist.getSongs() - } - } - - private class SavePlaylistAsyncTask(context: Context) : - WeakContextAsyncTask(context) { - - override fun doInBackground(vararg params: Playlist): String { - return String.format( - App.getContext().getString( - R.string - .saved_playlist_to - ), PlaylistsUtil.savePlaylist(App.getContext(), params[0]) - ) - } - - override fun onPostExecute(string: String) { - super.onPostExecute(string) - val context = context - if (context != null) { - Toast.makeText(context, string, Toast.LENGTH_LONG).show() - } - } - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java index c7b32229..cc2dad88 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.db.PlaylistWithSongs; import code.name.monkey.retromusic.helper.M3UWriter; import code.name.monkey.retromusic.model.Playlist; import code.name.monkey.retromusic.model.PlaylistSong; @@ -250,6 +251,10 @@ public class PlaylistsUtil { return M3UWriter.write(new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist); } + public static File savePlaylistWithSongs(Context context, PlaylistWithSongs playlist) throws IOException { + return M3UWriter.writeIO(new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist); + } + public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) { return playlistId != -1 && doesPlaylistExist(context, MediaStore.Audio.Playlists._ID + "=?", diff --git a/app/src/main/res/layout/loading.xml b/app/src/main/res/layout/loading.xml index 54c6d3c1..6ae87157 100644 --- a/app/src/main/res/layout/loading.xml +++ b/app/src/main/res/layout/loading.xml @@ -20,7 +20,7 @@ android:padding="14dp"> From 51d2c17ad72376ed85496e5834c3abb5b498a53d Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 00:41:48 +0530 Subject: [PATCH 34/46] Create playlist added to menu --- .../dialogs/CreatePlaylistDialog.kt | 5 ++--- .../retromusic/dialogs/ImportPlaylist.kt | 7 +++++++ .../fragments/library/LibraryFragment.kt | 18 ++++------------ .../fragments/playlists/PlaylistsFragment.kt | 21 +++++++++++++++---- app/src/main/res/layout/fragment_library.xml | 12 ----------- 5 files changed, 30 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt index a2c6eedb..ff26fb8a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt @@ -12,7 +12,7 @@ import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.extensions.colorButtons -import code.name.monkey.retromusic.extensions.extraNotNull +import code.name.monkey.retromusic.extensions.extra import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.Playlists @@ -46,7 +46,7 @@ class CreatePlaylistDialog : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null) - val songs = extraNotNull>(EXTRA_SONG).value + val songs: List = extra>(EXTRA_SONG).value ?: emptyList() val playlistView: TextInputEditText = view.actionNewPlaylist val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer return materialDialog(R.string.new_playlist_title) @@ -59,7 +59,6 @@ class CreatePlaylistDialog : DialogFragment() { lifecycleScope.launch(Dispatchers.IO) { if (repository.checkPlaylistExists(playlistName).isEmpty()) { val playlistId = repository.createPlaylist(PlaylistEntity(playlistName)) - println(playlistId) repository.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) libraryViewModel.forceReload(Playlists) } else { diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt new file mode 100644 index 00000000..9f46e917 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt @@ -0,0 +1,7 @@ +package code.name.monkey.retromusic.dialogs + +import androidx.fragment.app.DialogFragment + +class ImportPlaylist : DialogFragment() { + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index c856c062..ef41cdf3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -10,7 +10,6 @@ import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackg import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog -import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import kotlinx.android.synthetic.main.fragment_library.* @@ -31,25 +30,12 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { navOptions ) } - addPlaylist.apply { - accentColor() - setOnClickListener { - CreatePlaylistDialog().show(childFragmentManager, "ShowCreatePlaylistDialog") - } - } setupNavigationController() } private fun setupNavigationController() { val navController = findNavController(R.id.fragment_container) NavigationUI.setupWithNavController(mainActivity.getBottomNavigationView(), navController) - navController.addOnDestinationChangedListener { _, destination, _ -> - if (destination.id == R.id.action_playlist) { - addPlaylist.show() - } else { - addPlaylist.hide() - } - } } override fun onPrepareOptionsMenu(menu: Menu) { @@ -75,6 +61,10 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { null, navOptions ) + R.id.action_add_to_playlist -> CreatePlaylistDialog().show( + childFragmentManager, + "ShowCreatePlaylistDialog" + ) } return super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 552be54f..8d9b639e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -1,12 +1,17 @@ package code.name.monkey.retromusic.fragments.playlists import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import android.view.View import androidx.lifecycle.Observer import androidx.recyclerview.widget.GridLayoutManager +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment +import kotlinx.android.synthetic.main.fragment_library.* class PlaylistsFragment : AbsRecyclerViewFragment() { @@ -36,10 +41,18 @@ class PlaylistsFragment : AbsRecyclerViewFragment - - Date: Sun, 6 Sep 2020 01:43:45 +0530 Subject: [PATCH 35/46] =?UTF-8?q?=E2=AC=87=EF=B8=8F=20Import=20legacy=20pl?= =?UTF-8?q?aylists?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../retromusic/activities/MainActivity.kt | 15 +-- .../adapter/playlist/PlaylistAdapter.kt | 52 +++----- .../dialogs/CreatePlaylistDialog.kt | 10 +- .../retromusic/dialogs/ImportPlaylist.kt | 7 -- .../dialogs/ImportPlaylistFragment.kt | 111 ++++++++++++++++++ .../retromusic/fragments/LibraryViewModel.kt | 18 +++ .../fragments/library/LibraryFragment.kt | 3 +- .../fragments/playlists/PlaylistsFragment.kt | 10 +- .../retromusic/repository/Repository.kt | 4 +- app/src/main/res/layout/item_list.xml | 1 + .../main/res/layout/item_list_no_image.xml | 1 + app/src/main/res/navigation/library_graph.xml | 7 +- app/src/main/res/values/strings.xml | 1 + 13 files changed, 175 insertions(+), 65 deletions(-) delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index c772c320..ff855947 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -3,6 +3,7 @@ package code.name.monkey.retromusic.activities import android.content.Intent import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener +import android.net.Uri import android.os.Bundle import android.provider.MediaStore import android.view.View @@ -95,8 +96,8 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis private fun handlePlaybackIntent(intent: Intent) { lifecycleScope.launch(IO) { - val uri = intent.data - val mimeType = intent.type + 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 @@ -113,9 +114,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis MusicPlayerRemote.playFromUri(uri) handled = true } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) { - val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt() + val id: Int = parseIdFromIntent(intent, "playlistId", "playlist").toInt() if (id >= 0) { - val position = intent.getIntExtra("position", 0) + val position: Int = intent.getIntExtra("position", 0) val songs: List = PlaylistSongsLoader.getPlaylistSongList(this@MainActivity, id) MusicPlayerRemote.openQueue(songs, position, true) @@ -124,7 +125,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) { val id = parseIdFromIntent(intent, "albumId", "album").toInt() if (id >= 0) { - val position = intent.getIntExtra("position", 0) + val position: Int = intent.getIntExtra("position", 0) MusicPlayerRemote.openQueue( libraryViewModel.albumById(id).songs!!, position, @@ -133,9 +134,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis handled = true } } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { - val id = parseIdFromIntent(intent, "artistId", "artist").toInt() + val id: Int = parseIdFromIntent(intent, "artistId", "artist").toInt() if (id >= 0) { - val position = intent.getIntExtra("position", 0) + val position: Int = intent.getIntExtra("position", 0) MusicPlayerRemote.openQueue( libraryViewModel.artistById(id).songs, position, diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index 17f0d78d..1d21b803 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.SongEntity +import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper @@ -33,7 +34,6 @@ import code.name.monkey.retromusic.repository.PlaylistSongsLoader import code.name.monkey.retromusic.util.AutoGeneratedPlaylistBitmap import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.RetroColorUtil -import java.util.* class PlaylistAdapter( private val activity: FragmentActivity, @@ -73,7 +73,7 @@ class PlaylistAdapter( } private fun getPlaylistText(playlist: PlaylistWithSongs): String { - return MusicUtil.playlistInfoString(activity, getSongs(playlist)) + return MusicUtil.getPlaylistInfoString(activity, playlist.songs.toSongs()) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -81,7 +81,7 @@ class PlaylistAdapter( holder.itemView.isActivated = isChecked(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() @@ -91,20 +91,11 @@ class PlaylistAdapter( //PlaylistBitmapLoader(this, holder, playlist).execute() } - private fun getIconRes(playlist: PlaylistWithSongs): 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) - ) - } - + 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 @@ -129,28 +120,17 @@ class PlaylistAdapter( } private fun getSongList(playlists: List): List { - val songs = ArrayList() - /* for (playlist in playlists) { - songs.addAll(playlist.songs) - if (playlist is AbsCustomPlaylist) { - songs.addAll(playlist.songs()) - } else { - songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id)) - } - }*/ + val songs = mutableListOf() + playlists.forEach { + songs.addAll(it.songs.toSongs()) + } return songs } - private fun getSongs(playlist: PlaylistWithSongs): List { - val songs = ArrayList() - songs.addAll(playlist.songs) - /*if (playlist is AbsSmartPlaylist) { - songs.addAll(playlist.songs()) - } else { - songs.addAll(playlist.getSongs()) - }*/ - return songs - } + private fun getSongs(playlist: PlaylistWithSongs): List = + mutableListOf().apply { + addAll(playlist.songs) + } inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { init { diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt index ff26fb8a..db5158ae 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt @@ -17,17 +17,14 @@ import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.repository.RealRepository 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.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel class CreatePlaylistDialog : DialogFragment() { - private val repository by inject() private val libraryViewModel by sharedViewModel() companion object { @@ -57,9 +54,10 @@ class CreatePlaylistDialog : DialogFragment() { val playlistName = playlistView.text.toString() if (!TextUtils.isEmpty(playlistName)) { lifecycleScope.launch(Dispatchers.IO) { - if (repository.checkPlaylistExists(playlistName).isEmpty()) { - val playlistId = repository.createPlaylist(PlaylistEntity(playlistName)) - repository.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) + if (libraryViewModel.checkPlaylistExists(playlistName).isEmpty()) { + val playlistId: Long = + libraryViewModel.createPlaylist(PlaylistEntity(playlistName)) + libraryViewModel.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) }) libraryViewModel.forceReload(Playlists) } else { Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt deleted file mode 100644 index 9f46e917..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylist.kt +++ /dev/null @@ -1,7 +0,0 @@ -package code.name.monkey.retromusic.dialogs - -import androidx.fragment.app.DialogFragment - -class ImportPlaylist : DialogFragment() { - -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt new file mode 100644 index 00000000..91452bff --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt @@ -0,0 +1,111 @@ +package code.name.monkey.retromusic.dialogs + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.fragments.ReloadType.Playlists +import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment +import code.name.monkey.retromusic.model.Playlist +import code.name.monkey.retromusic.util.MusicUtil +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.launch + +class ImportPlaylistFragment : + AbsRecyclerViewFragment(), PlaylistClickListener { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + libraryViewModel.getLegacyPlaylist().observe(viewLifecycleOwner, Observer { + if (it.isNotEmpty()) + adapter?.swapData(it) + else + adapter?.swapData(listOf()) + }) + } + + override fun createLayoutManager(): LinearLayoutManager { + return LinearLayoutManager(requireContext()) + } + + override fun createAdapter(): LegacyPlaylistAdapter { + return LegacyPlaylistAdapter( + requireActivity(), + ArrayList(), + R.layout.item_list_no_image, + this + ) + } + + override fun onPlaylistClick(playlist: Playlist) { + Toast.makeText(requireContext(), "Importing ${playlist.name}", Toast.LENGTH_LONG).show() + lifecycleScope.launch(IO) { + if (playlist.name.isNotEmpty()) { + if (libraryViewModel.checkPlaylistExists(playlist.name).isEmpty()) { + val playlistId: Long = + libraryViewModel.createPlaylist(PlaylistEntity(playlist.name)) + libraryViewModel.insertSongs(playlist.getSongs().map { + it.toSongEntity(playlistId.toInt()) + }) + libraryViewModel.forceReload(Playlists) + } else { + Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) + .show() + } + } + } + } +} + +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/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index 3392ccb8..cdee7637 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -24,6 +24,7 @@ class LibraryViewModel( private val songs = MutableLiveData>() private val artists = MutableLiveData>() private val playlists = MutableLiveData>() + private val legacyPlaylists = MutableLiveData>() private val genres = MutableLiveData>() private val home = MutableLiveData>() @@ -58,6 +59,11 @@ class LibraryViewModel( return playlists } + fun getLegacyPlaylist(): LiveData> { + fetchLegacyPlaylist() + return legacyPlaylists + } + fun getGenre(): LiveData> { fetchGenres() return genres @@ -92,6 +98,12 @@ class LibraryViewModel( } } + private fun fetchLegacyPlaylist() { + viewModelScope.launch(IO) { + legacyPlaylists.postValue(repository.fetchLegacyPlaylist()) + } + } + private fun fetchGenres() { viewModelScope.launch(IO) { genres.postValue(repository.fetchGenres()) @@ -186,6 +198,12 @@ class LibraryViewModel( 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) + } enum class ReloadType { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index ef41cdf3..f49876f3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -61,7 +61,8 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { null, navOptions ) - R.id.action_add_to_playlist -> CreatePlaylistDialog().show( + R.id.action_import_playlist -> findNavController(R.id.fragment_container).navigate(R.id.action_import_playlist) + R.id.action_add_to_playlist -> CreatePlaylistDialog.create(emptyList()).show( childFragmentManager, "ShowCreatePlaylistDialog" ) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 8d9b639e..95f849a2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -6,14 +6,14 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.lifecycle.Observer -import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment import kotlinx.android.synthetic.main.fragment_library.* -class PlaylistsFragment : AbsRecyclerViewFragment() { +class PlaylistsFragment : AbsRecyclerViewFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -28,8 +28,8 @@ class PlaylistsFragment : AbsRecyclerViewFragment suspend fun fetchArtists(): List suspend fun albumArtists(): List - suspend fun allPlaylists(): List + suspend fun fetchLegacyPlaylist(): List suspend fun fetchGenres(): List suspend fun search(query: String?): MutableList suspend fun getPlaylistSongs(playlist: Playlist): List @@ -125,7 +125,7 @@ class RealRepository( override suspend fun topAlbums(): List = topPlayedRepository.topAlbums() - override suspend fun allPlaylists(): List = playlistRepository.playlists() + override suspend fun fetchLegacyPlaylist(): List = playlistRepository.playlists() override suspend fun fetchGenres(): List = genreRepository.genres() diff --git a/app/src/main/res/layout/item_list.xml b/app/src/main/res/layout/item_list.xml index 30a61347..fac82e1e 100755 --- a/app/src/main/res/layout/item_list.xml +++ b/app/src/main/res/layout/item_list.xml @@ -89,6 +89,7 @@ android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="1" + android:textAppearance="@style/TextViewBody2" android:textColor="?android:attr/textColorSecondary" tools:text="@tools:sample/full_names" /> diff --git a/app/src/main/res/layout/item_list_no_image.xml b/app/src/main/res/layout/item_list_no_image.xml index 4e28bbf8..456468b2 100644 --- a/app/src/main/res/layout/item_list_no_image.xml +++ b/app/src/main/res/layout/item_list_no_image.xml @@ -40,6 +40,7 @@ android:layout_height="wrap_content" android:singleLine="true" android:textAppearance="@style/TextViewBody2" + android:textColor="?android:textColorSecondary" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/title" diff --git a/app/src/main/res/navigation/library_graph.xml b/app/src/main/res/navigation/library_graph.xml index d95d705c..e6c85b8f 100644 --- a/app/src/main/res/navigation/library_graph.xml +++ b/app/src/main/res/navigation/library_graph.xml @@ -44,6 +44,11 @@ android:id="@+id/action_home" android:name="code.name.monkey.retromusic.fragments.home.HomeFragment" android:label="" - tools:layout="@layout/fragment_banner_home"/> + tools:layout="@layout/fragment_banner_home" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e69401b9..88412e41 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -884,4 +884,5 @@ Hello blank fragment Done Ok + Import playlist From 47d533f9edd43c9103f243a9164190308f087123 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 01:44:04 +0530 Subject: [PATCH 36/46] Update ImportPlaylistFragment.kt --- .../{dialogs => fragments/playlists}/ImportPlaylistFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/src/main/java/code/name/monkey/retromusic/{dialogs => fragments/playlists}/ImportPlaylistFragment.kt (98%) diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt similarity index 98% rename from app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt rename to app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt index 91452bff..d98fe95e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt @@ -1,4 +1,4 @@ -package code.name.monkey.retromusic.dialogs +package code.name.monkey.retromusic.fragments.playlists import android.os.Bundle import android.view.LayoutInflater From e8549513bd33f340249b25bf0d6153c86e68edc4 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 04:00:50 +0530 Subject: [PATCH 37/46] Hot fix --- .../fragments/playlists/ImportPlaylistFragment.kt | 11 ++++++++--- app/src/main/res/navigation/library_graph.xml | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt index d98fe95e..ad9e17c3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt @@ -1,9 +1,7 @@ package code.name.monkey.retromusic.fragments.playlists import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import android.view.* import android.widget.Toast import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Observer @@ -64,6 +62,13 @@ class ImportPlaylistFragment : } } } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + menu.removeItem(R.id.action_grid_size) + menu.removeItem(R.id.action_layout_type) + menu.removeItem(R.id.action_sort_order) + super.onCreateOptionsMenu(menu, inflater) + } } class LegacyPlaylistAdapter( diff --git a/app/src/main/res/navigation/library_graph.xml b/app/src/main/res/navigation/library_graph.xml index e6c85b8f..fca6df57 100644 --- a/app/src/main/res/navigation/library_graph.xml +++ b/app/src/main/res/navigation/library_graph.xml @@ -48,7 +48,7 @@ \ No newline at end of file From 521189060790bb99ef519056342840315991677b Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 12:48:47 +0530 Subject: [PATCH 38/46] Fix Album & Artist crash when no network --- .../fragments/albums/AlbumDetailsFragment.kt | 32 ++++++---- .../fragments/albums/AlbumDetailsViewModel.kt | 58 +++++-------------- .../artists/ArtistDetailsFragment.kt | 15 +++-- .../artists/ArtistDetailsViewModel.kt | 42 +++++--------- .../monkey/retromusic/{ => network}/Result.kt | 2 +- .../retromusic/repository/Repository.kt | 25 ++++++-- 6 files changed, 83 insertions(+), 91 deletions(-) rename app/src/main/java/code/name/monkey/retromusic/{ => network}/Result.kt (94%) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index c047f6c3..2dfc5101 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -38,6 +38,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Artist +import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.MusicUtil @@ -83,15 +84,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det 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) @@ -172,8 +165,25 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det } loadAlbumCover(album) simpleSongAdapter.swapDataSet(album.songs) - detailsViewModel.loadArtist(album.artistId) - detailsViewModel.loadAlbumInfo(album) + detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer { + loadArtistImage(it) + }) + /*detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer { + moreAlbums(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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt index f698f882..3311046e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt @@ -1,70 +1,44 @@ package code.name.monkey.retromusic.fragments.albums -import androidx.lifecycle.* +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.liveData import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Artist +import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.repository.RealRepository -import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.async -import kotlinx.coroutines.launch class AlbumDetailsViewModel( private val realRepository: RealRepository, private val albumId: Int ) : ViewModel(), MusicServiceEventListener { - private val _album = MutableLiveData() - private val _artist = MutableLiveData() - private val _lastFmAlbum = MutableLiveData() - private val _moreAlbums = MutableLiveData>() - fun getAlbum(): LiveData = liveData(IO) { val album = realRepository.albumByIdAsync(albumId) emit(album) } - fun getArtist(): LiveData = _artist - fun getAlbumInfo(): LiveData = _lastFmAlbum - fun getMoreAlbums(): LiveData> = _moreAlbums - - init { - loadAlbumDetails() - } - - fun getAlbum2() = liveData(context = viewModelScope.coroutineContext + IO) { - val album = realRepository.albumByIdAsync(albumId) - emit(album) - } - - private fun loadAlbumDetails() = viewModelScope.launch(IO) { - val album = loadAlbumAsync.await() ?: throw NullPointerException("Album couldn't found") - _album.postValue(album) - } - - fun loadAlbumInfo(album: Album) = viewModelScope.launch(IO) { - val lastFmAlbum = realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-") - _lastFmAlbum.postValue(lastFmAlbum) - } - - fun loadArtist(artistId: Int) = viewModelScope.launch(IO) { + fun getArtist(artistId: Int): LiveData = liveData(IO) { val artist = realRepository.artistById(artistId) - _artist.postValue(artist) - - artist.albums?.filter { item -> item.id != albumId }?.let { albums -> - if (albums.isNotEmpty()) _moreAlbums.postValue(albums) - } + emit(artist) } - private val loadAlbumAsync: Deferred - get() = viewModelScope.async(IO) { - realRepository.albumByIdAsync(albumId) + fun getAlbumInfo(album: Album): LiveData> = liveData { + emit(Result.Loading) + emit( realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-")) + } + + fun getMoreAlbums(artist: Artist): LiveData> = liveData(IO) { + artist.albums?.filter { item -> item.id != albumId }?.let { albums -> + if (albums.isNotEmpty()) emit(albums) } + } override fun onMediaStoreChanged() { - loadAlbumDetails() + } override fun onServiceConnected() {} diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt index f9db60bf..91743de4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt @@ -32,6 +32,7 @@ import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.SingleColorTarget import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Artist +import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.model.LastFmArtist import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.util.CustomArtistImageUtil @@ -77,9 +78,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d showArtist(it) startPostponedEnterTransition() }) - detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer { - artistInfo(it) - }) + playAction.apply { setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) } @@ -140,6 +139,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( @@ -148,7 +148,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?) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt index f2ee5fe6..89039735 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt @@ -1,51 +1,37 @@ package code.name.monkey.retromusic.fragments.artists import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.liveData import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.Artist +import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.model.LastFmArtist import code.name.monkey.retromusic.repository.RealRepository -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.launch +import kotlinx.coroutines.Dispatchers.IO class ArtistDetailsViewModel( private val realRepository: RealRepository, private val artistId: Int ) : 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/code/name/monkey/retromusic/Result.kt b/app/src/main/java/code/name/monkey/retromusic/network/Result.kt similarity index 94% rename from app/src/main/java/code/name/monkey/retromusic/Result.kt rename to app/src/main/java/code/name/monkey/retromusic/network/Result.kt index 4c241a14..05211fd3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Result.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/Result.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package code.name.monkey.retromusic +package code.name.monkey.retromusic.network /** * Generic class that holds the network state diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 06478f49..dcd94ff5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -21,6 +21,7 @@ import code.name.monkey.retromusic.db.* import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService +import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.network.model.LastFmArtist import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -48,8 +49,8 @@ interface Repository { suspend fun search(query: String?): MutableList suspend fun getPlaylistSongs(playlist: Playlist): List suspend fun getGenre(genreId: Int): List - suspend fun artistInfo(name: String, lang: String?, cache: String?): LastFmArtist - suspend fun albumInfo(artist: String, album: String): LastFmAlbum + suspend fun artistInfo(name: String, lang: String?, cache: String?): Result + suspend fun albumInfo(artist: String, album: String): Result suspend fun artistById(artistId: Int): Artist suspend fun recentArtists(): List suspend fun topArtists(): List @@ -110,7 +111,9 @@ class RealRepository( override suspend fun fetchAlbums(): List = albumRepository.albums() override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) + override fun albumById(albumId: Int): Album = albumRepository.album(albumId) + override suspend fun fetchArtists(): List = artistRepository.artists() override suspend fun albumArtists(): List = artistRepository.albumArtists() @@ -147,17 +150,29 @@ class RealRepository( name: String, lang: String?, cache: String? - ): LastFmArtist = lastFMService.artistInfo(name, lang, cache) + ): Result { + return try { + Result.Success(lastFMService.artistInfo(name, lang, cache)) + } catch (e: Exception) { + Result.Error + } + } override suspend fun albumInfo( artist: String, album: String - ): LastFmAlbum = lastFMService.albumInfo(artist, album) + ): Result { + return try { + val lastFmAlbum = lastFMService.albumInfo(artist, album) + Result.Success(lastFmAlbum) + } catch (e: Exception) { + Result.Error + } + } @ExperimentalCoroutinesApi override suspend fun homeSectionsFlow(): Flow>> { val homes = MutableStateFlow>>(value = Result.Loading) - println("homeSections:Loading") val homeSections = mutableListOf() val sections = listOf( topArtistsHome(), From 332c2dc69b77674e4185f9414082c54697bdf33d Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 16:17:06 +0530 Subject: [PATCH 39/46] Code refactor --- .../code/name/monkey/retromusic/MainModule.kt | 3 +++ .../name/monkey/retromusic/db/HistoryDao.kt | 26 +++++++++++++++++++ .../name/monkey/retromusic/db/PlaylistDao.kt | 11 -------- .../monkey/retromusic/db/RetroDatabase.kt | 1 + .../fragments/albums/AlbumDetailsFragment.kt | 7 ++--- .../artists/ArtistDetailsFragment.kt | 3 ++- .../retromusic/repository/Repository.kt | 10 ++++--- .../retromusic/repository/RoomRepository.kt | 26 ++++++++----------- 8 files changed, 54 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index aae0ed48..16741bc6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -55,6 +55,9 @@ private val roomModule = module { factory { get().playCountDao() } + factory { + get().historyDao() + } single { RealRoomRepository(get(), get(), get()) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt new file mode 100644 index 00000000..5ea731a2 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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: Int): 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/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index c3b7f801..0cfe2b8a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -45,17 +45,6 @@ interface PlaylistDao { @Delete suspend fun deleteSongsInPlaylist(songs: List) - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertSongInHistory(historyEntity: HistoryEntity) - - @Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1") - suspend fun isSongPresentInHistory(songId: Int): HistoryEntity? - - @Update - suspend fun updateHistorySong(historyEntity: HistoryEntity) - - @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC") - fun historySongs(): LiveData> @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") fun favoritesSongsLiveData(playlistId: Int): LiveData> diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt index 02cb6586..e9b99cca 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt @@ -12,4 +12,5 @@ abstract class RetroDatabase : RoomDatabase() { abstract fun playlistDao(): PlaylistDao abstract fun blackListStore(): BlackListStoreDao abstract fun playCountDao(): PlayCountDao + abstract fun historyDao(): HistoryDao } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 2dfc5101..05572748 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -168,9 +168,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer { loadArtistImage(it) }) - /*detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer { - moreAlbums(it) - })*/ + detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner, Observer { result -> when (result) { is Result.Loading -> { @@ -224,6 +222,9 @@ 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()) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt index 91743de4..877def06 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt @@ -18,6 +18,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter @@ -208,7 +209,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d override fun onAlbumClick(albumId: Int, view: View) { findNavController().navigate( R.id.albumDetailsFragment, - bundleOf("extra_album_id" to albumId), + bundleOf(EXTRA_ALBUM_ID to albumId), null, FragmentNavigatorExtras( view to getString(R.string.transition_album_art) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index dcd94ff5..f0af9ecc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -36,11 +36,12 @@ interface Repository { fun artistsFlow(): Flow>> fun playlistsFlow(): Flow>> fun genresFlow(): Flow>> - fun historySong(): LiveData> + fun historySong(): List fun favorites(): LiveData> + fun observableHistorySongs(): LiveData> + fun albumById(albumId: Int): Album suspend fun fetchAlbums(): List suspend fun albumByIdAsync(albumId: Int): Album - fun albumById(albumId: Int): Album suspend fun allSongs(): List suspend fun fetchArtists(): List suspend fun albumArtists(): List @@ -294,7 +295,10 @@ class RealRepository( override suspend fun blackListPaths(): List = roomRepository.blackListPaths() - override fun historySong(): LiveData> = + override fun observableHistorySongs(): LiveData> = + roomRepository.observableHistorySongs() + + override fun historySong(): List = roomRepository.historySongs() override fun favorites(): LiveData> = diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index a523883d..8267b36a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -7,9 +7,10 @@ import code.name.monkey.retromusic.model.Song interface RoomRepository { - fun historySongs(): LiveData> + fun historySongs(): List fun favoritePlaylistLiveData(favorite: String): LiveData> fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity) + fun observableHistorySongs(): LiveData> suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun checkPlaylistExists(playlistName: String): List suspend fun playlists(): List @@ -42,7 +43,8 @@ interface RoomRepository { class RealRoomRepository( private val playlistDao: PlaylistDao, private val blackListStoreDao: BlackListStoreDao, - private val playCountDao: PlayCountDao + private val playCountDao: PlayCountDao, + private val historyDao: HistoryDao ) : RoomRepository { @WorkerThread override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = @@ -59,12 +61,6 @@ class RealRoomRepository( override suspend fun playlistWithSongs(): List = playlistDao.playlistsWithSongs() - /* val tempList = ArrayList(songs) - val existingSongs = songs.map { - playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId) - }.first() - println("Existing ${existingSongs.size}") - tempList.removeAll(existingSongs)*/ @WorkerThread override suspend fun insertSongs(songs: List) = playlistDao.insertSongsToPlaylist(songs) @@ -96,7 +92,6 @@ class RealRoomRepository( } } - override suspend fun isFavoriteSong(songEntity: SongEntity): List = playlistDao.isSongExistsInPlaylist( songEntity.playlistCreatorId, @@ -107,17 +102,18 @@ class RealRoomRepository( playlistDao.removeSongFromPlaylist(songEntity.playlistCreatorId, songEntity.id) override suspend fun addSongToHistory(currentSong: Song) = - playlistDao.insertSongInHistory(currentSong.toHistoryEntity(System.currentTimeMillis())) + historyDao.insertSongInHistory(currentSong.toHistoryEntity(System.currentTimeMillis())) override suspend fun songPresentInHistory(song: Song): HistoryEntity? = - playlistDao.isSongPresentInHistory(song.id) + historyDao.isSongPresentInHistory(song.id) override suspend fun updateHistorySong(song: Song) = - playlistDao.updateHistorySong(song.toHistoryEntity(System.currentTimeMillis())) + historyDao.updateHistorySong(song.toHistoryEntity(System.currentTimeMillis())) - override fun historySongs(): LiveData> { - return playlistDao.historySongs() - } + override fun observableHistorySongs(): LiveData> = + historyDao.observableHistorySongs() + + override fun historySongs(): List = historyDao.historySongs() override fun favoritePlaylistLiveData(favorite: String): LiveData> = playlistDao.favoritesSongsLiveData( From 8eb7859f3098ce7d3cbd118c68c266f4228de328 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 16:33:24 +0530 Subject: [PATCH 40/46] Code refactor --- .../code/name/monkey/retromusic/MainModule.kt | 3 +- .../{DeezerApiService.kt => DeezerService.kt} | 4 +- .../fragments/DetailListFragment.kt | 2 +- .../glide/artistimage/ArtistImageLoader.kt | 18 +-- .../retromusic/network/RetrofitClient.kt | 104 +++++++++++------- .../retromusic/repository/Repository.kt | 47 ++++---- 6 files changed, 104 insertions(+), 74 deletions(-) rename app/src/main/java/code/name/monkey/retromusic/deezer/{DeezerApiService.kt => DeezerService.kt} (97%) diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index 16741bc6..8d0fafa8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -55,12 +55,13 @@ private val roomModule = module { factory { get().playCountDao() } + factory { get().historyDao() } single { - RealRoomRepository(get(), get(), get()) + RealRoomRepository(get(), get(), get(), get()) } bind RoomRepository::class } private val mainModule = module { diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt b/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt similarity index 97% rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt rename to app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt index fd107234..327f6848 100644 --- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt @@ -16,7 +16,7 @@ import java.util.* private const val BASE_QUERY_ARTIST = "search/artist" private const val BASE_URL = "https://api.deezer.com/" -interface DeezerApiService { +interface DeezerService { @GET("$BASE_QUERY_ARTIST&limit=1") fun getArtistImage( @@ -26,7 +26,7 @@ interface DeezerApiService { companion object { operator fun invoke( client: okhttp3.Call.Factory - ): DeezerApiService { + ): DeezerService { return Retrofit.Builder() .baseUrl(BASE_URL) .callFactory(client) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt index c71bcceb..6c7230a5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt @@ -104,7 +104,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de adapter = songAdapter layoutManager = linearLayoutManager() } - repository.historySong().observe(viewLifecycleOwner, Observer { + repository.observableHistorySongs().observe(viewLifecycleOwner, Observer { val songs = it.map { historyEntity -> historyEntity.toSong() } songAdapter.swapDataSet(songs) }) diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt index 398916ce..f9792c42 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt @@ -16,7 +16,7 @@ package code.name.monkey.retromusic.glide.artistimage import android.content.Context import code.name.monkey.retromusic.deezer.Data -import code.name.monkey.retromusic.deezer.DeezerApiService +import code.name.monkey.retromusic.deezer.DeezerService import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.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,7 +66,7 @@ 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()) @@ -106,7 +106,7 @@ class ArtistImageFetcher( class ArtistImageLoader( val context: Context, - private val deezerApiService: DeezerApiService, + private val deezerService: DeezerService, private val urlLoader: ModelLoader ) : StreamModelLoader { @@ -115,7 +115,7 @@ class ArtistImageLoader( width: Int, height: Int ): DataFetcher { - return ArtistImageFetcher(context, deezerApiService, model, urlLoader, width, height) + return ArtistImageFetcher(context, deezerService, model, urlLoader, width, height) } } @@ -123,7 +123,7 @@ class Factory( val context: Context ) : ModelLoaderFactory { - private var deezerApiService: DeezerApiService + private var deezerService: DeezerService private var okHttpFactory: OkHttpUrlLoader.Factory init { @@ -134,8 +134,8 @@ class Factory( .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .build() ) - deezerApiService = DeezerApiService.invoke( - DeezerApiService.createDefaultOkHttpClient(context) + deezerService = DeezerService.invoke( + DeezerService.createDefaultOkHttpClient(context) .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS) .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS) @@ -156,7 +156,7 @@ class Factory( ): ModelLoader { return ArtistImageLoader( context!!, - deezerApiService, + deezerService, okHttpFactory.build(context, factories) ) } diff --git a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt index affb3823..2121c812 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt @@ -1,12 +1,14 @@ package code.name.monkey.retromusic.network +import android.content.Context import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.Constants.AUDIO_SCROBBLER_URL +import code.name.monkey.retromusic.BuildConfig +import code.name.monkey.retromusic.deezer.DeezerService import com.google.gson.Gson import okhttp3.Cache -import okhttp3.ConnectionPool import okhttp3.Interceptor import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor import org.koin.dsl.module import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory @@ -16,50 +18,22 @@ import java.util.concurrent.TimeUnit private const val TIMEOUT: Long = 700 val networkModule = module { - factory { - provideHttpClient(get(), get()) - } - factory { - provideCacheControlInterceptor() - } + factory { provideDefaultCache() } factory { - provideLastFmService(get()) + provideOkHttp(get(), get()) } single { - providerRetrofit(get()) + provideLastFmRetrofit(get()) + } + single { + provideDeezerRest(get()) + } + single { + provideLastFmRest(get()) } -} - -fun provideLastFmService(retrofit: Retrofit): LastFMService = - retrofit.create(LastFMService::class.java) - -fun providerRetrofit(okHttpClient: OkHttpClient.Builder): Retrofit = Retrofit.Builder() - .baseUrl(AUDIO_SCROBBLER_URL) - .callFactory(okHttpClient.build()) - .addConverterFactory(GsonConverterFactory.create(Gson())) - .build() - -fun provideHttpClient( - cache: Cache, - interceptor: Interceptor -): OkHttpClient.Builder = OkHttpClient.Builder() - .connectionPool(ConnectionPool(0, 1, TimeUnit.NANOSECONDS)) - .retryOnConnectionFailure(true) - .connectTimeout(TIMEOUT, TimeUnit.MINUTES) - .writeTimeout(TIMEOUT, TimeUnit.MINUTES) - .readTimeout(TIMEOUT, TimeUnit.MINUTES) - .cache(cache) - .addInterceptor(interceptor) - - -fun provideCacheControlInterceptor(): Interceptor = Interceptor { chain: Interceptor.Chain -> - val modifiedRequest = chain.request().newBuilder() - .addHeader("Cache-Control", "max-age=31536000, max-stale=31536000") - .build() - chain.proceed(modifiedRequest) } fun provideDefaultCache(): Cache? { @@ -69,3 +43,55 @@ fun provideDefaultCache(): Cache? { } return null } + +fun logInterceptor(): Interceptor { + val loggingInterceptor = HttpLoggingInterceptor() + if (BuildConfig.DEBUG) { + loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY + } else { + // disable retrofit log on release + loggingInterceptor.level = HttpLoggingInterceptor.Level.NONE + } + return loggingInterceptor +} + +fun headerInterceptor(context: Context): Interceptor { + return Interceptor { + val original = it.request() + val request = original.newBuilder() + .header("User-Agent", context.packageName) + .addHeader("Content-Type", "application/json; charset=utf-8") + .method(original.method(), original.body()) + .build() + it.proceed(request) + } +} + +fun provideOkHttp(context: Context, cache: Cache): OkHttpClient { + return OkHttpClient.Builder() + .addNetworkInterceptor(logInterceptor()) + .addInterceptor(headerInterceptor(context)) + .connectTimeout(1, TimeUnit.SECONDS) + .readTimeout(1, TimeUnit.SECONDS) + .cache(cache) + .build() +} + +fun provideLastFmRetrofit(client: OkHttpClient): Retrofit { + return Retrofit.Builder() + .baseUrl("https://ws.audioscrobbler.com/2.0/") + .addConverterFactory(GsonConverterFactory.create(Gson())) + .callFactory { request -> client.newCall(request) } + .build() +} + +fun provideLastFmRest(retrofit: Retrofit): LastFMService { + return retrofit.create(LastFMService::class.java) +} + +fun provideDeezerRest(retrofit: Retrofit): DeezerService { + val newBuilder = retrofit.newBuilder() + .baseUrl("https://api.deezer.com/") + .build() + return newBuilder.create(DeezerService::class.java) +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index f0af9ecc..4dd683a1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService import code.name.monkey.retromusic.network.Result +import code.name.monkey.retromusic.network.Result.* import code.name.monkey.retromusic.network.model.LastFmAlbum import code.name.monkey.retromusic.network.model.LastFmArtist import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -153,9 +154,10 @@ class RealRepository( cache: String? ): Result { return try { - Result.Success(lastFMService.artistInfo(name, lang, cache)) + Success(lastFMService.artistInfo(name, lang, cache)) } catch (e: Exception) { - Result.Error + println(e) + Error } } @@ -165,15 +167,16 @@ class RealRepository( ): Result { return try { val lastFmAlbum = lastFMService.albumInfo(artist, album) - Result.Success(lastFmAlbum) + Success(lastFmAlbum) } catch (e: Exception) { - Result.Error + println(e) + Error } } @ExperimentalCoroutinesApi override suspend fun homeSectionsFlow(): Flow>> { - val homes = MutableStateFlow>>(value = Result.Loading) + val homes = MutableStateFlow>>(value = Loading) val homeSections = mutableListOf() val sections = listOf( topArtistsHome(), @@ -191,9 +194,9 @@ class RealRepository( } } if (homeSections.isEmpty()) { - homes.value = Result.Error + homes.value = Error } else { - homes.value = Result.Success(homeSections) + homes.value = Success(homeSections) } return homes } @@ -350,52 +353,52 @@ class RealRepository( } override fun songsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = songRepository.songs() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun albumsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = albumRepository.albums() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun artistsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = artistRepository.artists() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun playlistsFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = playlistRepository.playlists() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } override fun genresFlow(): Flow>> = flow { - emit(Result.Loading) + emit(Loading) val data = genreRepository.genres() if (data.isEmpty()) { - emit(Result.Error) + emit(Error) } else { - emit(Result.Success(data)) + emit(Success(data)) } } } \ No newline at end of file From 26edcdf4daf7859287b46cf85a70d5b5681a83bd Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sun, 6 Sep 2020 23:26:39 +0530 Subject: [PATCH 41/46] WIP Lyrics --- app/build.gradle | 3 +- app/src/debug/res/values/styles.xml | 9 ++-- .../code/name/monkey/retromusic/MainModule.kt | 39 +++++++++++++- .../adapter/album/AlbumCoverPagerAdapter.kt | 6 ++- .../monkey/retromusic/dialogs/LyricsDialog.kt | 51 +++++++++++++++++++ .../retromusic/extensions/DialogExtension.kt | 2 +- .../fragments/search/SearchViewModel.kt | 4 +- .../glide/artistimage/ArtistImageLoader.kt | 4 +- .../{deezer => model}/DeezerResponse.kt | 2 +- .../{deezer => network}/DeezerService.kt | 3 +- .../retromusic/network/LyricsService.kt | 12 +++++ .../retromusic/network/RetrofitClient.kt | 32 ++++-------- .../conversion/LyricsConverterFactory.kt | 51 +++++++++++++++++++ .../retromusic/repository/Repository.kt | 11 +++- .../name/monkey/retromusic/util/MusicUtil.kt | 4 +- app/src/main/res/layout/item_contributor.xml | 1 + app/src/main/res/layout/lyrics_dialog.xml | 33 ++++++++++++ app/src/main/res/values/styles.xml | 6 ++- 18 files changed, 228 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt rename app/src/main/java/code/name/monkey/retromusic/{deezer => model}/DeezerResponse.kt (94%) rename app/src/main/java/code/name/monkey/retromusic/{deezer => network}/DeezerService.kt (95%) create mode 100644 app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt create mode 100644 app/src/main/res/layout/lyrics_dialog.xml diff --git a/app/build.gradle b/app/build.gradle index d928d693..4725b1d8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -161,7 +161,6 @@ dependencies { 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' @@ -169,7 +168,7 @@ dependencies { 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' diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml index 7f4fe30c..c45bc56a 100644 --- a/app/src/debug/res/values/styles.xml +++ b/app/src/debug/res/values/styles.xml @@ -60,20 +60,23 @@ \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index 8d0fafa8..fe513d50 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -14,7 +14,7 @@ import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.search.SearchViewModel import code.name.monkey.retromusic.model.Genre -import code.name.monkey.retromusic.network.networkModule +import code.name.monkey.retromusic.network.* import code.name.monkey.retromusic.repository.* import code.name.monkey.retromusic.util.FilePathUtil import kotlinx.coroutines.Dispatchers.IO @@ -25,6 +25,28 @@ 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 { @@ -72,7 +94,20 @@ private val mainModule = module { } private val dataModule = module { single { - RealRepository(get(), 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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt index 039aa9fe..8cd40e97 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt @@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.dialogs.LyricsDialog import code.name.monkey.retromusic.fragments.AlbumCoverStyle import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import code.name.monkey.retromusic.glide.RetroMusicColoredTarget @@ -90,14 +91,15 @@ class AlbumCoverPagerAdapter( val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false) albumCover = view.findViewById(R.id.player_image) albumCover.setOnClickListener { - showLyricsDialog() + LyricsDialog().show(childFragmentManager, "LyricsDialog") + //showLyricsDialog() } return view } 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/code/name/monkey/retromusic/dialogs/LyricsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt new file mode 100644 index 00000000..d1f5f022 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt @@ -0,0 +1,51 @@ +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.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) + lifecycleScope.launch(IO) { + val result: Result = repository.lyrics( + MusicPlayerRemote.currentSong.artistName, + MusicPlayerRemote.currentSong.title + ) + withContext(Main) { + when (result) { + is Result.Error -> println("Error") + is Result.Loading -> println("Loading") + is Result.Success -> lyricsText.text = result.data + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt index d2c38310..c56a4045 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt index eecff933..50681023 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt @@ -6,9 +6,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import code.name.monkey.retromusic.repository.RealRepository import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class SearchViewModel(private val realRepository: RealRepository) : ViewModel() { private val results = MutableLiveData>() @@ -17,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel() fun search(query: String?) = viewModelScope.launch(IO) { val result = realRepository.search(query) - withContext(Main) { results.postValue(result) } + results.value = result } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt index f9792c42..43d23120 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt @@ -15,8 +15,8 @@ package code.name.monkey.retromusic.glide.artistimage import android.content.Context -import code.name.monkey.retromusic.deezer.Data -import code.name.monkey.retromusic.deezer.DeezerService +import code.name.monkey.retromusic.model.Data +import code.name.monkey.retromusic.network.DeezerService import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.bumptech.glide.Priority diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt b/app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt similarity index 94% rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt rename to app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt index b029ab53..929a9d13 100644 --- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt @@ -1,4 +1,4 @@ -package code.name.monkey.retromusic.deezer +package code.name.monkey.retromusic.model import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt b/app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt similarity index 95% rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt rename to app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt index 327f6848..1ea0c16c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt @@ -1,6 +1,7 @@ -package code.name.monkey.retromusic.deezer +package code.name.monkey.retromusic.network import android.content.Context +import code.name.monkey.retromusic.model.DeezerResponse import okhttp3.Cache import okhttp3.Interceptor import okhttp3.OkHttpClient diff --git a/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt b/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt new file mode 100644 index 00000000..0a0e0490 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.network + +import retrofit2.http.GET +import retrofit2.http.Headers +import retrofit2.http.Query + +interface LyricsRestService { + + @Headers("Cache-Control: public") + @GET("/lyrics") + suspend fun getLyrics(@Query("artist") artist: String, @Query("title") title: String): String +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt index 2121c812..df75072d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt @@ -3,39 +3,17 @@ package code.name.monkey.retromusic.network import android.content.Context import code.name.monkey.retromusic.App import code.name.monkey.retromusic.BuildConfig -import code.name.monkey.retromusic.deezer.DeezerService +import code.name.monkey.retromusic.network.conversion.LyricsConverterFactory import com.google.gson.Gson import okhttp3.Cache import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import org.koin.dsl.module import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.io.File import java.util.concurrent.TimeUnit -private const val TIMEOUT: Long = 700 - -val networkModule = module { - - factory { - provideDefaultCache() - } - factory { - provideOkHttp(get(), get()) - } - single { - provideLastFmRetrofit(get()) - } - single { - provideDeezerRest(get()) - } - single { - provideLastFmRest(get()) - } -} - fun provideDefaultCache(): Cache? { val cacheDir = File(App.getContext().cacheDir.absolutePath, "/okhttp-lastfm/") if (cacheDir.mkdirs() || cacheDir.isDirectory) { @@ -94,4 +72,12 @@ fun provideDeezerRest(retrofit: Retrofit): DeezerService { .baseUrl("https://api.deezer.com/") .build() return newBuilder.create(DeezerService::class.java) +} + +fun provideLyrics(retrofit: Retrofit): LyricsRestService { + val newBuilder = retrofit.newBuilder() + .baseUrl("https://makeitpersonal.co") + .addConverterFactory(LyricsConverterFactory()) + .build() + return newBuilder.create(LyricsRestService::class.java) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt new file mode 100644 index 00000000..474e81c9 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Naman Dwivedi. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ +package code.name.monkey.retromusic.network.conversion + +import okhttp3.MediaType +import okhttp3.RequestBody +import okhttp3.ResponseBody +import retrofit2.Converter +import retrofit2.Retrofit +import java.lang.reflect.Type + +class LyricsConverterFactory : Converter.Factory() { + + override fun responseBodyConverter( + type: Type?, + annotations: Array?, + retrofit: Retrofit? + ): Converter? { + return if (String::class.java == type) { + Converter { value -> value.string() } + } else null + } + + override fun requestBodyConverter( + type: Type?, + parameterAnnotations: Array?, + methodAnnotations: Array?, + retrofit: Retrofit? + ): Converter<*, RequestBody>? { + + return if (String::class.java == type) { + Converter { value -> RequestBody.create(MEDIA_TYPE, value) } + } else null + } + + companion object { + private val MEDIA_TYPE = MediaType.parse("text/plain") + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 4dd683a1..32ca1ffe 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -21,6 +21,7 @@ import code.name.monkey.retromusic.db.* import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist import code.name.monkey.retromusic.network.LastFMService +import code.name.monkey.retromusic.network.LyricsRestService import code.name.monkey.retromusic.network.Result import code.name.monkey.retromusic.network.Result.* import code.name.monkey.retromusic.network.model.LastFmAlbum @@ -94,6 +95,7 @@ interface Repository { suspend fun checkSongExistInPlayCount(songId: Int): List suspend fun playCountSongs(): List suspend fun blackListPaths(): List + suspend fun lyrics(artist: String, title: String): Result } class RealRepository( @@ -107,9 +109,16 @@ class RealRepository( private val playlistRepository: PlaylistRepository, private val searchRepository: RealSearchRepository, private val topPlayedRepository: TopPlayedRepository, - private val roomRepository: RoomRepository + private val roomRepository: RoomRepository, + private val lyricsRestService: LyricsRestService ) : Repository { + override suspend fun lyrics(artist: String, title: String): Result = try { + Success(lyricsRestService.getLyrics(artist, title)) + } catch (e: Exception) { + Error + } + override suspend fun fetchAlbums(): List = albumRepository.albums() override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index a3bbf776..8659a0ba 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -111,7 +111,7 @@ object MusicUtil : KoinComponent { } fun getLyrics(song: Song): String? { - var lyrics: String? = null + var lyrics: String? = "No lyrics found" val file = File(song.data) try { lyrics = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS) @@ -151,7 +151,7 @@ object MusicUtil : KoinComponent { } false } - if (files != null && files.size > 0) { + if (files != null && files.isNotEmpty()) { for (f in files) { try { val newLyrics = diff --git a/app/src/main/res/layout/item_contributor.xml b/app/src/main/res/layout/item_contributor.xml index ef73b468..d7ba8832 100644 --- a/app/src/main/res/layout/item_contributor.xml +++ b/app/src/main/res/layout/item_contributor.xml @@ -32,6 +32,7 @@ android:scaleType="centerCrop" app:civ_border="false" app:civ_shadow="false" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:retroCornerSize="21dp" diff --git a/app/src/main/res/layout/lyrics_dialog.xml b/app/src/main/res/layout/lyrics_dialog.xml new file mode 100644 index 00000000..27fa8a95 --- /dev/null +++ b/app/src/main/res/layout/lyrics_dialog.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c0eb21c3..3c37bd74 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -215,14 +215,16 @@ From 8cebb0c603656ecbc5781ccae48d314dff6ed5e2 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Mon, 7 Sep 2020 13:34:51 +0530 Subject: [PATCH 42/46] Code refactor --- .../adapter/playlist/LegacyPlaylistAdapter.kt | 52 +++++++++++++++++ .../playlists/ImportPlaylistFragment.kt | 56 ++----------------- 2 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/LegacyPlaylistAdapter.kt new file mode 100644 index 00000000..c74c8a5f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt index ad9e17c3..efe3c4e4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/ImportPlaylistFragment.kt @@ -1,25 +1,25 @@ package code.name.monkey.retromusic.fragments.playlists import android.os.Bundle -import android.view.* +import android.view.Menu +import android.view.MenuInflater +import android.view.View import android.widget.Toast -import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder +import code.name.monkey.retromusic.adapter.playlist.LegacyPlaylistAdapter import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment import code.name.monkey.retromusic.model.Playlist -import code.name.monkey.retromusic.util.MusicUtil import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch class ImportPlaylistFragment : - AbsRecyclerViewFragment(), PlaylistClickListener { + AbsRecyclerViewFragment(), + LegacyPlaylistAdapter.PlaylistClickListener { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -69,48 +69,4 @@ class ImportPlaylistFragment : menu.removeItem(R.id.action_sort_order) super.onCreateOptionsMenu(menu, inflater) } -} - -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 From 6d0898a49a626a77a152cc6c8832641dc5f59ad8 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Mon, 7 Sep 2020 15:01:27 +0530 Subject: [PATCH 43/46] Code refactor --- app/src/debug/res/values/styles.xml | 9 +++++++++ .../base/AbsSlidingMusicPanelActivity.kt | 1 - .../activities/bugreport/model/DeviceInfo.java | 2 +- .../retromusic/dialogs/SleepTimerDialog.kt | 4 ++-- .../fragments/albums/AlbumDetailsFragment.kt | 18 ++++++++---------- .../fragments/settings/MainSettingsFragment.kt | 2 +- .../retromusic/repository/SongRepository.kt | 11 ++++++++++- .../res/layout/bug_report_card_device_info.xml | 4 ++-- app/src/main/res/layout/card_credit.xml | 2 +- app/src/main/res/layout/card_other.xml | 1 + app/src/main/res/layout/card_retro_info.xml | 2 +- app/src/main/res/layout/card_social.xml | 2 +- .../main/res/layout/fragment_main_settings.xml | 4 ++-- app/src/main/res/values/styles.xml | 8 ++++++-- .../monkey/appthemehelper/util/VersionUtils.kt | 14 ++++++++++++++ 15 files changed, 59 insertions(+), 25 deletions(-) diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml index c45bc56a..81154a39 100644 --- a/app/src/debug/res/values/styles.xml +++ b/app/src/debug/res/values/styles.xml @@ -79,4 +79,13 @@ 16dp + \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt index d21b209d..54098279 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt @@ -78,7 +78,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { libraryViewModel.paletteColorLiveData.observe(this, Observer { this.paletteColor = it - miniPlayerFragment?.updateProgressBar(it) onPaletteColorChanged() }) } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java index e9eee8a2..3a6e8032 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java +++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.java @@ -85,7 +85,7 @@ public class DeviceInfo { return "Device info:\n" + "---\n" + "\n" - + "\n" + + "\n" + "\n" + "\n" + "\n" diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt index 4e628898..21c43f30 100755 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/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) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 05572748..bade59ff 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -6,6 +6,7 @@ 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 @@ -14,7 +15,6 @@ import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.EXTRA_ALBUM_ID @@ -76,9 +76,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det mainActivity.hideBottomBarVisibility(false) mainActivity.addMusicServiceEventListener(detailsViewModel) mainActivity.setSupportActionBar(toolbar) - - toolbar.title = null - + toolbar.title = " " postponeEnterTransition() detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer { startPostponedEnterTransition() @@ -148,7 +146,6 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det album.songCount ) songTitle.text = songText - if (MusicUtil.getYearString(album.year) == "-") { albumText.text = String.format( "%s • %s", @@ -207,7 +204,10 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det aboutAlbumTitle.show() aboutAlbumTitle.text = String.format(getString(R.string.about_album_label), lastFmAlbum.album.name) - aboutAlbumText.text = lastFmAlbum.album.wiki.content + aboutAlbumText.text = HtmlCompat.fromHtml( + lastFmAlbum.album.wiki.content, + HtmlCompat.FROM_HTML_MODE_LEGACY + ) } if (lastFmAlbum.album.listeners.isNotEmpty()) { listeners.show() @@ -250,10 +250,8 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det } private fun setColors(color: Int) { - val finalColor = - if (PreferenceUtil.isAdaptiveColor) color else ThemeStore.accentColor(requireContext()) - shuffleAction.applyColor(finalColor) - playAction.applyOutlineColor(finalColor) + shuffleAction.applyColor(color) + playAction.applyOutlineColor(color) } override fun onAlbumClick(albumId: Int, view: View) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt index d0c15861..2b4e8a07 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt @@ -63,7 +63,7 @@ class MainSettingsFragment : Fragment(), View.OnClickListener { aboutSettings.setOnClickListener(this) buyProContainer.apply { - if (!App.isProVersion()) show() else hide() + if (App.isProVersion()) hide() else show() setOnClickListener { NavigationUtil.goToProVersion(requireContext()) } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index e136a9b5..cbf6b4f4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -18,6 +18,7 @@ import android.content.Context import android.database.Cursor import android.provider.MediaStore import android.provider.MediaStore.Audio.AudioColumns +import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.Constants.IS_MUSIC import code.name.monkey.retromusic.Constants.baseProjection import code.name.monkey.retromusic.model.Song @@ -152,8 +153,16 @@ class RealSongRepository(private val context: Context) : SongRepository { selectionFinal = selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000) + + val uri = if (VersionUtils.hasQ()) { + + MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) + } else { + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + } + return context.contentResolver.query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + uri, baseProjection, selectionFinal, selectionValuesFinal, diff --git a/app/src/main/res/layout/bug_report_card_device_info.xml b/app/src/main/res/layout/bug_report_card_device_info.xml index 5ac4f728..743e11aa 100644 --- a/app/src/main/res/layout/bug_report_card_device_info.xml +++ b/app/src/main/res/layout/bug_report_card_device_info.xml @@ -2,6 +2,7 @@ diff --git a/app/src/main/res/layout/card_credit.xml b/app/src/main/res/layout/card_credit.xml index b80c6e8a..f7900700 100644 --- a/app/src/main/res/layout/card_credit.xml +++ b/app/src/main/res/layout/card_credit.xml @@ -2,9 +2,9 @@ + app:cardCornerRadius="8dp"> - - + diff --git a/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/VersionUtils.kt b/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/VersionUtils.kt index 92cbbf41..24164536 100644 --- a/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/VersionUtils.kt +++ b/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/VersionUtils.kt @@ -42,4 +42,18 @@ object VersionUtils { fun hasOreo(): Boolean { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O } + + /** + * @return true if device is running API >= 27 + */ + fun hasP(): Boolean { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P + } + + /** + * @return true if device is running API >= 28 + */ + fun hasQ(): Boolean { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q + } } From 5ebeb9c587a2e8ea302e7f8aeab7d7d335e2f2bf Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Wed, 9 Sep 2020 18:07:25 +0530 Subject: [PATCH 44/46] Code refactor --- .../activities/bugreport/BugReportActivity.kt | 8 +- .../name/monkey/retromusic/db/PlayCountDao.kt | 3 + .../dialogs/BlacklistFolderChooserDialog.java | 2 +- .../dialogs/DeleteSongsAsyncTask.java | 145 ------------------ .../retromusic/dialogs/DeleteSongsDialog.kt | 101 +++--------- .../dialogs/ImportPlaylistDialog.kt | 24 +++ .../retromusic/dialogs/SongDetailDialog.kt | 2 +- .../retromusic/fragments/LibraryViewModel.kt | 34 +++- .../fragments/library/LibraryFragment.kt | 20 ++- .../fragments/songs/SongsFragment.kt | 1 - .../preferences/LibraryPreference.kt | 2 +- .../retromusic/repository/Repository.kt | 3 + .../retromusic/repository/RoomRepository.kt | 7 + .../retromusic/repository/SongRepository.kt | 1 - .../name/monkey/retromusic/util/MusicUtil.kt | 75 +++++++++ .../monkey/retromusic/util/RingtoneManager.kt | 2 +- app/src/main/res/layout/fragment_library.xml | 2 +- .../main/res/layout/item_list_no_image.xml | 2 +- .../main/res/layout/section_recycler_view.xml | 5 +- app/src/main/res/values/strings.xml | 3 +- 20 files changed, 199 insertions(+), 243 deletions(-) delete mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsAsyncTask.java create mode 100644 app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt index 43107430..5bb2b7ac 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt @@ -280,21 +280,21 @@ open class BugReportActivity : AbsThemeActivity() { RESULT_BAD_CREDENTIALS -> MaterialAlertDialogBuilder(context) .setTitle(R.string.bug_report_failed) .setMessage(R.string.bug_report_failed_wrong_credentials) - .setPositiveButton(R.string.ok, null) + .setPositiveButton(android.R.string.ok, null) .show() RESULT_INVALID_TOKEN -> MaterialAlertDialogBuilder(context) .setTitle(R.string.bug_report_failed) .setMessage(R.string.bug_report_failed_invalid_token) - .setPositiveButton(R.string.ok, null).show() + .setPositiveButton(android.R.string.ok, null).show() RESULT_ISSUES_NOT_ENABLED -> MaterialAlertDialogBuilder(context) .setTitle(R.string.bug_report_failed) .setMessage(R.string.bug_report_failed_issues_not_available) - .setPositiveButton(R.string.ok, null) + .setPositiveButton(android.R.string.ok, null) else -> MaterialAlertDialogBuilder(context) .setTitle(R.string.bug_report_failed) .setMessage(R.string.bug_report_failed_unknown) - .setPositiveButton(R.string.ok) { _, _ -> tryToFinishActivity() } + .setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() } .setNegativeButton(android.R.string.cancel) { _, _ -> tryToFinishActivity() } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt index 9c22d4da..17868e7e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt @@ -18,4 +18,7 @@ interface PlayCountDao { @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC") fun playCountSongs(): List + + @Query("DELETE FROM SongEntity WHERE id =:songId") + fun deleteSong(songId: Int) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java index c78834bc..1e2099cc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java @@ -76,7 +76,7 @@ public class BlacklistFolderChooserDialog extends DialogFragment implements Mate return new MaterialDialog.Builder(requireActivity()) .title(R.string.md_error_label) .content(R.string.md_storage_perm_error) - .positiveText(R.string.ok) + .positiveText(android.R.string.ok) .build(); } if (savedInstanceState == null) { diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsAsyncTask.java deleted file mode 100644 index 5cc00d76..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/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 code.name.monkey.retromusic.dialogs; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.List; - -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.activities.saf.SAFGuideActivity; -import code.name.monkey.retromusic.misc.DialogAsyncTask; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.util.SAFUtil; - -/** - * Created by hemanths on 2019-07-31. - */ -public class DeleteSongsAsyncTask extends DialogAsyncTask { - - 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/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt index c9fdae70..4398a6c6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt @@ -1,50 +1,45 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - package code.name.monkey.retromusic.dialogs import android.app.Dialog -import android.content.Intent -import android.net.Uri import android.os.Bundle import androidx.core.text.HtmlCompat import androidx.fragment.app.DialogFragment import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.activities.saf.SAFGuideActivity import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil -import code.name.monkey.retromusic.util.SAFUtil +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class DeleteSongsDialog : DialogFragment() { - @JvmField - var currentSong: Song? = null + private val libraryViewModel by sharedViewModel() - @JvmField - var songsToRemove: List? = null + companion object { + fun create(song: Song): DeleteSongsDialog { + val list = ArrayList() + list.add(song) + return create(list) + } - private var deleteSongsAsyncTask: DeleteSongsAsyncTask? = null + fun create(songs: List): DeleteSongsDialog { + val dialog = DeleteSongsDialog() + val args = Bundle() + args.putParcelableArrayList(EXTRA_SONG, ArrayList(songs)) + dialog.arguments = args + 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( + R.string.delete_songs_title, + HtmlCompat.fromHtml( String.format(getString(R.string.delete_x_songs), songs.size), HtmlCompat.FROM_HTML_MODE_LEGACY ) @@ -62,63 +57,15 @@ class DeleteSongsDialog : DialogFragment() { return materialDialog(pair.first) .setMessage(pair.second) .setCancelable(false) - .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.action_delete) { _, _ -> - if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) { + if (songs.isNotEmpty() and (songs.size == 1) and MusicPlayerRemote.isPlaying(songs.first())) { MusicPlayerRemote.playNextSong() } - songsToRemove = songs - deleteSongsAsyncTask = DeleteSongsAsyncTask(this@DeleteSongsDialog) - deleteSongsAsyncTask?.execute(DeleteSongsAsyncTask.LoadingInfo(songs, null)) + MusicUtil.deleteTracks(requireActivity(), songs) + libraryViewModel.deleteTracks(songs) + } .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() - }) - } - - companion object { - - fun create(song: Song): DeleteSongsDialog { - val list = ArrayList() - list.add(song) - return create(list) - } - - fun create(songs: List): DeleteSongsDialog { - val dialog = DeleteSongsDialog() - 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/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt new file mode 100644 index 00000000..359ef1c5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt index bed9c1b7..3409b698 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt @@ -144,7 +144,7 @@ class SongDetailDialog : DialogFragment() { } } return materialDialog(R.string.action_details) - .setPositiveButton(R.string.ok, null) + .setPositiveButton(android.R.string.ok, null) .setView(dialogView) .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index cdee7637..e3c15fb2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -30,12 +30,16 @@ class LibraryViewModel( val paletteColorLiveData: LiveData = paletteColor + init { + fetchHomeSections() + } + private fun loadLibraryContent() = viewModelScope.launch(IO) { + fetchHomeSections() fetchSongs() fetchAlbums() fetchArtists() fetchGenres() - fetchHomeSections() fetchPlaylists() } @@ -70,7 +74,6 @@ class LibraryViewModel( } fun getHome(): LiveData> { - fetchHomeSections() return home } @@ -132,11 +135,10 @@ class LibraryViewModel( } override fun onMediaStoreChanged() { - loadLibraryContent() println("onMediaStoreChanged") + loadLibraryContent() } - override fun onServiceConnected() { println("onServiceConnected") } @@ -204,6 +206,30 @@ class LibraryViewModel( suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = repository.createPlaylist(playlistEntity) + fun importPlaylists() = viewModelScope.launch(IO) { + val playlists = repository.fetchLegacyPlaylist() + playlists.forEach { playlist -> + val playlistEntity = repository.checkPlaylistExists(playlist.name).firstOrNull(); + if (playlistEntity != null) { + val songEntities = playlist.getSongs().map { + it.toSongEntity(playlistEntity.playListId) + } + repository.insertSongs(songEntities) + } else { + val playListId = createPlaylist(PlaylistEntity(playlist.name)) + val songEntities = playlist.getSongs().map { + it.toSongEntity(playListId.toInt()) + } + repository.insertSongs(songEntities) + } + forceReload(Playlists) + } + } + + fun deleteTracks(songs: List) = viewModelScope.launch(IO) { + repository.deleteSongs(songs) + } + } enum class ReloadType { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index f49876f3..086e0a09 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -4,15 +4,19 @@ import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import androidx.core.text.HtmlCompat import androidx.navigation.fragment.findNavController import androidx.navigation.ui.NavigationUI +import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog +import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import kotlinx.android.synthetic.main.fragment_library.* +import java.lang.String class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { @@ -31,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() { @@ -61,7 +76,10 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { null, navOptions ) - R.id.action_import_playlist -> findNavController(R.id.fragment_container).navigate(R.id.action_import_playlist) + R.id.action_import_playlist -> ImportPlaylistDialog().show( + childFragmentManager, + "ImportPlaylist" + ) R.id.action_add_to_playlist -> CreatePlaylistDialog.create(emptyList()).show( childFragmentManager, "ShowCreatePlaylistDialog" diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index 413edb83..533aa0f7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -20,7 +20,6 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment updateCategories(categoryAdapter.categoryInfos) } + .setPositiveButton(android.R.string.ok) { _, _ -> updateCategories(categoryAdapter.categoryInfos) } .setView(view) .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 32ca1ffe..06aff1c7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -96,6 +96,7 @@ interface Repository { suspend fun playCountSongs(): List suspend fun blackListPaths(): List suspend fun lyrics(artist: String, title: String): Result + suspend fun deleteSongs(songs: List) } class RealRepository( @@ -119,6 +120,8 @@ class RealRepository( Error } + override suspend fun deleteSongs(songs: List) = roomRepository.deleteSongs(songs) + override suspend fun fetchAlbums(): List = albumRepository.albums() override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index 8267b36a..24c9e65b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -38,6 +38,7 @@ interface RoomRepository { suspend fun clearBlacklist() suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity) suspend fun blackListPaths(): List + suspend fun deleteSongs(songs: List) } class RealRoomRepository( @@ -153,6 +154,12 @@ class RealRoomRepository( override suspend fun blackListPaths(): List = blackListStoreDao.blackListPaths() + override suspend fun deleteSongs(songs: List) { + songs.forEach { + playCountDao.deleteSong(it.id) + } + } + override suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) = blackListStoreDao.deleteBlacklistPath(blackListStoreEntity) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index cbf6b4f4..41df3e29 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -155,7 +155,6 @@ class RealSongRepository(private val context: Context) : SongRepository { val uri = if (VersionUtils.hasQ()) { - MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) } else { MediaStore.Audio.Media.EXTERNAL_CONTENT_URI diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index 8659a0ba..a29663a1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -4,11 +4,13 @@ import android.content.ContentUris import android.content.ContentValues import android.content.Context import android.content.Intent +import android.database.Cursor import android.net.Uri import android.os.Environment import android.provider.BaseColumns import android.provider.MediaStore import android.text.TextUtils +import android.util.Log import android.widget.Toast import androidx.core.content.FileProvider import androidx.fragment.app.FragmentActivity @@ -20,6 +22,7 @@ import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics import code.name.monkey.retromusic.repository.RealPlaylistRepository +import code.name.monkey.retromusic.repository.RealSongRepository import code.name.monkey.retromusic.repository.SongRepository import code.name.monkey.retromusic.service.MusicService import org.jaudiotagger.audio.AudioFileIO @@ -421,6 +424,78 @@ object MusicUtil : KoinComponent { .show() callback?.run() } + } } + + fun deleteTracks(context: Context, songs: List) { + val projection = arrayOf( + BaseColumns._ID, MediaStore.MediaColumns.DATA + ) + val selection = StringBuilder() + selection.append(BaseColumns._ID + " IN (") + for (i in songs.indices) { + selection.append(songs[i].id) + if (i < songs.size - 1) { + selection.append(",") + } + } + selection.append(")") + var deletedCount = 0 + try { + val cursor: Cursor? = context.contentResolver.query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(), + null, null + ) + if (cursor != null) { + // Step 1: Remove selected tracks from the current playlist, as well + // as from the album art cache + cursor.moveToFirst() + while (!cursor.isAfterLast) { + val id: Int = cursor.getInt(0) + val song: Song = RealSongRepository(context).song(id) + removeFromQueue(song) + cursor.moveToNext() + } + + + // Step 2: Remove files from card + cursor.moveToFirst() + while (!cursor.isAfterLast) { + val id: Int = cursor.getInt(0) + val name: String = cursor.getString(1) + try { // File.delete can throw a security exception + val f = File(name) + if (f.delete()) { + // Step 3: Remove selected track from the database + context.contentResolver.delete( + ContentUris.withAppendedId( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + id.toLong() + ), null, null + ) + deletedCount++ + } else { + // I'm not sure if we'd ever get here (deletion would + // have to fail, but no exception thrown) + Log.e("MusicUtils", "Failed to delete file $name") + } + cursor.moveToNext() + } catch (ex: SecurityException) { + cursor.moveToNext() + } catch (e: NullPointerException) { + Log.e("MusicUtils", "Failed to find file $name") + } + } + cursor.close() + } + Toast.makeText( + context, + context.getString(R.string.deleted_x_songs, deletedCount), + Toast.LENGTH_SHORT + ).show() + } catch (ignored: SecurityException) { + } + } + } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt b/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt index 89d98e26..00052977 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt @@ -77,7 +77,7 @@ class RingtoneManager(val context: Context) { return MaterialAlertDialogBuilder(context) .setTitle(R.string.dialog_title_set_ringtone) .setMessage(R.string.dialog_message_set_ringtone) - .setPositiveButton(R.string.ok) { _, _ -> + .setPositiveButton(android.R.string.ok) { _, _ -> val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS) intent.data = Uri.parse("package:" + context.applicationContext.packageName) context.startActivity(intent) diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 186b93eb..59a58832 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -31,7 +31,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:text="@string/app_name" + android:id="@+id/appNameText" android:textAppearance="@style/TextViewHeadline6" android:textStyle="bold" /> diff --git a/app/src/main/res/layout/item_list_no_image.xml b/app/src/main/res/layout/item_list_no_image.xml index 456468b2..bf6ffc26 100644 --- a/app/src/main/res/layout/item_list_no_image.xml +++ b/app/src/main/res/layout/item_list_no_image.xml @@ -18,7 +18,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp" - android:background="?rectSelector" + android:background="?attr/rectSelector" android:minHeight="64dp" android:padding="14dp" tools:ignore="UnusedAttribute"> diff --git a/app/src/main/res/layout/section_recycler_view.xml b/app/src/main/res/layout/section_recycler_view.xml index 4f4d6e74..a86a9cc0 100644 --- a/app/src/main/res/layout/section_recycler_view.xml +++ b/app/src/main/res/layout/section_recycler_view.xml @@ -5,8 +5,7 @@ android:id="@+id/recentArtistContainer" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingBottom="12dp"> + android:orientation="vertical" > Hello blank fragment Done - Ok Import playlist + It imports all playlists listed in the Android Media Store with songs, if the playlists already exists, the songs will get merged. + Import From 0ef83c713650df1691e37e6ec474f622f07523b3 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Fri, 11 Sep 2020 00:52:10 +0530 Subject: [PATCH 45/46] Code refactor --- app/build.gradle | 4 +- .../code/name/monkey/retromusic/MainModule.kt | 5 +- .../adapter/album/AlbumCoverPagerAdapter.kt | 2 +- .../name/monkey/retromusic/db/LyricsDao.kt | 18 ++++++ .../name/monkey/retromusic/db/LyricsEntity.kt | 10 ++++ .../name/monkey/retromusic/db/PlaylistDao.kt | 9 ++- .../monkey/retromusic/db/RetroDatabase.kt | 5 +- .../retromusic/dialogs/DeleteSongsDialog.kt | 1 - .../monkey/retromusic/dialogs/LyricsDialog.kt | 17 ++++-- .../monkey/retromusic/extensions/ColorExt.kt | 10 +++- .../retromusic/fragments/LibraryViewModel.kt | 7 ++- .../playlists/PlaylistDetailsFragment.kt | 10 +--- .../playlists/PlaylistDetailsViewModel.kt | 20 +------ .../monkey/retromusic/model/CategoryInfo.java | 3 +- .../name/monkey/retromusic/network/Result.kt | 2 +- .../retromusic/network/RetrofitClient.kt | 10 +++- .../retromusic/repository/Repository.kt | 29 ++++++---- .../retromusic/repository/RoomRepository.kt | 22 ++++--- .../monkey/retromusic/util/PreferenceUtil.kt | 1 - app/src/main/res/layout/lyrics_dialog.xml | 57 ++++++++++++++----- app/src/main/res/navigation/library_graph.xml | 5 -- .../appthemehelper/util/VersionUtils.kt | 1 + build.gradle | 2 +- 23 files changed, 156 insertions(+), 94 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/LyricsDao.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/db/LyricsEntity.kt diff --git a/app/build.gradle b/app/build.gradle index 4725b1d8..ebb6025a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,7 +143,7 @@ dependencies { implementation 'com.afollestad:material-cab:0.1.12' def kotlin_coroutines_version = "1.3.8" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.0" + 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" @@ -171,6 +171,6 @@ dependencies { 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/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index fe513d50..c7296dda 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -65,6 +65,9 @@ private val roomModule = module { .fallbackToDestructiveMigration() .build() } + factory { + get().lyricsDao() + } factory { get().playlistDao() @@ -83,7 +86,7 @@ private val roomModule = module { } single { - RealRoomRepository(get(), get(), get(), get()) + RealRoomRepository(get(), get(), get(), get(), get()) } bind RoomRepository::class } private val mainModule = module { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt index 8cd40e97..1a82f465 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt @@ -92,7 +92,7 @@ class AlbumCoverPagerAdapter( albumCover = view.findViewById(R.id.player_image) albumCover.setOnClickListener { LyricsDialog().show(childFragmentManager, "LyricsDialog") - //showLyricsDialog() + showLyricsDialog() } return view } diff --git a/app/src/main/java/code/name/monkey/retromusic/db/LyricsDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/LyricsDao.kt new file mode 100644 index 00000000..a09b430a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/db/LyricsEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/LyricsEntity.kt new file mode 100644 index 00000000..0cec6431 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/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/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt index 0cfe2b8a..219ca590 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -18,10 +18,10 @@ interface PlaylistDao { suspend fun playlists(): List @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId") - suspend fun deleteSongsInPlaylist(playlistId: Int) + suspend fun deletePlaylistSongs(playlistId: Int) @Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId") - suspend fun removeSongFromPlaylist(playlistId: Int, songId: Int) + suspend fun deleteSongFromPlaylist(playlistId: Int, songId: Int) @Transaction @Query("SELECT * FROM PlaylistEntity") @@ -34,7 +34,7 @@ interface PlaylistDao { suspend fun isSongExistsInPlaylist(playlistId: Int, songId: Int): List @Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId") - suspend fun songsFromPlaylist(playlistId: Int): List + fun songsFromPlaylist(playlistId: Int): LiveData> @Delete suspend fun deletePlaylist(playlistEntity: PlaylistEntity) @@ -43,7 +43,7 @@ interface PlaylistDao { suspend fun deletePlaylists(playlistEntities: List) @Delete - suspend fun deleteSongsInPlaylist(songs: List) + suspend fun deletePlaylistSongs(songs: List) @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @@ -53,5 +53,4 @@ interface PlaylistDao { fun favoritesSongs(playlistId: Int): List - } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt index e9b99cca..cda6eddd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt @@ -4,8 +4,8 @@ import androidx.room.Database import androidx.room.RoomDatabase @Database( - entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class], - version = 20, + entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class, LyricsEntity::class], + version = 21, exportSchema = false ) abstract class RetroDatabase : RoomDatabase() { @@ -13,4 +13,5 @@ abstract class RetroDatabase : RoomDatabase() { 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/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt index 4398a6c6..24a67a0f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt @@ -63,7 +63,6 @@ class DeleteSongsDialog : DialogFragment() { } MusicUtil.deleteTracks(requireActivity(), songs) libraryViewModel.deleteTracks(songs) - } .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt index d1f5f022..9c3b63c7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt @@ -7,6 +7,8 @@ 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 @@ -34,16 +36,23 @@ class LyricsDialog : DialogFragment() { 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( - MusicPlayerRemote.currentSong.artistName, - MusicPlayerRemote.currentSong.title + song.artistName, + song.title ) withContext(Main) { + when (result) { - is Result.Error -> println("Error") + is Result.Error -> progressBar.hide() is Result.Loading -> println("Loading") - is Result.Success -> lyricsText.text = result.data + is Result.Success -> { + progressBar.hide() + lyricsText.text = result.data + } } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt index 8d2d56e4..9afbd431 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExt.kt @@ -22,8 +22,10 @@ import android.graphics.drawable.Drawable import android.widget.Button import android.widget.CheckBox import android.widget.SeekBar -import androidx.annotation.* -import androidx.appcompat.content.res.AppCompatResources +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 @@ -97,6 +99,10 @@ fun Button.accentTextColor() { setTextColor(ThemeStore.accentColor(App.getContext())) } +fun MaterialButton.accentTextColor() { + setTextColor(ThemeStore.accentColor(App.getContext())) +} + fun SeekBar.applyColor(@ColorInt color: Int) { thumbTintList = ColorStateList.valueOf(color) progressTintList = ColorStateList.valueOf(color) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index e3c15fb2..a60b9256 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -185,7 +185,7 @@ class LibraryViewModel( } fun deleteSongsFromPlaylist(playlists: List) = viewModelScope.launch(IO) { - repository.deleteSongsFromPlaylist(playlists) + repository.deletePlaylistSongs(playlists) } fun deleteRoomPlaylist(playlists: List) = viewModelScope.launch(IO) { @@ -209,7 +209,7 @@ class LibraryViewModel( fun importPlaylists() = viewModelScope.launch(IO) { val playlists = repository.fetchLegacyPlaylist() playlists.forEach { playlist -> - val playlistEntity = repository.checkPlaylistExists(playlist.name).firstOrNull(); + val playlistEntity = repository.checkPlaylistExists(playlist.name).firstOrNull() if (playlistEntity != null) { val songEntities = playlist.getSongs().map { it.toSongEntity(playlistEntity.playListId) @@ -228,8 +228,9 @@ class LibraryViewModel( fun deleteTracks(songs: List) = viewModelScope.launch(IO) { repository.deleteSongs(songs) + fetchPlaylists() + loadLibraryContent() } - } enum class ReloadType { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index 6cf4cb5e..8f78f518 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -5,7 +5,6 @@ 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 @@ -13,6 +12,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter import code.name.monkey.retromusic.adapter.song.SongAdapter import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.extensions.dipToPix import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper @@ -49,17 +49,13 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli setUpRecyclerView() - viewModel.getSongs().observe(viewLifecycleOwner, Observer { - songs(it) + 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 = diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt index cc13bad2..ac498b4e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt @@ -3,16 +3,11 @@ package code.name.monkey.retromusic.fragments.playlists import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import code.name.monkey.retromusic.db.PlaylistWithSongs -import code.name.monkey.retromusic.db.toSongs +import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class PlaylistDetailsViewModel( private val realRepository: RealRepository, @@ -26,17 +21,8 @@ class PlaylistDetailsViewModel( fun getPlaylist(): LiveData = _playlist - fun getSongs(): LiveData> = _playListSongs + fun getSongs(): LiveData> = realRepository.playlistSongs(playlist.playlistEntity) - init { - loadPlaylistSongs(playlist) - } - - private fun loadPlaylistSongs(playlist: PlaylistWithSongs) = - viewModelScope.launch(Dispatchers.IO) { - val songs: List = playlist.songs.toSongs() - withContext(Main) { _playListSongs.postValue(songs) } - } override fun onMediaStoreChanged() { /*if (playlist !is AbsCustomPlaylist) { @@ -65,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/code/name/monkey/retromusic/model/CategoryInfo.java b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java index f8689439..5b206ba2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java +++ b/app/src/main/java/code/name/monkey/retromusic/model/CategoryInfo.java @@ -63,9 +63,8 @@ public class CategoryInfo implements Parcelable { Songs(R.id.action_song, R.string.songs, R.drawable.ic_audiotrack), Albums(R.id.action_album, R.string.albums, R.drawable.ic_album), Artists(R.id.action_artist, R.string.artists, R.drawable.ic_artist), - Playlists(R.id.action_playlist, R.string.playlists, R.drawable.ic_playlist_play), + Playlists(R.id.action_playlist, R.string.playlists, (R.drawable.ic_queue_music)), Genres(R.id.action_genre, R.string.genres, R.drawable.ic_guitar), - Queue(R.id.action_playing_queue, R.string.queue, R.drawable.ic_queue_music), Folder(R.id.action_folder, R.string.folders, R.drawable.ic_folder); public final int icon; diff --git a/app/src/main/java/code/name/monkey/retromusic/network/Result.kt b/app/src/main/java/code/name/monkey/retromusic/network/Result.kt index 05211fd3..2d155522 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/Result.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/Result.kt @@ -21,5 +21,5 @@ package code.name.monkey.retromusic.network sealed class Result { data class Success(val data: T) : Result() object Loading : Result() - object Error : Result() + data class Error(val error: Exception) : Result() } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt index df75072d..719d682f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt @@ -4,7 +4,7 @@ import android.content.Context import code.name.monkey.retromusic.App import code.name.monkey.retromusic.BuildConfig import code.name.monkey.retromusic.network.conversion.LyricsConverterFactory -import com.google.gson.Gson +import com.google.gson.GsonBuilder import okhttp3.Cache import okhttp3.Interceptor import okhttp3.OkHttpClient @@ -14,6 +14,7 @@ import retrofit2.converter.gson.GsonConverterFactory import java.io.File import java.util.concurrent.TimeUnit + fun provideDefaultCache(): Cache? { val cacheDir = File(App.getContext().cacheDir.absolutePath, "/okhttp-lastfm/") if (cacheDir.mkdirs() || cacheDir.isDirectory) { @@ -48,7 +49,7 @@ fun headerInterceptor(context: Context): Interceptor { fun provideOkHttp(context: Context, cache: Cache): OkHttpClient { return OkHttpClient.Builder() .addNetworkInterceptor(logInterceptor()) - .addInterceptor(headerInterceptor(context)) + //.addInterceptor(headerInterceptor(context)) .connectTimeout(1, TimeUnit.SECONDS) .readTimeout(1, TimeUnit.SECONDS) .cache(cache) @@ -56,9 +57,12 @@ fun provideOkHttp(context: Context, cache: Cache): OkHttpClient { } fun provideLastFmRetrofit(client: OkHttpClient): Retrofit { + val gson = GsonBuilder() + .setLenient() + .create() return Retrofit.Builder() .baseUrl("https://ws.audioscrobbler.com/2.0/") - .addConverterFactory(GsonConverterFactory.create(Gson())) + .addConverterFactory(GsonConverterFactory.create(gson)) .callFactory { request -> client.newCall(request) } .build() } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 06aff1c7..7ea0db79 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -42,6 +42,7 @@ interface Repository { fun favorites(): LiveData> fun observableHistorySongs(): LiveData> fun albumById(albumId: Int): Album + fun playlistSongs(playlistEntity: PlaylistEntity): LiveData> suspend fun fetchAlbums(): List suspend fun albumByIdAsync(albumId: Int): Album suspend fun allSongs(): List @@ -80,7 +81,7 @@ interface Repository { suspend fun renameRoomPlaylist(playlistId: Int, name: String) suspend fun deleteSongsInPlaylist(songs: List) suspend fun removeSongFromPlaylist(songEntity: SongEntity) - suspend fun deleteSongsFromPlaylist(playlists: List) + suspend fun deletePlaylistSongs(playlists: List) suspend fun favoritePlaylist(): PlaylistEntity suspend fun isFavoriteSong(songEntity: SongEntity): List suspend fun addSongToHistory(currentSong: Song) @@ -117,7 +118,8 @@ class RealRepository( override suspend fun lyrics(artist: String, title: String): Result = try { Success(lyricsRestService.getLyrics(artist, title)) } catch (e: Exception) { - Error + println(e) + Error(e) } override suspend fun deleteSongs(songs: List) = roomRepository.deleteSongs(songs) @@ -169,7 +171,7 @@ class RealRepository( Success(lastFMService.artistInfo(name, lang, cache)) } catch (e: Exception) { println(e) - Error + Error(e) } } @@ -182,7 +184,7 @@ class RealRepository( Success(lastFmAlbum) } catch (e: Exception) { println(e) - Error + Error(e) } } @@ -206,7 +208,7 @@ class RealRepository( } } if (homeSections.isEmpty()) { - homes.value = Error + homes.value = Error(Exception(Throwable("No items"))) } else { homes.value = Success(homeSections) } @@ -244,6 +246,9 @@ class RealRepository( it.toSong() } + override fun playlistSongs(playlistEntity: PlaylistEntity): LiveData> = + roomRepository.getSongs(playlistEntity) + override suspend fun insertSongs(songs: List) = roomRepository.insertSongs(songs) @@ -267,8 +272,8 @@ class RealRepository( override suspend fun removeSongFromPlaylist(songEntity: SongEntity) = roomRepository.removeSongFromPlaylist(songEntity) - override suspend fun deleteSongsFromPlaylist(playlists: List) = - roomRepository.deleteSongsFromPlaylist(playlists) + override suspend fun deletePlaylistSongs(playlists: List) = + roomRepository.deletePlaylistSongs(playlists) override suspend fun favoritePlaylist(): PlaylistEntity = roomRepository.favoritePlaylist(context.getString(R.string.favorites)) @@ -368,7 +373,7 @@ class RealRepository( emit(Loading) val data = songRepository.songs() if (data.isEmpty()) { - emit(Error) + emit(Error(Exception(Throwable("No items")))) } else { emit(Success(data)) } @@ -378,7 +383,7 @@ class RealRepository( emit(Loading) val data = albumRepository.albums() if (data.isEmpty()) { - emit(Error) + emit(Error(Exception(Throwable("No items")))) } else { emit(Success(data)) } @@ -388,7 +393,7 @@ class RealRepository( emit(Loading) val data = artistRepository.artists() if (data.isEmpty()) { - emit(Error) + emit(Error(Exception(Throwable("No items")))) } else { emit(Success(data)) } @@ -398,7 +403,7 @@ class RealRepository( emit(Loading) val data = playlistRepository.playlists() if (data.isEmpty()) { - emit(Error) + emit(Error(Exception(Throwable("No items")))) } else { emit(Success(data)) } @@ -408,7 +413,7 @@ class RealRepository( emit(Loading) val data = genreRepository.genres() if (data.isEmpty()) { - emit(Error) + emit(Error(Exception(Throwable("No items")))) } else { emit(Success(data)) } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index 24c9e65b..9ded5b73 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -11,16 +11,16 @@ interface RoomRepository { fun favoritePlaylistLiveData(favorite: String): LiveData> fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity) fun observableHistorySongs(): LiveData> + fun getSongs(playlistEntity: PlaylistEntity): LiveData> suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun checkPlaylistExists(playlistName: String): List suspend fun playlists(): List suspend fun playlistWithSongs(): List suspend fun insertSongs(songs: List) - suspend fun getSongs(playlistEntity: PlaylistEntity): List suspend fun deletePlaylistEntities(playlistEntities: List) suspend fun renamePlaylistEntity(playlistId: Int, name: String) suspend fun deleteSongsInPlaylist(songs: List) - suspend fun deleteSongsFromPlaylist(playlists: List) + suspend fun deletePlaylistSongs(playlists: List) suspend fun favoritePlaylist(favorite: String): PlaylistEntity suspend fun isFavoriteSong(songEntity: SongEntity): List suspend fun removeSongFromPlaylist(songEntity: SongEntity) @@ -45,7 +45,8 @@ class RealRoomRepository( private val playlistDao: PlaylistDao, private val blackListStoreDao: BlackListStoreDao, private val playCountDao: PlayCountDao, - private val historyDao: HistoryDao + private val historyDao: HistoryDao, + private val lyricsDao: LyricsDao ) : RoomRepository { @WorkerThread override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = @@ -66,7 +67,7 @@ class RealRoomRepository( override suspend fun insertSongs(songs: List) = playlistDao.insertSongsToPlaylist(songs) - override suspend fun getSongs(playlistEntity: PlaylistEntity): List = + override fun getSongs(playlistEntity: PlaylistEntity): LiveData> = playlistDao.songsFromPlaylist(playlistEntity.playListId) override suspend fun deletePlaylistEntities(playlistEntities: List) = @@ -75,12 +76,15 @@ class RealRoomRepository( override suspend fun renamePlaylistEntity(playlistId: Int, name: String) = playlistDao.renamePlaylist(playlistId, name) - override suspend fun deleteSongsInPlaylist(songs: List) = - playlistDao.deleteSongsInPlaylist(songs) + override suspend fun deleteSongsInPlaylist(songs: List) { + songs.forEach { + playlistDao.deleteSongFromPlaylist(it.playlistCreatorId, it.id) + } + } - override suspend fun deleteSongsFromPlaylist(playlists: List) = + override suspend fun deletePlaylistSongs(playlists: List) = playlists.forEach { - playlistDao.deleteSongsInPlaylist(it.playListId) + playlistDao.deletePlaylistSongs(it.playListId) } override suspend fun favoritePlaylist(favorite: String): PlaylistEntity { @@ -100,7 +104,7 @@ class RealRoomRepository( ) override suspend fun removeSongFromPlaylist(songEntity: SongEntity) = - playlistDao.removeSongFromPlaylist(songEntity.playlistCreatorId, songEntity.id) + playlistDao.deleteSongFromPlaylist(songEntity.playlistCreatorId, songEntity.id) override suspend fun addSongToHistory(currentSong: Song) = historyDao.insertSongInHistory(currentSong.toHistoryEntity(System.currentTimeMillis())) diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index 9b4d427e..88333684 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -35,7 +35,6 @@ object PreferenceUtil { CategoryInfo(CategoryInfo.Category.Artists, true), CategoryInfo(CategoryInfo.Category.Playlists, true), CategoryInfo(CategoryInfo.Category.Genres, false), - CategoryInfo(CategoryInfo.Category.Queue, false), CategoryInfo(CategoryInfo.Category.Folder, false) ) diff --git a/app/src/main/res/layout/lyrics_dialog.xml b/app/src/main/res/layout/lyrics_dialog.xml index 27fa8a95..47f15438 100644 --- a/app/src/main/res/layout/lyrics_dialog.xml +++ b/app/src/main/res/layout/lyrics_dialog.xml @@ -4,30 +4,57 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:padding="16dp"> + android:background="?attr/colorSurface" + android:padding="8dp"> + + + app:layout_constraintTop_toBottomOf="@id/dialogTitle"> - + android:layout_height="wrap_content"> + + + + + - + app:layout_constraintEnd_toEndOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/navigation/library_graph.xml b/app/src/main/res/navigation/library_graph.xml index fca6df57..3d670797 100644 --- a/app/src/main/res/navigation/library_graph.xml +++ b/app/src/main/res/navigation/library_graph.xml @@ -30,11 +30,6 @@ android:name="code.name.monkey.retromusic.fragments.playlists.PlaylistsFragment" tools:layout="@layout/fragment_main_activity_recycler_view" /> - - = 28 */ + @JvmStatic fun hasQ(): Boolean { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q } diff --git a/build.gradle b/build.gradle index 194f9bfd..94e3964a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.72' + ext.kotlin_version = '1.4.10' repositories { jcenter() google() From cc494edbbf9e93b3bd23dd13638f218320460744 Mon Sep 17 00:00:00 2001 From: Hemanth S Date: Sat, 12 Sep 2020 12:23:23 +0530 Subject: [PATCH 46/46] Fix songs not loading from SD card --- .../main/java/code/name/monkey/retromusic/db/PlayCountDao.kt | 3 +++ .../java/code/name/monkey/retromusic/db/RetroDatabase.kt | 2 +- .../main/java/code/name/monkey/retromusic/db/SongEntity.kt | 4 ++-- .../code/name/monkey/retromusic/repository/RoomRepository.kt | 5 ++++- .../code/name/monkey/retromusic/repository/SongRepository.kt | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt index 17868e7e..0c3fbbae 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt @@ -21,4 +21,7 @@ interface PlayCountDao { @Query("DELETE FROM SongEntity WHERE id =:songId") fun deleteSong(songId: Int) + + @Query("UPDATE PlayCountEntity SET play_count = play_count + 1 WHERE id = :id") + fun updateQuantity(id: Int) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt index cda6eddd..6be545b6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt @@ -5,7 +5,7 @@ import androidx.room.RoomDatabase @Database( entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class, LyricsEntity::class], - version = 21, + version = 22, exportSchema = false ) abstract class RetroDatabase : RoomDatabase() { diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt index 1d9b13f7..19a50fe0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -3,11 +3,12 @@ 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 +@Entity(indices = [Index(value = ["playlist_creator_id", "id"], unique = true)]) class SongEntity( @ColumnInfo(name = "playlist_creator_id") val playlistCreatorId: Int, @@ -35,6 +36,5 @@ class SongEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "song_key") var songPrimaryKey: Long = 0 - } diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index 9ded5b73..16100176 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -64,8 +64,11 @@ class RealRoomRepository( playlistDao.playlistsWithSongs() @WorkerThread - override suspend fun insertSongs(songs: List) = + override suspend fun insertSongs(songs: List) { + playlistDao.insertSongsToPlaylist(songs) + } + override fun getSongs(playlistEntity: PlaylistEntity): LiveData> = playlistDao.songsFromPlaylist(playlistEntity.playListId) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index 41df3e29..fcfded6a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -155,7 +155,7 @@ class RealSongRepository(private val context: Context) : SongRepository { val uri = if (VersionUtils.hasQ()) { - MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) + MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) } else { MediaStore.Audio.Media.EXTERNAL_CONTENT_URI }
App version" + versionName + "
App version" + versionName + "
App version code" + versionCode + "
Android build version" + buildVersion + "
Android release version" + releaseVersion + "