⬇️ Import legacy playlists

This commit is contained in:
Hemanth S 2020-09-06 01:43:45 +05:30
parent 51d2c17ad7
commit 45b93ed3aa
13 changed files with 175 additions and 65 deletions

View file

@ -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<Song> =
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,

View file

@ -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<PlaylistWithSongs>): List<Song> {
val songs = ArrayList<Song>()
/* 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<Song>()
playlists.forEach {
songs.addAll(it.songs.toSongs())
}
return songs
}
private fun getSongs(playlist: PlaylistWithSongs): List<SongEntity> {
val songs = ArrayList<SongEntity>()
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<SongEntity> =
mutableListOf<SongEntity>().apply {
addAll(playlist.songs)
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init {

View file

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

View file

@ -1,7 +0,0 @@
package code.name.monkey.retromusic.dialogs
import androidx.fragment.app.DialogFragment
class ImportPlaylist : DialogFragment() {
}

View file

@ -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<LegacyPlaylistAdapter, LinearLayoutManager>(), 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<Playlist>,
private val layoutRes: Int,
private val playlistClickListener: PlaylistClickListener
) :
RecyclerView.Adapter<LegacyPlaylistAdapter.ViewHolder>() {
fun swapData(list: List<Playlist>) {
this.list = list
notifyDataSetChanged()
}
class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(layoutRes, parent, false)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val playlist: Playlist = list[position]
holder.title?.text = playlist.name
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, playlist.getSongs())
holder.itemView.setOnClickListener {
playlistClickListener.onPlaylistClick(playlist)
}
}
override fun getItemCount(): Int {
return list.size
}
}
interface PlaylistClickListener {
fun onPlaylistClick(playlist: Playlist)
}

View file

@ -24,6 +24,7 @@ class LibraryViewModel(
private val songs = MutableLiveData<List<Song>>()
private val artists = MutableLiveData<List<Artist>>()
private val playlists = MutableLiveData<List<PlaylistWithSongs>>()
private val legacyPlaylists = MutableLiveData<List<Playlist>>()
private val genres = MutableLiveData<List<Genre>>()
private val home = MutableLiveData<List<Home>>()
@ -58,6 +59,11 @@ class LibraryViewModel(
return playlists
}
fun getLegacyPlaylist(): LiveData<List<Playlist>> {
fetchLegacyPlaylist()
return legacyPlaylists
}
fun getGenre(): LiveData<List<Genre>> {
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<PlaylistEntity> =
repository.checkPlaylistExists(playlistName)
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
repository.createPlaylist(playlistEntity)
}
enum class ReloadType {

View file

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

View file

@ -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<PlaylistAdapter, GridLayoutManager>() {
class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -28,8 +28,8 @@ class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutMan
override val emptyMessage: Int
get() = R.string.no_playlists
override fun createLayoutManager(): GridLayoutManager {
return GridLayoutManager(requireContext(), 1)
override fun createLayoutManager(): LinearLayoutManager {
return LinearLayoutManager(requireContext())
}
override fun createAdapter(): PlaylistAdapter {
@ -51,7 +51,7 @@ class PlaylistsFragment : AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutMan
menu.removeItem(R.id.action_layout_type)
menu.removeItem(R.id.action_sort_order)
menu.add(0, R.id.action_add_to_playlist, 0, R.string.new_playlist_title)
.setIcon(R.drawable.ic_playlist_add)
menu.add(0, R.id.action_import_playlist, 0, R.string.import_playlist)
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
super.onCreateOptionsMenu(menu, inflater)
}

View file

@ -43,7 +43,7 @@ interface Repository {
suspend fun allSongs(): List<Song>
suspend fun fetchArtists(): List<Artist>
suspend fun albumArtists(): List<Artist>
suspend fun allPlaylists(): List<Playlist>
suspend fun fetchLegacyPlaylist(): List<Playlist>
suspend fun fetchGenres(): List<Genre>
suspend fun search(query: String?): MutableList<Any>
suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
@ -125,7 +125,7 @@ class RealRepository(
override suspend fun topAlbums(): List<Album> = topPlayedRepository.topAlbums()
override suspend fun allPlaylists(): List<Playlist> = playlistRepository.playlists()
override suspend fun fetchLegacyPlaylist(): List<Playlist> = playlistRepository.playlists()
override suspend fun fetchGenres(): List<Genre> = genreRepository.genres()

View file

@ -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" />
</LinearLayout>

View file

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

View file

@ -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" />
<fragment
android:id="@+id/action_import_playlist"
android:name="code.name.monkey.retromusic.dialogs.ImportPlaylistFragment"
android:label="ImportPlaylist"
tools:layout="@layout/fragment_main_activity_recycler_view" />
</navigation>

View file

@ -884,4 +884,5 @@
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="done">Done</string>
<string name="ok">Ok</string>
<string name="import_playlist">Import playlist</string>
</resources>