⬇️ Import legacy playlists
This commit is contained in:
parent
51d2c17ad7
commit
45b93ed3aa
13 changed files with 175 additions and 65 deletions
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package code.name.monkey.retromusic.dialogs
|
||||
|
||||
import androidx.fragment.app.DialogFragment
|
||||
|
||||
class ImportPlaylist : DialogFragment() {
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue