feat: Minor redesign in Playlist details page

This commit is contained in:
Prathamesh More 2023-03-08 17:29:25 +05:30
parent c6dd54d200
commit b9f3e7979b
12 changed files with 233 additions and 56 deletions

View file

@ -168,10 +168,10 @@ private val viewModules = module {
) )
} }
viewModel { (playlist: PlaylistWithSongs) -> viewModel { (playlistId: Long) ->
PlaylistDetailsViewModel( PlaylistDetailsViewModel(
get(), get(),
playlist playlistId
) )
} }

View file

@ -217,7 +217,7 @@ class SearchAdapter(
PLAYLIST -> { PLAYLIST -> {
activity.findNavController(R.id.fragment_container).navigate( activity.findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment, R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to (item as PlaylistWithSongs)) bundleOf(EXTRA_PLAYLIST_ID to (item as PlaylistWithSongs).playlistEntity.playListId)
) )
} }

View file

@ -24,12 +24,8 @@ import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.db.toSongsEntity import code.name.monkey.retromusic.db.toSongsEntity
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.accentOutlineColor
import code.name.monkey.retromusic.fragments.LibraryViewModel 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.model.Song
import com.google.android.material.button.MaterialButton
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -37,11 +33,11 @@ import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
class OrderablePlaylistSongAdapter( class OrderablePlaylistSongAdapter(
private val playlist: PlaylistEntity, private val playlistId: Long,
activity: FragmentActivity, activity: FragmentActivity,
dataSet: MutableList<Song>, dataSet: MutableList<Song>,
itemLayoutRes: Int, itemLayoutRes: Int,
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes), ) : SongAdapter(activity, dataSet, itemLayoutRes),
DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> { DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
val libraryViewModel: LibraryViewModel by activity.viewModel() val libraryViewModel: LibraryViewModel by activity.viewModel()
@ -65,45 +61,20 @@ class OrderablePlaylistSongAdapter(
return ViewHolder(view) return ViewHolder(view)
} }
override fun getItemViewType(position: Int): Int {
return if (position == 0) OFFSET_ITEM else SONG
}
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
if (holder.itemViewType == OFFSET_ITEM) {
val viewHolder = holder as ViewHolder
viewHolder.playAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
it.accentOutlineColor()
}
viewHolder.shuffleAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
it.accentColor()
}
} else {
super.onBindViewHolder(holder, position - 1)
}
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) { override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
when (menuItem.itemId) { when (menuItem.itemId) {
R.id.action_remove_from_playlist -> RemoveSongFromPlaylistDialog.create( R.id.action_remove_from_playlist -> RemoveSongFromPlaylistDialog.create(
selection.toSongsEntity( selection.toSongsEntity(
playlist playlistId
) )
) )
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
else -> super.onMultipleItemAction(menuItem, selection) else -> super.onMultipleItemAction(menuItem, selection)
} }
} }
inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
override var songMenuRes: Int override var songMenuRes: Int
get() = R.menu.menu_item_playlist_song get() = R.menu.menu_item_playlist_song
@ -114,7 +85,7 @@ class OrderablePlaylistSongAdapter(
override fun onSongMenuItemClick(item: MenuItem): Boolean { override fun onSongMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_remove_from_playlist -> { R.id.action_remove_from_playlist -> {
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId)) RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlistId))
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
return true return true
} }
@ -147,7 +118,7 @@ class OrderablePlaylistSongAdapter(
} }
override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange { override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange {
return ItemDraggableRange(1, itemCount - 1) return ItemDraggableRange(0, itemCount - 1)
} }
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {

View file

@ -41,6 +41,10 @@ interface PlaylistDao {
@Query("SELECT * FROM PlaylistEntity") @Query("SELECT * FROM PlaylistEntity")
suspend fun playlistsWithSongs(): List<PlaylistWithSongs> suspend fun playlistsWithSongs(): List<PlaylistWithSongs>
@Transaction
@Query("SELECT * FROM PlaylistEntity WHERE playlist_id= :playlistId")
fun getPlaylist(playlistId: Long): LiveData<PlaylistWithSongs>
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>) suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)

View file

@ -145,3 +145,9 @@ fun List<Song>.toSongsEntity(playlistEntity: PlaylistEntity): List<SongEntity> {
it.toSongEntity(playlistEntity.playListId) it.toSongEntity(playlistEntity.playListId)
} }
} }
fun List<Song>.toSongsEntity(playlistId: Long): List<SongEntity> {
return map {
it.toSongEntity(playlistId)
}
}

View file

@ -14,15 +14,21 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailBinding import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailNewBinding
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.elevatedAccentColor
import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.RetroGlideExtension.playlistOptions
import code.name.monkey.retromusic.glide.playlistPreview.PlaylistPreview
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.ThemedFastScroller import code.name.monkey.retromusic.util.ThemedFastScroller
import com.bumptech.glide.Glide
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialArcMotion import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform import com.google.android.material.transition.MaterialContainerTransform
@ -34,13 +40,13 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail) { class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail_new) {
private val arguments by navArgs<PlaylistDetailsFragmentArgs>() private val arguments by navArgs<PlaylistDetailsFragmentArgs>()
private val viewModel by viewModel<PlaylistDetailsViewModel> { private val viewModel by viewModel<PlaylistDetailsViewModel> {
parametersOf(arguments.extraPlaylist) parametersOf(arguments.extraPlaylistId)
} }
private var _binding: FragmentPlaylistDetailBinding? = null private var _binding: FragmentPlaylistDetailNewBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var playlist: PlaylistWithSongs private lateinit var playlist: PlaylistWithSongs
@ -58,16 +64,26 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlaylistDetailBinding.bind(view) _binding = FragmentPlaylistDetailNewBinding.bind(view)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view) enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
mainActivity.setSupportActionBar(binding.toolbar) mainActivity.setSupportActionBar(binding.toolbar)
binding.container.transitionName = "playlist" binding.toolbar.title = null
playlist = arguments.extraPlaylist // binding.container.transitionName = playlist.playlistEntity.playlistName
binding.toolbar.title = playlist.playlistEntity.playlistName
binding.toolbar.subtitle =
MusicUtil.getPlaylistInfoString(requireContext(), playlist.songs.toSongs())
setUpRecyclerView() setUpRecyclerView()
setupButtons()
viewModel.getPlaylist().observe(viewLifecycleOwner) { playlistWithSongs ->
playlist = playlistWithSongs
Glide.with(this)
.load(PlaylistPreview(playlist))
.playlistOptions()
.into(binding.image)
binding.title.text = playlist.playlistEntity.playlistName
binding.subtitle.text =
MusicUtil.getPlaylistInfoString(requireContext(), playlist.songs.toSongs())
binding.collapsingAppBarLayout.title = playlist.playlistEntity.playlistName
}
viewModel.getSongs().observe(viewLifecycleOwner) { viewModel.getSongs().observe(viewLifecycleOwner) {
songs(it.toSongs()) songs(it.toSongs())
} }
@ -82,9 +98,24 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
MaterialShapeDrawable.createWithElevationOverlay(requireContext()) MaterialShapeDrawable.createWithElevationOverlay(requireContext())
} }
private fun setupButtons() {
binding.playButton.apply {
setOnClickListener {
MusicPlayerRemote.openQueue(playlistSongAdapter.dataSet, 0, true)
}
accentColor()
}
binding.shuffleButton.apply {
setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(playlistSongAdapter.dataSet, true)
}
elevatedAccentColor()
}
}
private fun setUpRecyclerView() { private fun setUpRecyclerView() {
playlistSongAdapter = OrderablePlaylistSongAdapter( playlistSongAdapter = OrderablePlaylistSongAdapter(
playlist.playlistEntity, arguments.extraPlaylistId,
requireActivity(), requireActivity(),
ArrayList(), ArrayList(),
R.layout.item_queue R.layout.item_queue

View file

@ -18,15 +18,18 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
class PlaylistDetailsViewModel( class PlaylistDetailsViewModel(
private val realRepository: RealRepository, private val realRepository: RealRepository,
private var playlist: PlaylistWithSongs private var playlistId: Long
) : ViewModel() { ) : ViewModel() {
fun getSongs(): LiveData<List<SongEntity>> = fun getSongs(): LiveData<List<SongEntity>> =
realRepository.playlistSongs(playlist.playlistEntity.playListId) realRepository.playlistSongs(playlistId)
fun playlistExists(): LiveData<Boolean> = fun playlistExists(): LiveData<Boolean> =
realRepository.checkPlaylistExists(playlist.playlistEntity.playListId) realRepository.checkPlaylistExists(playlistId)
fun getPlaylist(): LiveData<PlaylistWithSongs> = realRepository.getPlaylist(playlistId)
} }

View file

@ -21,6 +21,7 @@ import androidx.core.view.MenuCompat
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.EXTRA_PLAYLIST import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
@ -244,7 +245,7 @@ class PlaylistsFragment :
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
findNavController().navigate( findNavController().navigate(
R.id.playlistDetailsFragment, R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to playlistWithSongs) bundleOf(EXTRA_PLAYLIST_ID to playlistWithSongs.playlistEntity.playListId)
) )
} }
} }

View file

@ -99,6 +99,7 @@ interface Repository {
suspend fun isSongFavorite(songId: Long): Boolean suspend fun isSongFavorite(songId: Long): Boolean
fun getSongByGenre(genreId: Long): Song fun getSongByGenre(genreId: Long): Song
fun checkPlaylistExists(playListId: Long): LiveData<Boolean> fun checkPlaylistExists(playListId: Long): LiveData<Boolean>
fun getPlaylist(playlistId: Long): LiveData<PlaylistWithSongs>
} }
class RealRepository( class RealRepository(
@ -223,6 +224,8 @@ class RealRepository(
override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> = override suspend fun fetchPlaylistWithSongs(): List<PlaylistWithSongs> =
roomRepository.playlistWithSongs() roomRepository.playlistWithSongs()
override fun getPlaylist(playlistId: Long): LiveData<PlaylistWithSongs> = roomRepository.getPlaylist(playlistId)
override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song> = override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song> =
playlistWithSongs.songs.map { playlistWithSongs.songs.map {
it.toSong() it.toSong()

View file

@ -44,6 +44,7 @@ interface RoomRepository {
suspend fun deleteSongs(songs: List<Song>) suspend fun deleteSongs(songs: List<Song>)
suspend fun isSongFavorite(context: Context, songId: Long): Boolean suspend fun isSongFavorite(context: Context, songId: Long): Boolean
fun checkPlaylistExists(playListId: Long): LiveData<Boolean> fun checkPlaylistExists(playListId: Long): LiveData<Boolean>
fun getPlaylist(playlistId: Long): LiveData<PlaylistWithSongs>
} }
class RealRoomRepository( class RealRoomRepository(
@ -81,6 +82,9 @@ class RealRoomRepository(
} }
} }
@WorkerThread
override fun getPlaylist(playlistId: Long): LiveData<PlaylistWithSongs> = playlistDao.getPlaylist(playlistId)
@WorkerThread @WorkerThread
override suspend fun insertSongs(songs: List<SongEntity>) { override suspend fun insertSongs(songs: List<SongEntity>) {

View file

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:transitionGroup="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:liftOnScroll="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingAppBarLayout"
style="?attr/collapsingToolbarLayoutLargeStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:expandedTitleTextColor="@color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="?actionBarSize"
android:paddingBottom="16dp"
android:paddingHorizontal="16dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@+id/title"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintHorizontal_weight="0.4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="?shapeAppearanceCornerExtraLarge"
tools:src="@tools:sample/avatars[0]" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textAppearance="?textAppearanceDisplaySmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="0.6"
app:layout_constraintStart_toEndOf="@+id/image"
app:layout_constraintTop_toTopOf="@+id/image"
tools:text="Playlist" />
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="@+id/title"
app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Playlist" />
<com.google.android.material.button.MaterialButton
android:id="@+id/play_button"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:padding="16dp"
app:icon="@drawable/ic_play_arrow"
app:layout_constraintEnd_toStartOf="@+id/shuffle_button"
app:layout_constraintStart_toStartOf="@+id/subtitle"
app:layout_constraintTop_toBottomOf="@+id/subtitle" />
<com.google.android.material.button.MaterialButton
android:id="@+id/shuffle_button"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:backgroundTint="?colorTertiaryContainer"
android:padding="16dp"
app:icon="@drawable/ic_shuffle"
app:layout_constraintBottom_toBottomOf="@+id/play_button"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/play_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_arrow_back"
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<code.name.monkey.retromusic.views.insets.InsetsRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:layoutAnimation="@anim/layout_anim_fade"
android:overScrollMode="@integer/overScrollMode"
android:paddingBottom="@dimen/mini_player_height"
android:scrollbars="none"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:listitem="@layout/item_song" />
<LinearLayout
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/emptyEmoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/empty_text_emoji"
android:textAppearance="@style/TextViewHeadline3" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/emptyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/no_songs"
android:textAppearance="@style/TextViewHeadline5"
android:textColor="?android:attr/textColorSecondary"
tools:visibility="visible" />
</LinearLayout>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressIndicator"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:gravity="center"
android:indeterminate="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -20,8 +20,8 @@
android:label="PlaylistDetailsFragment" android:label="PlaylistDetailsFragment"
tools:layout="@layout/fragment_playlist_detail"> tools:layout="@layout/fragment_playlist_detail">
<argument <argument
android:name="extra_playlist" android:name="extra_playlist_id"
app:argType="code.name.monkey.retromusic.db.PlaylistWithSongs" /> app:argType="long" />
</fragment> </fragment>
<fragment <fragment