Merge pull request #720 from h4h13/songAdapterRefactor

Song adapter refactor
This commit is contained in:
Hemanth S 2020-04-26 15:50:15 +05:30 committed by GitHub
commit 85ef05f6ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 210 additions and 83 deletions

View file

@ -2,11 +2,13 @@ package code.name.monkey.retromusic.adapter.song
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import com.google.android.material.button.MaterialButton
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.textview.MaterialTextView
class ShuffleButtonSongAdapter(
activity: AppCompatActivity,
@ -15,34 +17,75 @@ class ShuffleButtonSongAdapter(
cabHolder: CabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) {
override fun createViewHolder(view: View): SongAdapter.ViewHolder {
override fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view)
}
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
if (holder.itemViewType == OFFSET_ITEM) {
val viewHolder = holder as ViewHolder
viewHolder.playAction?.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
val info =
activity.resources.getQuantityString(
R.plurals.numSongs,
dataSet.size,
dataSet.size
)
viewHolder.info?.text = info
viewHolder.shuffleAction?.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
showChangeLayout(viewHolder)
showSortMenu(viewHolder)
} else {
super.onBindViewHolder(holder, position - 1)
}
}
inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
private fun showChangeLayout(viewHolder: ViewHolder) {
viewHolder.changeLayoutType?.setOnClickListener {
val popupMenu = PopupMenu(activity, viewHolder.changeLayoutType)
popupMenu.inflate(R.menu.menu_layout_types)
popupMenu.setOnMenuItemClickListener {
when (it.itemId) {
R.layout.item_card ->
popupMenu.menu.findItem(R.id.action_layout_card).isChecked = true
R.layout.item_grid ->
popupMenu.menu.findItem(R.id.action_layout_normal).isChecked = true
override fun onClick(v: View?) {
if (itemViewType == OFFSET_ITEM) {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
return
R.layout.item_card_color ->
popupMenu.menu.findItem(R.id.action_layout_colored_card).isChecked = true
R.layout.item_grid_circle ->
popupMenu.menu.findItem(R.id.action_layout_circular).isChecked = true
R.layout.image ->
popupMenu.menu.findItem(R.id.action_layout_image).isChecked = true
R.layout.item_image_gradient ->
popupMenu.menu.findItem(R.id.action_layout_gradient_image).isChecked = true
}
super.onClick(v)
PreferenceUtil.getInstance(activity).songGridStyle = it.itemId
true
}
popupMenu.show()
popupMenu.menu
.findItem(PreferenceUtil.getInstance(activity).songGridStyle).isChecked = true
}
}
private fun showSortMenu(viewHolder: ViewHolder) {
viewHolder.sortOrder?.setOnClickListener {
val popupMenu = PopupMenu(activity, viewHolder.sortOrder)
popupMenu.inflate(R.menu.menu_song_sort_order)
popupMenu.show()
}
}
inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
val sortOrder: View? = itemView.findViewById(R.id.sortOrder)
val changeLayoutType: View? = itemView.findViewById(R.id.changeLayoutType)
val shuffleAction: View? = itemView.findViewById(R.id.shuffleAction)
val info: MaterialTextView? = itemView.findViewById(R.id.info)
}
}

View file

@ -86,7 +86,7 @@ class BlacklistFolderChooserDialog : DialogFragment() {
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
return MaterialDialog(requireActivity(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
return MaterialDialog(requireActivity()).show {
title(R.string.md_error_label)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
message(R.string.md_storage_perm_error)
@ -103,7 +103,7 @@ class BlacklistFolderChooserDialog : DialogFragment() {
checkIfCanGoUp()
parentContents = listFiles()
return MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
return MaterialDialog(requireContext()).show {
title(text = parentFolder!!.absolutePath)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
listItems(items = contentsArray(), waitForPositiveButton = false) { _, index, _ ->

View file

@ -14,23 +14,27 @@
package code.name.monkey.retromusic.model
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import code.name.monkey.retromusic.room.SongEntity
import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "playing_queue")
open class Song(
val id: Int,
val title: String,
val trackNumber: Int,
val year: Int,
val duration: Long,
val data: String,
val dateModified: Long,
val albumId: Int,
val albumName: String,
val artistId: Int,
val artistName: String,
val composer: String?
@PrimaryKey val id: Int,
@ColumnInfo(name = "title") val title: String,
@ColumnInfo(name = "track_number") val trackNumber: Int,
@ColumnInfo(name = "year") val year: Int,
@ColumnInfo(name = "duration") val duration: Long,
@ColumnInfo(name = "data") 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,
@ColumnInfo(name = "composer") val composer: String?
) : Parcelable {

View file

@ -28,9 +28,7 @@ import code.name.monkey.retromusic.dialogs.BlacklistFolderChooserDialog
import code.name.monkey.retromusic.extensions.colorControlNormal
import code.name.monkey.retromusic.providers.BlacklistStore
import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems
import java.io.File
import java.util.*
@ -59,23 +57,23 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val blacklistFolderChooserDialog =
val chooserDialog =
childFragmentManager.findFragmentByTag("FOLDER_CHOOSER") as BlacklistFolderChooserDialog?
blacklistFolderChooserDialog?.setCallback(this)
chooserDialog?.setCallback(this)
refreshBlacklistData()
return MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(code.name.monkey.retromusic.R.string.blacklist)
return MaterialDialog(requireContext()).show {
title(R.string.blacklist)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
positiveButton(android.R.string.ok) {
dismiss()
}
neutralButton(text = getString(R.string.clear_action)) {
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
MaterialDialog(requireContext()).show {
title(code.name.monkey.retromusic.R.string.clear_blacklist)
message(code.name.monkey.retromusic.R.string.do_you_want_to_clear_the_blacklist)
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
positiveButton(code.name.monkey.retromusic.R.string.clear_action) {
BlacklistStore.getInstance(context).clear()
BlacklistStore.getInstance(requireContext()).clear()
refreshBlacklistData()
}
negativeButton(android.R.string.cancel)
@ -87,20 +85,21 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
dialog.show(childFragmentManager, "FOLDER_CHOOSER")
}
listItems(items = paths, waitForPositiveButton = false) { _, _, text ->
MaterialDialog(context, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
MaterialDialog(requireContext()).show {
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
title(code.name.monkey.retromusic.R.string.remove_from_blacklist)
message(
text = HtmlCompat.fromHtml(
getString(
code.name.monkey.retromusic.R.string.do_you_want_to_remove_from_the_blacklist,
R.string.do_you_want_to_remove_from_the_blacklist,
text
),
HtmlCompat.FROM_HTML_MODE_LEGACY
)
)
positiveButton(code.name.monkey.retromusic.R.string.remove_action) {
BlacklistStore.getInstance(context).removePath(File(text.toString()))
BlacklistStore.getInstance(requireContext())
.removePath(File(text.toString()))
refreshBlacklistData()
}
negativeButton(android.R.string.cancel)
@ -113,13 +112,13 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
private lateinit var paths: ArrayList<String>
private fun refreshBlacklistData() {
this.paths = BlacklistStore.getInstance(context!!).paths
this.paths = BlacklistStore.getInstance(requireContext()).paths
val dialog = dialog as MaterialDialog?
dialog?.listItems(items = paths)
}
override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) {
BlacklistStore.getInstance(context!!).addPath(folder)
BlacklistStore.getInstance(requireContext()).addPath(folder)
refreshBlacklistData()
}
}

View file

@ -4,8 +4,9 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import code.name.monkey.retromusic.model.Song
@Database(entities = [SongEntity::class], version = 2, exportSchema = false)
@Database(entities = [Song::class, SongEntity::class], version = 3, exportSchema = false)
abstract class MusicPlaybackQueueStoreDatabase : RoomDatabase() {
abstract fun queueDao(): QueueDao

View file

@ -1,16 +1,18 @@
package code.name.monkey.retromusic.room
import code.name.monkey.retromusic.model.Song
class MusicQueueRepository(private val queueDao: QueueDao) {
fun getQueue(): List<SongEntity> = queueDao.getQueue()
fun getQueue(): List<Song> = queueDao.getQueue()
fun getOriginalQueue(): List<SongEntity> = queueDao.getQueue()
fun getOriginalQueue(): List<SongEntity> = queueDao.getOriginalQueue()
suspend fun insertQueue(queue: List<SongEntity>) {
suspend fun insertQueue(queue: List<Song>) {
queueDao.saveQueue(queue)
}
suspend fun insertOriginalQueue(queue: List<SongEntity>) {
queueDao.saveQueue(queue)
queueDao.saveOriginalQueue(queue)
}
}

View file

@ -12,31 +12,19 @@ class NowPlayingQueue(context: Context) {
private val musicQueueRepository: MusicQueueRepository = MusicQueueRepository(queueDao)
fun saveQueue(songs: List<Song>) = GlobalScope.launch(Dispatchers.IO) {
val songEntity = songs.map {
Song.toSongEntity(it)
}
musicQueueRepository.insertQueue(songEntity)
fun saveQueue(songs: List<Song>) = GlobalScope.launch(Dispatchers.Default) {
musicQueueRepository.insertQueue(songs)
}
fun saveOriginalQueue(playingQueue: List<Song>) = GlobalScope.launch(Dispatchers.IO) {
val songEntity = playingQueue.map {
Song.toSongEntity(it)
}
musicQueueRepository.insertOriginalQueue(songEntity)
fun saveOriginalQueue(songs: List<Song>) = GlobalScope.launch(Dispatchers.Default) {
musicQueueRepository.insertOriginalQueue(songs.map { Song.toSongEntity(it) })
}
fun getQueue(): List<Song> {
val songEntity = musicQueueRepository.getQueue()
return songEntity.map {
SongEntity.toSong(it)
}
return musicQueueRepository.getQueue()
}
fun getOriginalQueue(): List<Song> {
val songEntity = musicQueueRepository.getOriginalQueue()
return songEntity.map {
SongEntity.toSong(it)
}
return musicQueueRepository.getOriginalQueue().map { SongEntity.toSong(it) }
}
}

View file

@ -4,6 +4,7 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import code.name.monkey.retromusic.model.Song
/**
* Created by hemanths on 2020-02-23.
@ -12,12 +13,15 @@ import androidx.room.Query
interface QueueDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun saveQueue(playingQueue: List<SongEntity>)
suspend fun saveQueue(playingQueue: List<Song>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun saveOriginalQueue(playingQueue: List<SongEntity>)
@Query("SELECT * FROM song_entity")
fun getQueue(): List<SongEntity>
@Query("SELECT * FROM playing_queue")
fun getQueue(): List<Song>
@Query("SELECT * FROM song_entity")
@Query("SELECT * FROM original_playing_queue")
fun getOriginalQueue(): List<SongEntity>
}

View file

@ -5,7 +5,7 @@ import androidx.room.Entity
import androidx.room.PrimaryKey
import code.name.monkey.retromusic.model.Song
@Entity(tableName = "song_entity")
@Entity(tableName = "original_playing_queue")
class SongEntity(
@PrimaryKey val id: Int,
@ColumnInfo(name = "title") val title: String,

View file

@ -12,33 +12,71 @@
~ See the GNU General Public License for more details.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/playAction"
<com.google.android.material.textview.MaterialTextView
android:id="@+id/info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/gridSize"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/gridSize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:padding="16dp"
android:text="@string/action_play_all"
app:backgroundTint="?attr/colorSurface"
app:icon="@drawable/ic_play_arrow_white_24dp" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/sortOrder"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_grid_size_white_24dp"
app:tint="?android:attr/colorControlNormal" />
<com.google.android.material.button.MaterialButton
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/sortOrder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/action_play_all"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/changeLayoutType"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_sort_white_24dp"
app:tint="?android:attr/colorControlNormal" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/changeLayoutType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/action_play_all"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/shuffleAction"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_dashboard_white_24dp"
app:tint="?android:attr/colorControlNormal" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/shuffleAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:padding="16dp"
android:text="@string/shuffle"
app:backgroundTint="?attr/colorSurface"
app:icon="@drawable/ic_shuffle_white_24dp" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_shuffle_white_24dp"
app:tint="?android:attr/colorControlNormal" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="@+id/group_layout_type"
android:checkableBehavior="single">
<item
android:id="@+id/action_layout_normal"
android:title="@string/normal" />
<item
android:id="@+id/action_layout_card"
android:title="@string/card" />
<item
android:id="@+id/action_layout_colored_card"
android:title="@string/card_color_style" />
<item
android:id="@+id/action_layout_circular"
android:title="@string/circular" />
<item
android:id="@+id/action_layout_image"
android:title="@string/image" />
<item
android:id="@+id/action_layout_gradient_image"
android:title="@string/image_gradient" />
</group>
</menu>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="@+id/song_sort"
android:checkableBehavior="single">
<item
android:id="@+id/action_song_sort_order_asc"
android:title="@string/sort_order_a_z" />
</group>
</menu>

View file

@ -850,4 +850,17 @@
<string name="pref_language_name">Select language</string>
<string name="translators">Translators</string>
<string name="translators_summary">The people who helped translate this app</string>
<plurals name="numSongs">
<item quantity="one">%d Song</item>
<item quantity="other">%d Songs</item>
</plurals>
<plurals name="numAlbums">
<item quantity="one">%d Album</item>
<item quantity="other">%d Albums</item>
</plurals>
<plurals name="numArtists">
<item quantity="one">%d Artist</item>
<item quantity="other">%d Artists</item>
</plurals>
</resources>