diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt index 2714447b..32a4d141 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt @@ -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 + } + PreferenceUtil.getInstance(activity).songGridStyle = it.itemId + true } - super.onClick(v) + 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) + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt index e91ed492..330f72c3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt @@ -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, _ -> diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt index 765c044b..be5f8ed8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt @@ -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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt index 7ebe4f64..6ed4eda1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt @@ -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 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() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/room/MusicPlaybackQueueStoreDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/room/MusicPlaybackQueueStoreDatabase.kt index f9233c7b..668e50c7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/room/MusicPlaybackQueueStoreDatabase.kt +++ b/app/src/main/java/code/name/monkey/retromusic/room/MusicPlaybackQueueStoreDatabase.kt @@ -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 diff --git a/app/src/main/java/code/name/monkey/retromusic/room/MusicQueueRepository.kt b/app/src/main/java/code/name/monkey/retromusic/room/MusicQueueRepository.kt index 7fd99db5..25959c9d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/room/MusicQueueRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/room/MusicQueueRepository.kt @@ -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 = queueDao.getQueue() + fun getQueue(): List = queueDao.getQueue() - fun getOriginalQueue(): List = queueDao.getQueue() + fun getOriginalQueue(): List = queueDao.getOriginalQueue() - suspend fun insertQueue(queue: List) { + suspend fun insertQueue(queue: List) { queueDao.saveQueue(queue) } suspend fun insertOriginalQueue(queue: List) { - queueDao.saveQueue(queue) + queueDao.saveOriginalQueue(queue) } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/room/NowPlayingQueue.kt b/app/src/main/java/code/name/monkey/retromusic/room/NowPlayingQueue.kt index f10a5963..b066a4dd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/room/NowPlayingQueue.kt +++ b/app/src/main/java/code/name/monkey/retromusic/room/NowPlayingQueue.kt @@ -12,31 +12,19 @@ class NowPlayingQueue(context: Context) { private val musicQueueRepository: MusicQueueRepository = MusicQueueRepository(queueDao) - fun saveQueue(songs: List) = GlobalScope.launch(Dispatchers.IO) { - val songEntity = songs.map { - Song.toSongEntity(it) - } - musicQueueRepository.insertQueue(songEntity) + fun saveQueue(songs: List) = GlobalScope.launch(Dispatchers.Default) { + musicQueueRepository.insertQueue(songs) } - fun saveOriginalQueue(playingQueue: List) = GlobalScope.launch(Dispatchers.IO) { - val songEntity = playingQueue.map { - Song.toSongEntity(it) - } - musicQueueRepository.insertOriginalQueue(songEntity) + fun saveOriginalQueue(songs: List) = GlobalScope.launch(Dispatchers.Default) { + musicQueueRepository.insertOriginalQueue(songs.map { Song.toSongEntity(it) }) } fun getQueue(): List { - val songEntity = musicQueueRepository.getQueue() - return songEntity.map { - SongEntity.toSong(it) - } + return musicQueueRepository.getQueue() } fun getOriginalQueue(): List { - val songEntity = musicQueueRepository.getOriginalQueue() - return songEntity.map { - SongEntity.toSong(it) - } + return musicQueueRepository.getOriginalQueue().map { SongEntity.toSong(it) } } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/room/QueueDao.kt b/app/src/main/java/code/name/monkey/retromusic/room/QueueDao.kt index ffc9bb45..7e54de92 100644 --- a/app/src/main/java/code/name/monkey/retromusic/room/QueueDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/room/QueueDao.kt @@ -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) + suspend fun saveQueue(playingQueue: List) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun saveOriginalQueue(playingQueue: List) - @Query("SELECT * FROM song_entity") - fun getQueue(): List + @Query("SELECT * FROM playing_queue") + fun getQueue(): List - @Query("SELECT * FROM song_entity") + @Query("SELECT * FROM original_playing_queue") fun getOriginalQueue(): List } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/room/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/room/SongEntity.kt index 6c65cfe9..3d75c132 100644 --- a/app/src/main/java/code/name/monkey/retromusic/room/SongEntity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/room/SongEntity.kt @@ -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, diff --git a/app/src/main/res/layout/item_list_quick_actions.xml b/app/src/main/res/layout/item_list_quick_actions.xml index b9604e41..4339cd71 100644 --- a/app/src/main/res/layout/item_list_quick_actions.xml +++ b/app/src/main/res/layout/item_list_quick_actions.xml @@ -12,33 +12,71 @@ ~ See the GNU General Public License for more details. --> - - + + + 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" /> - + + + + + 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" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_layout_types.xml b/app/src/main/res/menu/menu_layout_types.xml new file mode 100644 index 00000000..2a2a12d3 --- /dev/null +++ b/app/src/main/res/menu/menu_layout_types.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_song_sort_order.xml b/app/src/main/res/menu/menu_song_sort_order.xml new file mode 100644 index 00000000..592b03ad --- /dev/null +++ b/app/src/main/res/menu/menu_song_sort_order.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d179eb30..20b728aa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -850,4 +850,17 @@ Select language Translators The people who helped translate this app + + + %d Song + %d Songs + + + %d Album + %d Albums + + + %d Artist + %d Artists +