Changes Playlist to PlaylistEntity

This commit is contained in:
Hemanth S 2020-08-20 15:22:38 +05:30
parent b5e07a31d8
commit a93dcb0285
14 changed files with 115 additions and 89 deletions

View file

@ -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

View file

@ -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<RoomPlaylistRepository>()
lifecycleScope.launch {
println("Size:${playlistRepository.playlistWithSongs()}")
}
}
override fun onSupportNavigateUp(): Boolean =

View file

@ -9,7 +9,7 @@ interface PlaylistDao {
suspend fun checkPlaylistExists(name: String): List<PlaylistEntity>
@Insert
suspend fun createPlaylist(playlistEntity: PlaylistEntity)
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
@Query("SELECT * FROM PlaylistEntity")
suspend fun playlists(): List<PlaylistEntity>
@ -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<SongEntity>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId ORDER BY song_key")
suspend fun getSongs(playlistId: Int): List<SongEntity>
}

View file

@ -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<SongEntity>
)
)
val songs: List<SongEntity>
):Parcelable

View file

@ -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<PlaylistEntity>
suspend fun playlists(): List<PlaylistEntity>
suspend fun playlistWithSongs(): List<PlaylistWithSongs>
suspend fun insertSongs(songs: List<SongEntity>)
suspend fun getSongs(playlistEntity: PlaylistEntity): List<SongEntity>
}
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<SongEntity>) {
/* val tempList = ArrayList<SongEntity>(songs)
val existingSongs = songs.map {
playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId)
}.first()
println("Existing ${existingSongs.size}")
tempList.removeAll(existingSongs)*/
/* val tempList = ArrayList<SongEntity>(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<SongEntity> {
return playlistDao.getSongs(playlistEntity.playListId)
}
}

View file

@ -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

View file

@ -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<RoomPlaylistRepository>()
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
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"

View file

@ -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,
}

View file

@ -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<Song>) {
progressIndicator.hide()
if (songs.isNotEmpty()) {
adapter.swapDataSet(songs)
} else {
showEmptyView()
}
}
}

View file

@ -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<List<Song>>()
private val _playlist = MutableLiveData<Playlist>().apply {
private val _playlist = MutableLiveData<PlaylistWithSongs>().apply {
postValue(playlist)
}
fun getPlaylist(): LiveData<Playlist> = _playlist
fun getPlaylist(): LiveData<PlaylistWithSongs> = _playlist
fun getSongs(): LiveData<List<Song>> = _playListSongs
@ -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<Song> = 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() {}

View file

@ -88,6 +88,8 @@ interface Repository {
suspend fun playlistWithSongs(): List<PlaylistWithSongs>
suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song>
fun songsFlow(): Flow<Result<List<Song>>>
fun albumsFlow(): Flow<Result<List<Album>>>
@ -223,6 +225,12 @@ class RealRepository(
override suspend fun playlistWithSongs(): List<PlaylistWithSongs> =
roomPlaylistRepository.playlistWithSongs()
override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs ): List<Song> {
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<Song>()
else emptyList()
return Home(songs, FAVOURITES)
}

View file

@ -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(

View file

@ -70,4 +70,12 @@
android:textColor="?android:attr/textColorSecondary"
tools:visibility="visible" />
</LinearLayout>
<com.google.android.material.progressindicator.ProgressIndicator
android:layout_width="100dp"
android:id="@+id/progressIndicator"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:gravity="center" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -26,7 +26,7 @@
tools:layout="@layout/fragment_playlist_detail">
<argument
android:name="extra_playlist"
app:argType="code.name.monkey.retromusic.model.Playlist" />
app:argType="code.name.monkey.retromusic.db.PlaylistWithSongs" />
</fragment>
<fragment