all: migrate to centralized constant table
Migrate to a centralized constant table for easier management. Previously, Auxio would tie constants to the class itself, which led to a largely disjointed system that relied on an internal table so that it would stay sane. This commit moves all of those constants to a single table for easier usage and management.
This commit is contained in:
parent
6d9da35de0
commit
608112a7ac
23 changed files with 293 additions and 282 deletions
|
@ -36,9 +36,6 @@ import org.oxycblt.auxio.settings.SettingsManager
|
||||||
* - Rework RecyclerView management and item dragging
|
* - Rework RecyclerView management and item dragging
|
||||||
* - Rework sealed classes to minimize whens and maximize overrides
|
* - Rework sealed classes to minimize whens and maximize overrides
|
||||||
* ```
|
* ```
|
||||||
*
|
|
||||||
* TODO: Dumpster int-codes for a 4-byte identifier (can still be in the form of an int) For
|
|
||||||
* example, instead of 0xA111 for ReplayGainMode.TRACK, you would instead have RTCK
|
|
||||||
*/
|
*/
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
class AuxioApp : Application(), ImageLoaderFactory {
|
class AuxioApp : Application(), ImageLoaderFactory {
|
||||||
|
|
101
app/src/main/java/org/oxycblt/auxio/IntegerTable.kt
Normal file
101
app/src/main/java/org/oxycblt/auxio/IntegerTable.kt
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Auxio Project
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oxycblt.auxio
|
||||||
|
|
||||||
|
object IntegerTable {
|
||||||
|
/** SongViewHolder */
|
||||||
|
const val ITEM_TYPE_SONG = 0xA000
|
||||||
|
/** AlbumViewHolder */
|
||||||
|
const val ITEM_TYPE_ALBUM = 0xA001
|
||||||
|
/** ArtistViewHolder */
|
||||||
|
const val ITEM_TYPE_ARTIST = 0xA002
|
||||||
|
/** GenreViewHolder */
|
||||||
|
const val ITEM_TYPE_GENRE = 0xA003
|
||||||
|
/** HeaderViewHolder */
|
||||||
|
const val ITEM_TYPE_HEADER = 0xA004
|
||||||
|
/** ActionHeaderViewHolder */
|
||||||
|
const val ITEM_TYPE_ACTION_HEADER = 0xA005
|
||||||
|
|
||||||
|
/** AlbumDetailViewHolder */
|
||||||
|
const val ITEM_TYPE_ALBUM_DETAIL = 0xA006
|
||||||
|
/** AlbumSongViewHolder */
|
||||||
|
const val ITEM_TYPE_ALBUM_SONG = 0xA007
|
||||||
|
/** ArtistDetailViewHolder */
|
||||||
|
const val ITEM_TYPE_ARTIST_DETAIL = 0xA008
|
||||||
|
/** ArtistAlbumViewHolder */
|
||||||
|
const val ITEM_TYPE_ARTIST_ALBUM = 0xA009
|
||||||
|
/** ArtistSongViewHolder */
|
||||||
|
const val ITEM_TYPE_ARTIST_SONG = 0xA00A
|
||||||
|
/** GenreDetailViewHolder */
|
||||||
|
const val ITEM_TYPE_GENRE_DETAIL = 0xA00B
|
||||||
|
/** GenreSongViewHolder */
|
||||||
|
const val ITEM_TYPE_GENRE_SONG = 0xA00C
|
||||||
|
|
||||||
|
/** QueueSongViewHolder */
|
||||||
|
const val ITEM_TYPE_QUEUE_SONG = 0xA00D
|
||||||
|
|
||||||
|
/** "Music playback" Notification channel */
|
||||||
|
const val NOTIFICATION_CODE = 0xA0A0
|
||||||
|
/** Intent request code */
|
||||||
|
const val REQUEST_CODE = 0xA0C0
|
||||||
|
|
||||||
|
/** LoopMode.NONE */
|
||||||
|
const val LOOP_MODE_NONE = 0xA100
|
||||||
|
/** LoopMode.ALL */
|
||||||
|
const val LOOP_MODE_ALL = 0xA101
|
||||||
|
/** LoopMode.TRACK */
|
||||||
|
const val LOOP_MODE_TRACK = 0xA102
|
||||||
|
|
||||||
|
/** PlaybackMode.IN_GENRE */
|
||||||
|
const val PLAYBACK_MODE_IN_GENRE = 0xA103
|
||||||
|
/** PlaybackMode.IN_ARTIST */
|
||||||
|
const val PLAYBACK_MODE_IN_ARTIST = 0xA104
|
||||||
|
/** PlaybackMode.IN_ALBUM */
|
||||||
|
const val PLAYBACK_MODE_IN_ALBUM = 0xA105
|
||||||
|
/** PlaybackMode.ALL_SONGS */
|
||||||
|
const val PLAYBACK_MODE_ALL_SONGS = 0xA106
|
||||||
|
|
||||||
|
/** DisplayMode.NONE (No Longer used but still reserved) */
|
||||||
|
// const val DISPLAY_MODE_NONE = 0xA107
|
||||||
|
/** DisplayMode.SHOW_GENRES */
|
||||||
|
const val DISPLAY_MODE_SHOW_GENRES = 0xA108
|
||||||
|
/** DisplayMode.SHOW_ARTISTS */
|
||||||
|
const val DISPLAY_MODE_SHOW_ARTISTS = 0xA109
|
||||||
|
/** DisplayMode.SHOW_ALBUMS */
|
||||||
|
const val DISPLAY_MODE_SHOW_ALBUMS = 0xA10A
|
||||||
|
/** DisplayMode.SHOW_SONGS */
|
||||||
|
const val DISPLAY_MODE_SHOW_SONGS = 0xA10B
|
||||||
|
|
||||||
|
/** Sort.ByName */
|
||||||
|
const val SORT_BY_NAME = 0xA10C
|
||||||
|
/** Sort.ByArtist */
|
||||||
|
const val SORT_BY_ARTIST = 0xA10D
|
||||||
|
/** Sort.ByAlbum */
|
||||||
|
const val SORT_BY_ALBUM = 0xA10E
|
||||||
|
/** Sort.ByYear */
|
||||||
|
const val SORT_BY_YEAR = 0xA10F
|
||||||
|
|
||||||
|
/** ReplayGainMode.Off */
|
||||||
|
const val REPLAY_GAIN_MODE_OFF = 0xA110
|
||||||
|
/** ReplayGainMode.Track */
|
||||||
|
const val REPLAY_GAIN_MODE_TRACK = 0xA111
|
||||||
|
/** ReplayGainMode.Album */
|
||||||
|
const val REPLAY_GAIN_MODE_ALBUM = 0xA112
|
||||||
|
/** ReplayGainMode.Dynamic */
|
||||||
|
const val REPLAY_GAIN_MODE_DYNAMIC = 0xA113
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import android.view.ViewGroup
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.coil.bindAlbumArt
|
import org.oxycblt.auxio.coil.bindAlbumArt
|
||||||
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
|
import org.oxycblt.auxio.databinding.ItemAlbumSongBinding
|
||||||
|
@ -53,20 +54,20 @@ class AlbumDetailAdapter(
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (getItem(position)) {
|
return when (getItem(position)) {
|
||||||
is Album -> ALBUM_DETAIL_ITEM_TYPE
|
is Album -> IntegerTable.ITEM_TYPE_ALBUM_DETAIL
|
||||||
is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE
|
is ActionHeader -> IntegerTable.ITEM_TYPE_ACTION_HEADER
|
||||||
is Song -> ALBUM_SONG_ITEM_TYPE
|
is Song -> IntegerTable.ITEM_TYPE_ALBUM_SONG
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
ALBUM_DETAIL_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ALBUM_DETAIL ->
|
||||||
AlbumDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
|
AlbumDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
|
||||||
ALBUM_SONG_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ACTION_HEADER -> ActionHeaderViewHolder.from(parent.context)
|
||||||
|
IntegerTable.ITEM_TYPE_ALBUM_SONG ->
|
||||||
AlbumSongViewHolder(ItemAlbumSongBinding.inflate(parent.context.inflater))
|
AlbumSongViewHolder(ItemAlbumSongBinding.inflate(parent.context.inflater))
|
||||||
ActionHeaderViewHolder.ITEM_TYPE -> ActionHeaderViewHolder.from(parent.context)
|
|
||||||
else -> error("Invalid ViewHolder item type $viewType")
|
else -> error("Invalid ViewHolder item type $viewType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,9 +173,4 @@ class AlbumDetailAdapter(
|
||||||
binding.songTrackPlaceholder.isActivated = isHighlighted
|
binding.songTrackPlaceholder.isActivated = isHighlighted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val ALBUM_DETAIL_ITEM_TYPE = 0xA006
|
|
||||||
const val ALBUM_SONG_ITEM_TYPE = 0xA007
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.coil.bindArtistImage
|
import org.oxycblt.auxio.coil.bindArtistImage
|
||||||
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
|
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
|
||||||
|
@ -58,25 +59,25 @@ class ArtistDetailAdapter(
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (getItem(position)) {
|
return when (getItem(position)) {
|
||||||
is Artist -> ARTIST_DETAIL_ITEM_TYPE
|
is Artist -> IntegerTable.ITEM_TYPE_ARTIST_DETAIL
|
||||||
is Album -> ARTIST_ALBUM_ITEM_TYPE
|
is Album -> IntegerTable.ITEM_TYPE_ARTIST_ALBUM
|
||||||
is Song -> ARTIST_SONG_ITEM_TYPE
|
is Song -> IntegerTable.ITEM_TYPE_ARTIST_SONG
|
||||||
is Header -> HeaderViewHolder.ITEM_TYPE
|
is Header -> IntegerTable.ITEM_TYPE_HEADER
|
||||||
is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE
|
is ActionHeader -> IntegerTable.ITEM_TYPE_ACTION_HEADER
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
ARTIST_DETAIL_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ARTIST_DETAIL ->
|
||||||
ArtistDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
|
ArtistDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
|
||||||
ARTIST_ALBUM_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ARTIST_ALBUM ->
|
||||||
ArtistAlbumViewHolder(ItemArtistAlbumBinding.inflate(parent.context.inflater))
|
ArtistAlbumViewHolder(ItemArtistAlbumBinding.inflate(parent.context.inflater))
|
||||||
ARTIST_SONG_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ARTIST_SONG ->
|
||||||
ArtistSongViewHolder(ItemArtistSongBinding.inflate(parent.context.inflater))
|
ArtistSongViewHolder(ItemArtistSongBinding.inflate(parent.context.inflater))
|
||||||
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
|
IntegerTable.ITEM_TYPE_HEADER -> HeaderViewHolder.from(parent.context)
|
||||||
ActionHeaderViewHolder.ITEM_TYPE -> ActionHeaderViewHolder.from(parent.context)
|
IntegerTable.ITEM_TYPE_ACTION_HEADER -> ActionHeaderViewHolder.from(parent.context)
|
||||||
else -> error("Invalid ViewHolder item type $viewType")
|
else -> error("Invalid ViewHolder item type $viewType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,10 +223,4 @@ class ArtistDetailAdapter(
|
||||||
binding.songName.isActivated = isHighlighted
|
binding.songName.isActivated = isHighlighted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val ARTIST_DETAIL_ITEM_TYPE = 0xA008
|
|
||||||
const val ARTIST_ALBUM_ITEM_TYPE = 0xA009
|
|
||||||
const val ARTIST_SONG_ITEM_TYPE = 0xA00A
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.coil.bindGenreImage
|
import org.oxycblt.auxio.coil.bindGenreImage
|
||||||
import org.oxycblt.auxio.databinding.ItemDetailBinding
|
import org.oxycblt.auxio.databinding.ItemDetailBinding
|
||||||
|
@ -50,22 +51,22 @@ class GenreDetailAdapter(
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (getItem(position)) {
|
return when (getItem(position)) {
|
||||||
is Genre -> GENRE_DETAIL_ITEM_TYPE
|
is Genre -> IntegerTable.ITEM_TYPE_GENRE_DETAIL
|
||||||
is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE
|
is ActionHeader -> IntegerTable.ITEM_TYPE_ACTION_HEADER
|
||||||
is Song -> GENRE_SONG_ITEM_TYPE
|
is Song -> IntegerTable.ITEM_TYPE_GENRE_SONG
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
GENRE_DETAIL_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_GENRE_DETAIL ->
|
||||||
GenreDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
|
GenreDetailViewHolder(ItemDetailBinding.inflate(parent.context.inflater))
|
||||||
GENRE_SONG_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ACTION_HEADER -> ActionHeaderViewHolder.from(parent.context)
|
||||||
|
IntegerTable.ITEM_TYPE_GENRE_SONG ->
|
||||||
GenreSongViewHolder(
|
GenreSongViewHolder(
|
||||||
ItemGenreSongBinding.inflate(parent.context.inflater),
|
ItemGenreSongBinding.inflate(parent.context.inflater),
|
||||||
)
|
)
|
||||||
ActionHeaderViewHolder.ITEM_TYPE -> ActionHeaderViewHolder.from(parent.context)
|
|
||||||
else -> error("Bad ViewHolder item type $viewType")
|
else -> error("Bad ViewHolder item type $viewType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,9 +155,4 @@ class GenreDetailAdapter(
|
||||||
binding.songName.isActivated = isHighlighted
|
binding.songName.isActivated = isHighlighted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val GENRE_DETAIL_ITEM_TYPE = 0xA00B
|
|
||||||
const val GENRE_SONG_ITEM_TYPE = 0xA00C
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleRes: Int = 0)
|
||||||
startAngle: Float,
|
startAngle: Float,
|
||||||
sweepAngle: Float
|
sweepAngle: Float
|
||||||
) {
|
) {
|
||||||
path.arcTo(
|
arcTo(
|
||||||
centerX - radius,
|
centerX - radius,
|
||||||
centerY - radius,
|
centerY - radius,
|
||||||
centerX + radius,
|
centerX + radius,
|
||||||
|
|
|
@ -27,6 +27,7 @@ import androidx.recyclerview.widget.AsyncListDiffer
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.shape.MaterialShapeDrawable
|
import com.google.android.material.shape.MaterialShapeDrawable
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.databinding.ItemQueueSongBinding
|
import org.oxycblt.auxio.databinding.ItemQueueSongBinding
|
||||||
import org.oxycblt.auxio.music.ActionHeader
|
import org.oxycblt.auxio.music.ActionHeader
|
||||||
import org.oxycblt.auxio.music.Header
|
import org.oxycblt.auxio.music.Header
|
||||||
|
@ -55,19 +56,19 @@ class QueueAdapter(private val touchHelper: ItemTouchHelper) :
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (data[position]) {
|
return when (data[position]) {
|
||||||
is Song -> QUEUE_SONG_ITEM_TYPE
|
is Song -> IntegerTable.ITEM_TYPE_QUEUE_SONG
|
||||||
is Header -> HeaderViewHolder.ITEM_TYPE
|
is Header -> IntegerTable.ITEM_TYPE_HEADER
|
||||||
is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE
|
is ActionHeader -> IntegerTable.ITEM_TYPE_ACTION_HEADER
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
QUEUE_SONG_ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_QUEUE_SONG ->
|
||||||
QueueSongViewHolder(ItemQueueSongBinding.inflate(parent.context.inflater))
|
QueueSongViewHolder(ItemQueueSongBinding.inflate(parent.context.inflater))
|
||||||
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
|
IntegerTable.ITEM_TYPE_HEADER -> HeaderViewHolder.from(parent.context)
|
||||||
ActionHeaderViewHolder.ITEM_TYPE -> ActionHeaderViewHolder.from(parent.context)
|
IntegerTable.ITEM_TYPE_ACTION_HEADER -> ActionHeaderViewHolder.from(parent.context)
|
||||||
else -> error("Invalid ViewHolder item type $viewType")
|
else -> error("Invalid ViewHolder item type $viewType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,8 +147,4 @@ class QueueAdapter(private val touchHelper: ItemTouchHelper) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val QUEUE_SONG_ITEM_TYPE = 0xA00D
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.playback.state
|
package org.oxycblt.auxio.playback.state
|
||||||
|
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum that determines the playback repeat mode.
|
* Enum that determines the playback repeat mode.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
|
@ -39,25 +41,21 @@ enum class LoopMode {
|
||||||
* Convert the LoopMode to an int constant that is saved in PlaybackStateDatabase
|
* Convert the LoopMode to an int constant that is saved in PlaybackStateDatabase
|
||||||
* @return The int constant for this mode
|
* @return The int constant for this mode
|
||||||
*/
|
*/
|
||||||
fun toInt(): Int {
|
val intCode: Int
|
||||||
return when (this) {
|
get() =
|
||||||
NONE -> INT_NONE
|
when (this) {
|
||||||
ALL -> INT_ALL
|
NONE -> IntegerTable.LOOP_MODE_NONE
|
||||||
TRACK -> INT_TRACK
|
ALL -> IntegerTable.LOOP_MODE_ALL
|
||||||
}
|
TRACK -> IntegerTable.LOOP_MODE_TRACK
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val INT_NONE = 0xA100
|
|
||||||
private const val INT_ALL = 0xA101
|
|
||||||
private const val INT_TRACK = 0xA102
|
|
||||||
|
|
||||||
/** Convert an int [constant] into a LoopMode, or null if it isn't valid. */
|
/** Convert an int [constant] into a LoopMode, or null if it isn't valid. */
|
||||||
fun fromInt(constant: Int): LoopMode? {
|
fun fromIntCode(constant: Int): LoopMode? {
|
||||||
return when (constant) {
|
return when (constant) {
|
||||||
INT_NONE -> NONE
|
IntegerTable.LOOP_MODE_NONE -> NONE
|
||||||
INT_ALL -> ALL
|
IntegerTable.LOOP_MODE_ALL -> ALL
|
||||||
INT_TRACK -> TRACK
|
IntegerTable.LOOP_MODE_TRACK -> TRACK
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.playback.state
|
package org.oxycblt.auxio.playback.state
|
||||||
|
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum that indicates how the queue should be constructed.
|
* Enum that indicates how the queue should be constructed.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
|
@ -35,32 +37,26 @@ enum class PlaybackMode {
|
||||||
* Convert the mode into an int constant, to be saved in PlaybackStateDatabase
|
* Convert the mode into an int constant, to be saved in PlaybackStateDatabase
|
||||||
* @return The constant for this mode,
|
* @return The constant for this mode,
|
||||||
*/
|
*/
|
||||||
fun toInt(): Int {
|
val intCode: Int
|
||||||
return when (this) {
|
get() =
|
||||||
ALL_SONGS -> INT_ALL_SONGS
|
when (this) {
|
||||||
IN_ALBUM -> INT_IN_ALBUM
|
ALL_SONGS -> IntegerTable.PLAYBACK_MODE_ALL_SONGS
|
||||||
IN_ARTIST -> INT_IN_ARTIST
|
IN_ALBUM -> IntegerTable.PLAYBACK_MODE_IN_ALBUM
|
||||||
IN_GENRE -> INT_IN_GENRE
|
IN_ARTIST -> IntegerTable.PLAYBACK_MODE_IN_ARTIST
|
||||||
}
|
IN_GENRE -> IntegerTable.PLAYBACK_MODE_IN_GENRE
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Kept in reverse order because of backwards compat, do not re-order these
|
|
||||||
private const val INT_ALL_SONGS = 0xA106
|
|
||||||
private const val INT_IN_ALBUM = 0xA105
|
|
||||||
private const val INT_IN_ARTIST = 0xA104
|
|
||||||
private const val INT_IN_GENRE = 0xA103
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a [PlaybackMode] for an int [constant]
|
* Get a [PlaybackMode] for an int [constant]
|
||||||
* @return The mode, null if there isn't one for this.
|
* @return The mode, null if there isn't one for this.
|
||||||
*/
|
*/
|
||||||
fun fromInt(constant: Int): PlaybackMode? {
|
fun fromInt(constant: Int): PlaybackMode? {
|
||||||
return when (constant) {
|
return when (constant) {
|
||||||
INT_ALL_SONGS -> ALL_SONGS
|
IntegerTable.PLAYBACK_MODE_ALL_SONGS -> ALL_SONGS
|
||||||
INT_IN_ALBUM -> IN_ALBUM
|
IntegerTable.PLAYBACK_MODE_IN_ALBUM -> IN_ALBUM
|
||||||
INT_IN_ARTIST -> IN_ARTIST
|
IntegerTable.PLAYBACK_MODE_IN_ARTIST -> IN_ARTIST
|
||||||
INT_IN_GENRE -> IN_GENRE
|
IntegerTable.PLAYBACK_MODE_IN_GENRE -> IN_GENRE
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.oxycblt.auxio.util.queryAll
|
||||||
* A SQLite database for managing the persistent playback state and queue. Yes. I know Room exists.
|
* A SQLite database for managing the persistent playback state and queue. Yes. I know Room exists.
|
||||||
* But that would needlessly bloat my app and has crippling bugs.
|
* But that would needlessly bloat my app and has crippling bugs.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
|
*
|
||||||
|
* TODO: Rework to rely on queue indices more and only use specific items as fallbacks
|
||||||
*/
|
*/
|
||||||
class PlaybackStateDatabase(context: Context) :
|
class PlaybackStateDatabase(context: Context) :
|
||||||
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
|
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
|
||||||
|
@ -144,7 +146,7 @@ class PlaybackStateDatabase(context: Context) :
|
||||||
queueIndex = cursor.getInt(indexIndex),
|
queueIndex = cursor.getInt(indexIndex),
|
||||||
playbackMode = mode,
|
playbackMode = mode,
|
||||||
isShuffling = cursor.getInt(shuffleIndex) == 1,
|
isShuffling = cursor.getInt(shuffleIndex) == 1,
|
||||||
loopMode = LoopMode.fromInt(cursor.getInt(loopModeIndex)) ?: LoopMode.NONE,
|
loopMode = LoopMode.fromIntCode(cursor.getInt(loopModeIndex)) ?: LoopMode.NONE,
|
||||||
)
|
)
|
||||||
|
|
||||||
logD("Successfully read playback state: $state")
|
logD("Successfully read playback state: $state")
|
||||||
|
@ -169,9 +171,9 @@ class PlaybackStateDatabase(context: Context) :
|
||||||
put(StateColumns.COLUMN_POSITION, state.position)
|
put(StateColumns.COLUMN_POSITION, state.position)
|
||||||
put(StateColumns.COLUMN_PARENT_HASH, state.parent?.id)
|
put(StateColumns.COLUMN_PARENT_HASH, state.parent?.id)
|
||||||
put(StateColumns.COLUMN_QUEUE_INDEX, state.queueIndex)
|
put(StateColumns.COLUMN_QUEUE_INDEX, state.queueIndex)
|
||||||
put(StateColumns.COLUMN_PLAYBACK_MODE, state.playbackMode.toInt())
|
put(StateColumns.COLUMN_PLAYBACK_MODE, state.playbackMode.intCode)
|
||||||
put(StateColumns.COLUMN_IS_SHUFFLING, state.isShuffling)
|
put(StateColumns.COLUMN_IS_SHUFFLING, state.isShuffling)
|
||||||
put(StateColumns.COLUMN_LOOP_MODE, state.loopMode.toInt())
|
put(StateColumns.COLUMN_LOOP_MODE, state.loopMode.intCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
insert(TABLE_NAME_STATE, null, stateData)
|
insert(TABLE_NAME_STATE, null, stateData)
|
||||||
|
|
|
@ -49,7 +49,6 @@ private constructor(private val context: Context, mediaToken: MediaSessionCompat
|
||||||
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||||
setShowWhen(false)
|
setShowWhen(false)
|
||||||
setSilent(true)
|
setSilent(true)
|
||||||
setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
|
|
||||||
setContentIntent(context.newMainIntent())
|
setContentIntent(context.newMainIntent())
|
||||||
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
|
||||||
|
@ -159,7 +158,6 @@ private constructor(private val context: Context, mediaToken: MediaSessionCompat
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel.PLAYBACK"
|
const val CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel.PLAYBACK"
|
||||||
const val NOTIFICATION_ID = 0xA0A0
|
|
||||||
|
|
||||||
/** Build a new instance of [PlaybackNotification]. */
|
/** Build a new instance of [PlaybackNotification]. */
|
||||||
fun from(
|
fun from(
|
||||||
|
|
|
@ -51,6 +51,7 @@ import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.takeWhile
|
import kotlinx.coroutines.flow.takeWhile
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.oxycblt.auxio.BuildConfig
|
import org.oxycblt.auxio.BuildConfig
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.LoopMode
|
import org.oxycblt.auxio.playback.state.LoopMode
|
||||||
|
@ -407,18 +408,17 @@ class PlaybackService :
|
||||||
// Specify that this is a media service, if supported.
|
// Specify that this is a media service, if supported.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
startForeground(
|
startForeground(
|
||||||
PlaybackNotification.NOTIFICATION_ID,
|
IntegerTable.NOTIFICATION_CODE,
|
||||||
notification.build(),
|
notification.build(),
|
||||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
|
||||||
} else {
|
} else {
|
||||||
startForeground(PlaybackNotification.NOTIFICATION_ID, notification.build())
|
startForeground(IntegerTable.NOTIFICATION_CODE, notification.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
isForeground = true
|
isForeground = true
|
||||||
} else {
|
} else {
|
||||||
// If we are already in foreground just update the notification
|
// If we are already in foreground just update the notification
|
||||||
notificationManager.notify(
|
notificationManager.notify(IntegerTable.NOTIFICATION_CODE, notification.build())
|
||||||
PlaybackNotification.NOTIFICATION_ID, notification.build())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ class PlaybackService :
|
||||||
/** Stop the foreground state and hide the notification */
|
/** Stop the foreground state and hide the notification */
|
||||||
private fun stopForegroundAndNotification() {
|
private fun stopForegroundAndNotification() {
|
||||||
stopForeground(true)
|
stopForeground(true)
|
||||||
notificationManager.cancel(PlaybackNotification.NOTIFICATION_ID)
|
notificationManager.cancel(IntegerTable.NOTIFICATION_CODE)
|
||||||
isForeground = false
|
isForeground = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.playback.system
|
package org.oxycblt.auxio.playback.system
|
||||||
|
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
|
|
||||||
/** Represents the current setting for ReplayGain. */
|
/** Represents the current setting for ReplayGain. */
|
||||||
enum class ReplayGainMode {
|
enum class ReplayGainMode {
|
||||||
/** Do not apply ReplayGain. */
|
/** Do not apply ReplayGain. */
|
||||||
|
@ -28,29 +30,13 @@ enum class ReplayGainMode {
|
||||||
/** Apply the album gain only when playing from an album, defaulting to track gain otherwise. */
|
/** Apply the album gain only when playing from an album, defaulting to track gain otherwise. */
|
||||||
DYNAMIC;
|
DYNAMIC;
|
||||||
|
|
||||||
/** Converts this type to an integer constant. */
|
|
||||||
fun toInt(): Int {
|
|
||||||
return when (this) {
|
|
||||||
OFF -> INT_OFF
|
|
||||||
TRACK -> INT_TRACK
|
|
||||||
ALBUM -> INT_ALBUM
|
|
||||||
DYNAMIC -> INT_DYNAMIC
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val INT_OFF = 0xA110
|
fun fromIntCode(value: Int): ReplayGainMode? {
|
||||||
private const val INT_TRACK = 0xA111
|
|
||||||
private const val INT_ALBUM = 0xA112
|
|
||||||
private const val INT_DYNAMIC = 0xA113
|
|
||||||
|
|
||||||
/** Converts an integer constant to this type. */
|
|
||||||
fun fromInt(value: Int): ReplayGainMode? {
|
|
||||||
return when (value) {
|
return when (value) {
|
||||||
INT_OFF -> OFF
|
IntegerTable.REPLAY_GAIN_MODE_OFF -> OFF
|
||||||
INT_TRACK -> TRACK
|
IntegerTable.REPLAY_GAIN_MODE_TRACK -> TRACK
|
||||||
INT_ALBUM -> ALBUM
|
IntegerTable.REPLAY_GAIN_MODE_ALBUM -> ALBUM
|
||||||
INT_DYNAMIC -> DYNAMIC
|
IntegerTable.REPLAY_GAIN_MODE_DYNAMIC -> DYNAMIC
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
@ -46,26 +47,26 @@ class SearchAdapter(
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (getItem(position)) {
|
return when (getItem(position)) {
|
||||||
is Genre -> GenreViewHolder.ITEM_TYPE
|
is Genre -> IntegerTable.ITEM_TYPE_GENRE
|
||||||
is Artist -> ArtistViewHolder.ITEM_TYPE
|
is Artist -> IntegerTable.ITEM_TYPE_ARTIST
|
||||||
is Album -> AlbumViewHolder.ITEM_TYPE
|
is Album -> IntegerTable.ITEM_TYPE_ALBUM
|
||||||
is Song -> SongViewHolder.ITEM_TYPE
|
is Song -> IntegerTable.ITEM_TYPE_SONG
|
||||||
is Header -> HeaderViewHolder.ITEM_TYPE
|
is Header -> IntegerTable.ITEM_TYPE_HEADER
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
GenreViewHolder.ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_GENRE ->
|
||||||
GenreViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
GenreViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
||||||
ArtistViewHolder.ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ARTIST ->
|
||||||
ArtistViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
ArtistViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
||||||
AlbumViewHolder.ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_ALBUM ->
|
||||||
AlbumViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
AlbumViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
||||||
SongViewHolder.ITEM_TYPE ->
|
IntegerTable.ITEM_TYPE_SONG ->
|
||||||
SongViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
SongViewHolder.from(parent.context, doOnClick, doOnLongClick)
|
||||||
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
|
IntegerTable.ITEM_TYPE_HEADER -> HeaderViewHolder.from(parent.context)
|
||||||
else -> error("Invalid ViewHolder item type")
|
else -> error("Invalid ViewHolder item type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ class SettingsManager private constructor(context: Context) :
|
||||||
/** The current ReplayGain configuration */
|
/** The current ReplayGain configuration */
|
||||||
val replayGainMode: ReplayGainMode
|
val replayGainMode: ReplayGainMode
|
||||||
get() =
|
get() =
|
||||||
ReplayGainMode.fromInt(prefs.getInt(KEY_REPLAY_GAIN, Int.MIN_VALUE))
|
ReplayGainMode.fromIntCode(prefs.getInt(KEY_REPLAY_GAIN, Int.MIN_VALUE))
|
||||||
?: ReplayGainMode.OFF
|
?: ReplayGainMode.OFF
|
||||||
|
|
||||||
/** What queue to create when a song is selected (ex. From All Songs or Search) */
|
/** What queue to create when a song is selected (ex. From All Songs or Search) */
|
||||||
|
@ -129,50 +129,54 @@ class SettingsManager private constructor(context: Context) :
|
||||||
|
|
||||||
/** The current filter mode of the search tab */
|
/** The current filter mode of the search tab */
|
||||||
var searchFilterMode: DisplayMode?
|
var searchFilterMode: DisplayMode?
|
||||||
get() = DisplayMode.fromFilterInt(prefs.getInt(KEY_SEARCH_FILTER_MODE, Int.MIN_VALUE))
|
get() = DisplayMode.fromInt(prefs.getInt(KEY_SEARCH_FILTER_MODE, Int.MIN_VALUE))
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_SEARCH_FILTER_MODE, DisplayMode.toFilterInt(value))
|
putInt(KEY_SEARCH_FILTER_MODE, value?.intCode ?: Int.MIN_VALUE)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The song sort mode on HomeFragment */
|
/** The song sort mode on HomeFragment */
|
||||||
var libSongSort: Sort
|
var libSongSort: Sort
|
||||||
get() = Sort.fromInt(prefs.getInt(KEY_LIB_SONGS_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
get() =
|
||||||
|
Sort.fromIntCode(prefs.getInt(KEY_LIB_SONGS_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_LIB_SONGS_SORT, value.toInt())
|
putInt(KEY_LIB_SONGS_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The album sort mode on HomeFragment */
|
/** The album sort mode on HomeFragment */
|
||||||
var libAlbumSort: Sort
|
var libAlbumSort: Sort
|
||||||
get() = Sort.fromInt(prefs.getInt(KEY_LIB_ALBUMS_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
get() =
|
||||||
|
Sort.fromIntCode(prefs.getInt(KEY_LIB_ALBUMS_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_LIB_ALBUMS_SORT, value.toInt())
|
putInt(KEY_LIB_ALBUMS_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The artist sort mode on HomeFragment */
|
/** The artist sort mode on HomeFragment */
|
||||||
var libArtistSort: Sort
|
var libArtistSort: Sort
|
||||||
get() = Sort.fromInt(prefs.getInt(KEY_LIB_ARTISTS_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
get() =
|
||||||
|
Sort.fromIntCode(prefs.getInt(KEY_LIB_ARTISTS_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_LIB_ARTISTS_SORT, value.toInt())
|
putInt(KEY_LIB_ARTISTS_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The genre sort mode on HomeFragment */
|
/** The genre sort mode on HomeFragment */
|
||||||
var libGenreSort: Sort
|
var libGenreSort: Sort
|
||||||
get() = Sort.fromInt(prefs.getInt(KEY_LIB_GENRES_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
get() =
|
||||||
|
Sort.fromIntCode(prefs.getInt(KEY_LIB_GENRES_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_LIB_GENRES_SORT, value.toInt())
|
putInt(KEY_LIB_GENRES_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,10 +184,11 @@ class SettingsManager private constructor(context: Context) :
|
||||||
/** The detail album sort mode */
|
/** The detail album sort mode */
|
||||||
var detailAlbumSort: Sort
|
var detailAlbumSort: Sort
|
||||||
get() =
|
get() =
|
||||||
Sort.fromInt(prefs.getInt(KEY_DETAIL_ALBUM_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
Sort.fromIntCode(prefs.getInt(KEY_DETAIL_ALBUM_SORT, Int.MIN_VALUE))
|
||||||
|
?: Sort.ByName(true)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_DETAIL_ALBUM_SORT, value.toInt())
|
putInt(KEY_DETAIL_ALBUM_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,10 +196,11 @@ class SettingsManager private constructor(context: Context) :
|
||||||
/** The detail artist sort mode */
|
/** The detail artist sort mode */
|
||||||
var detailArtistSort: Sort
|
var detailArtistSort: Sort
|
||||||
get() =
|
get() =
|
||||||
Sort.fromInt(prefs.getInt(KEY_DETAIL_ARTIST_SORT, Int.MIN_VALUE)) ?: Sort.ByYear(false)
|
Sort.fromIntCode(prefs.getInt(KEY_DETAIL_ARTIST_SORT, Int.MIN_VALUE))
|
||||||
|
?: Sort.ByYear(false)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_DETAIL_ARTIST_SORT, value.toInt())
|
putInt(KEY_DETAIL_ARTIST_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,10 +208,11 @@ class SettingsManager private constructor(context: Context) :
|
||||||
/** The detail genre sort mode */
|
/** The detail genre sort mode */
|
||||||
var detailGenreSort: Sort
|
var detailGenreSort: Sort
|
||||||
get() =
|
get() =
|
||||||
Sort.fromInt(prefs.getInt(KEY_DETAIL_GENRE_SORT, Int.MIN_VALUE)) ?: Sort.ByName(true)
|
Sort.fromIntCode(prefs.getInt(KEY_DETAIL_GENRE_SORT, Int.MIN_VALUE))
|
||||||
|
?: Sort.ByName(true)
|
||||||
set(value) {
|
set(value) {
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putInt(KEY_DETAIL_GENRE_SORT, value.toInt())
|
putInt(KEY_DETAIL_GENRE_SORT, value.intCode)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.ui
|
package org.oxycblt.auxio.ui
|
||||||
|
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,39 +50,27 @@ enum class DisplayMode {
|
||||||
SHOW_GENRES -> R.drawable.ic_genre
|
SHOW_GENRES -> R.drawable.ic_genre
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
val intCode: Int
|
||||||
private const val INT_NULL = 0xA107
|
get() =
|
||||||
private const val INT_SHOW_GENRES = 0xA108
|
when (this) {
|
||||||
private const val INT_SHOW_ARTISTS = 0xA109
|
SHOW_SONGS -> IntegerTable.DISPLAY_MODE_SHOW_SONGS
|
||||||
private const val INT_SHOW_ALBUMS = 0xA10A
|
SHOW_ALBUMS -> IntegerTable.DISPLAY_MODE_SHOW_ALBUMS
|
||||||
private const val INT_SHOW_SONGS = 0xA10B
|
SHOW_ARTISTS -> IntegerTable.DISPLAY_MODE_SHOW_ARTISTS
|
||||||
|
SHOW_GENRES -> IntegerTable.DISPLAY_MODE_SHOW_GENRES
|
||||||
/**
|
|
||||||
* Convert this enum into an integer for filtering. In this context, a null value means to
|
|
||||||
* filter nothing.
|
|
||||||
* @return An integer constant for that display mode, or a constant for a null [DisplayMode]
|
|
||||||
*/
|
|
||||||
fun toFilterInt(value: DisplayMode?): Int {
|
|
||||||
return when (value) {
|
|
||||||
SHOW_SONGS -> INT_SHOW_SONGS
|
|
||||||
SHOW_ALBUMS -> INT_SHOW_ALBUMS
|
|
||||||
SHOW_ARTISTS -> INT_SHOW_ARTISTS
|
|
||||||
SHOW_GENRES -> INT_SHOW_GENRES
|
|
||||||
null -> INT_NULL
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Convert a filtering integer to a [DisplayMode]. In this context, a null value means to
|
* Convert a filtering integer to a [DisplayMode]. In this context, a null value means to
|
||||||
* filter nothing.
|
* filter nothing.
|
||||||
* @return A [DisplayMode] for this constant (including null)
|
* @return A [DisplayMode] for this constant (including null)
|
||||||
*/
|
*/
|
||||||
fun fromFilterInt(value: Int): DisplayMode? {
|
fun fromInt(value: Int): DisplayMode? {
|
||||||
return when (value) {
|
return when (value) {
|
||||||
INT_SHOW_SONGS -> SHOW_SONGS
|
IntegerTable.DISPLAY_MODE_SHOW_SONGS -> SHOW_SONGS
|
||||||
INT_SHOW_ALBUMS -> SHOW_ALBUMS
|
IntegerTable.DISPLAY_MODE_SHOW_ALBUMS -> SHOW_ALBUMS
|
||||||
INT_SHOW_ARTISTS -> SHOW_ARTISTS
|
IntegerTable.DISPLAY_MODE_SHOW_ARTISTS -> SHOW_ARTISTS
|
||||||
INT_SHOW_GENRES -> SHOW_GENRES
|
IntegerTable.DISPLAY_MODE_SHOW_GENRES -> SHOW_GENRES
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.oxycblt.auxio.ui
|
package org.oxycblt.auxio.ui
|
||||||
|
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
@ -43,6 +44,9 @@ import org.oxycblt.auxio.util.logW
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
sealed class Sort(open val isAscending: Boolean) {
|
sealed class Sort(open val isAscending: Boolean) {
|
||||||
|
protected abstract val sortIntCode: Int
|
||||||
|
abstract val itemId: Int
|
||||||
|
|
||||||
open fun songs(songs: Collection<Song>): List<Song> {
|
open fun songs(songs: Collection<Song>): List<Song> {
|
||||||
logW("This sort is not supported for songs")
|
logW("This sort is not supported for songs")
|
||||||
return songs.toList()
|
return songs.toList()
|
||||||
|
@ -63,8 +67,20 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
return genres.toList()
|
return genres.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply [newIsAscending] to the status of this sort.
|
||||||
|
* @return A new [Sort] with the value of [newIsAscending] applied.
|
||||||
|
*/
|
||||||
|
abstract fun ascending(newIsAscending: Boolean): Sort
|
||||||
|
|
||||||
/** Sort by the names of an item */
|
/** Sort by the names of an item */
|
||||||
class ByName(override val isAscending: Boolean) : Sort(isAscending) {
|
class ByName(override val isAscending: Boolean) : Sort(isAscending) {
|
||||||
|
override val sortIntCode: Int
|
||||||
|
get() = IntegerTable.SORT_BY_NAME
|
||||||
|
|
||||||
|
override val itemId: Int
|
||||||
|
get() = R.id.option_sort_name
|
||||||
|
|
||||||
override fun songs(songs: Collection<Song>): List<Song> {
|
override fun songs(songs: Collection<Song>): List<Song> {
|
||||||
return songs.sortedWith(compareByDynamic(NameComparator()) { it })
|
return songs.sortedWith(compareByDynamic(NameComparator()) { it })
|
||||||
}
|
}
|
||||||
|
@ -80,10 +96,20 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
override fun genres(genres: Collection<Genre>): List<Genre> {
|
override fun genres(genres: Collection<Genre>): List<Genre> {
|
||||||
return genres.sortedWith(compareByDynamic(NameComparator()) { it })
|
return genres.sortedWith(compareByDynamic(NameComparator()) { it })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun ascending(newIsAscending: Boolean): Sort {
|
||||||
|
return ByName(isAscending)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sort by the album of an item, only supported by [Song] */
|
/** Sort by the album of an item, only supported by [Song] */
|
||||||
class ByAlbum(override val isAscending: Boolean) : Sort(isAscending) {
|
class ByAlbum(override val isAscending: Boolean) : Sort(isAscending) {
|
||||||
|
override val sortIntCode: Int
|
||||||
|
get() = IntegerTable.SORT_BY_ALBUM
|
||||||
|
|
||||||
|
override val itemId: Int
|
||||||
|
get() = R.id.option_sort_album
|
||||||
|
|
||||||
override fun songs(songs: Collection<Song>): List<Song> {
|
override fun songs(songs: Collection<Song>): List<Song> {
|
||||||
return songs.sortedWith(
|
return songs.sortedWith(
|
||||||
MultiComparator(
|
MultiComparator(
|
||||||
|
@ -91,10 +117,20 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
compareBy(NullableComparator()) { it.track },
|
compareBy(NullableComparator()) { it.track },
|
||||||
compareBy(NameComparator()) { it }))
|
compareBy(NameComparator()) { it }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun ascending(newIsAscending: Boolean): Sort {
|
||||||
|
return ByAlbum(newIsAscending)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sort by the artist of an item, only supported by [Album] and [Song] */
|
/** Sort by the artist of an item, only supported by [Album] and [Song] */
|
||||||
class ByArtist(override val isAscending: Boolean) : Sort(isAscending) {
|
class ByArtist(override val isAscending: Boolean) : Sort(isAscending) {
|
||||||
|
override val sortIntCode: Int
|
||||||
|
get() = IntegerTable.SORT_BY_ARTIST
|
||||||
|
|
||||||
|
override val itemId: Int
|
||||||
|
get() = R.id.option_sort_artist
|
||||||
|
|
||||||
override fun songs(songs: Collection<Song>): List<Song> {
|
override fun songs(songs: Collection<Song>): List<Song> {
|
||||||
return songs.sortedWith(
|
return songs.sortedWith(
|
||||||
MultiComparator(
|
MultiComparator(
|
||||||
|
@ -112,10 +148,20 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
compareByDescending(NullableComparator()) { it.year },
|
compareByDescending(NullableComparator()) { it.year },
|
||||||
compareBy(NameComparator()) { it }))
|
compareBy(NameComparator()) { it }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun ascending(newIsAscending: Boolean): Sort {
|
||||||
|
return ByArtist(newIsAscending)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sort by the year of an item, only supported by [Album] and [Song] */
|
/** Sort by the year of an item, only supported by [Album] and [Song] */
|
||||||
class ByYear(override val isAscending: Boolean) : Sort(isAscending) {
|
class ByYear(override val isAscending: Boolean) : Sort(isAscending) {
|
||||||
|
override val sortIntCode: Int
|
||||||
|
get() = IntegerTable.SORT_BY_YEAR
|
||||||
|
|
||||||
|
override val itemId: Int
|
||||||
|
get() = R.id.option_sort_year
|
||||||
|
|
||||||
override fun songs(songs: Collection<Song>): List<Song> {
|
override fun songs(songs: Collection<Song>): List<Song> {
|
||||||
return songs.sortedWith(
|
return songs.sortedWith(
|
||||||
MultiComparator(
|
MultiComparator(
|
||||||
|
@ -131,31 +177,15 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
compareByDynamic(NullableComparator()) { it.year },
|
compareByDynamic(NullableComparator()) { it.year },
|
||||||
compareBy(NameComparator()) { it }))
|
compareBy(NameComparator()) { it }))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the corresponding item id for this sort. */
|
override fun ascending(newIsAscending: Boolean): Sort {
|
||||||
val itemId: Int
|
return ByYear(newIsAscending)
|
||||||
get() =
|
|
||||||
when (this) {
|
|
||||||
is ByName -> R.id.option_sort_name
|
|
||||||
is ByArtist -> R.id.option_sort_artist
|
|
||||||
is ByAlbum -> R.id.option_sort_album
|
|
||||||
is ByYear -> R.id.option_sort_year
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply [ascending] to the status of this sort.
|
|
||||||
* @return A new [Sort] with the value of [ascending] applied.
|
|
||||||
*/
|
|
||||||
fun ascending(ascending: Boolean): Sort {
|
|
||||||
return when (this) {
|
|
||||||
is ByName -> ByName(ascending)
|
|
||||||
is ByArtist -> ByArtist(ascending)
|
|
||||||
is ByAlbum -> ByAlbum(ascending)
|
|
||||||
is ByYear -> ByYear(ascending)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val intCode: Int
|
||||||
|
get() = sortIntCode.shl(1) or if (isAscending) 1 else 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign a new [id] to this sort
|
* Assign a new [id] to this sort
|
||||||
* @return A new [Sort] corresponding to the [id] given, null if the ID has no analogue.
|
* @return A new [Sort] corresponding to the [id] given, null if the ID has no analogue.
|
||||||
|
@ -197,16 +227,6 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
return songs(genre.songs)
|
return songs(genre.songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert this sort to it's integer representation. */
|
|
||||||
fun toInt(): Int {
|
|
||||||
return when (this) {
|
|
||||||
is ByName -> INT_NAME
|
|
||||||
is ByArtist -> INT_ARTIST
|
|
||||||
is ByAlbum -> INT_ALBUM
|
|
||||||
is ByYear -> INT_YEAR
|
|
||||||
}.shl(1) or if (isAscending) 1 else 0
|
|
||||||
}
|
|
||||||
|
|
||||||
protected inline fun <T : Music, K> compareByDynamic(
|
protected inline fun <T : Music, K> compareByDynamic(
|
||||||
comparator: Comparator<in K>,
|
comparator: Comparator<in K>,
|
||||||
crossinline selector: (T) -> K
|
crossinline selector: (T) -> K
|
||||||
|
@ -244,8 +264,8 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
*
|
*
|
||||||
* Sorts often need to compare multiple things at once across several hierarchies, with this
|
* Sorts often need to compare multiple things at once across several hierarchies, with this
|
||||||
* class doing such in a more efficient manner than resorting at multiple intervals or grouping
|
* class doing such in a more efficient manner than resorting at multiple intervals or grouping
|
||||||
* items up. Comparators are checked from first to last, with the first comparator that returns a
|
* items up. Comparators are checked from first to last, with the first comparator that returns
|
||||||
* non-equal result being propagated upwards.
|
* a non-equal result being propagated upwards.
|
||||||
*/
|
*/
|
||||||
class MultiComparator<T>(vararg comparators: Comparator<T>) : Comparator<T> {
|
class MultiComparator<T>(vararg comparators: Comparator<T>) : Comparator<T> {
|
||||||
private val mComparators = comparators
|
private val mComparators = comparators
|
||||||
|
@ -263,24 +283,19 @@ sealed class Sort(open val isAscending: Boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val INT_NAME = 0xA10C
|
|
||||||
private const val INT_ARTIST = 0xA10D
|
|
||||||
private const val INT_ALBUM = 0xA10E
|
|
||||||
private const val INT_YEAR = 0xA10F
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a sort's integer representation into a [Sort] instance.
|
* Convert a sort's integer representation into a [Sort] instance.
|
||||||
*
|
*
|
||||||
* @return A [Sort] instance, null if the data is malformed.
|
* @return A [Sort] instance, null if the data is malformed.
|
||||||
*/
|
*/
|
||||||
fun fromInt(value: Int): Sort? {
|
fun fromIntCode(value: Int): Sort? {
|
||||||
val ascending = (value and 1) == 1
|
val ascending = (value and 1) == 1
|
||||||
|
|
||||||
return when (value.shr(1)) {
|
return when (value.shr(1)) {
|
||||||
INT_NAME -> ByName(ascending)
|
IntegerTable.SORT_BY_NAME -> ByName(ascending)
|
||||||
INT_ARTIST -> ByArtist(ascending)
|
IntegerTable.SORT_BY_ARTIST -> ByArtist(ascending)
|
||||||
INT_ALBUM -> ByAlbum(ascending)
|
IntegerTable.SORT_BY_ALBUM -> ByAlbum(ascending)
|
||||||
INT_YEAR -> ByYear(ascending)
|
IntegerTable.SORT_BY_YEAR -> ByYear(ascending)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,8 +100,6 @@ private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 0xA000
|
|
||||||
|
|
||||||
/** Create an instance of [SongViewHolder] */
|
/** Create an instance of [SongViewHolder] */
|
||||||
fun from(
|
fun from(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -128,8 +126,6 @@ private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 0xA001
|
|
||||||
|
|
||||||
/** Create an instance of [AlbumViewHolder] */
|
/** Create an instance of [AlbumViewHolder] */
|
||||||
fun from(
|
fun from(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -156,8 +152,6 @@ private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 0xA002
|
|
||||||
|
|
||||||
/** Create an instance of [ArtistViewHolder] */
|
/** Create an instance of [ArtistViewHolder] */
|
||||||
fun from(
|
fun from(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -184,8 +178,6 @@ private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 0xA003
|
|
||||||
|
|
||||||
/** Create an instance of [GenreViewHolder] */
|
/** Create an instance of [GenreViewHolder] */
|
||||||
fun from(
|
fun from(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -207,8 +199,6 @@ class HeaderViewHolder private constructor(private val binding: ItemHeaderBindin
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 0xA004
|
|
||||||
|
|
||||||
/** Create an instance of [HeaderViewHolder] */
|
/** Create an instance of [HeaderViewHolder] */
|
||||||
fun from(context: Context): HeaderViewHolder {
|
fun from(context: Context): HeaderViewHolder {
|
||||||
return HeaderViewHolder(ItemHeaderBinding.inflate(context.inflater))
|
return HeaderViewHolder(ItemHeaderBinding.inflate(context.inflater))
|
||||||
|
@ -233,8 +223,6 @@ class ActionHeaderViewHolder private constructor(private val binding: ItemAction
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ITEM_TYPE = 0xA005
|
|
||||||
|
|
||||||
/** Create an instance of [ActionHeaderViewHolder] */
|
/** Create an instance of [ActionHeaderViewHolder] */
|
||||||
fun from(context: Context): ActionHeaderViewHolder {
|
fun from(context: Context): ActionHeaderViewHolder {
|
||||||
return ActionHeaderViewHolder(ItemActionHeaderBinding.inflate(context.inflater))
|
return ActionHeaderViewHolder(ItemActionHeaderBinding.inflate(context.inflater))
|
||||||
|
|
|
@ -40,10 +40,9 @@ import androidx.annotation.StringRes
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
import org.oxycblt.auxio.IntegerTable
|
||||||
import org.oxycblt.auxio.MainActivity
|
import org.oxycblt.auxio.MainActivity
|
||||||
|
|
||||||
const val INTENT_REQUEST_CODE = 0xA0A0
|
|
||||||
|
|
||||||
/** Shortcut to get a [LayoutInflater] from a [Context] */
|
/** Shortcut to get a [LayoutInflater] from a [Context] */
|
||||||
val Context.inflater: LayoutInflater
|
val Context.inflater: LayoutInflater
|
||||||
get() = LayoutInflater.from(this)
|
get() = LayoutInflater.from(this)
|
||||||
|
@ -213,7 +212,7 @@ fun Context.showToast(@StringRes str: Int) {
|
||||||
fun Context.newMainIntent(): PendingIntent {
|
fun Context.newMainIntent(): PendingIntent {
|
||||||
return PendingIntent.getActivity(
|
return PendingIntent.getActivity(
|
||||||
this,
|
this,
|
||||||
INTENT_REQUEST_CODE,
|
IntegerTable.REQUEST_CODE,
|
||||||
Intent(this, MainActivity::class.java),
|
Intent(this, MainActivity::class.java),
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
|
||||||
}
|
}
|
||||||
|
@ -222,7 +221,7 @@ fun Context.newMainIntent(): PendingIntent {
|
||||||
fun Context.newBroadcastIntent(what: String): PendingIntent {
|
fun Context.newBroadcastIntent(what: String): PendingIntent {
|
||||||
return PendingIntent.getBroadcast(
|
return PendingIntent.getBroadcast(
|
||||||
this,
|
this,
|
||||||
INTENT_REQUEST_CODE,
|
IntegerTable.REQUEST_CODE,
|
||||||
Intent(what),
|
Intent(what),
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
|
@ -117,7 +118,7 @@ private fun isUnderImpl(
|
||||||
val View.isRtl: Boolean
|
val View.isRtl: Boolean
|
||||||
get() = layoutDirection == View.LAYOUT_DIRECTION_RTL
|
get() = layoutDirection == View.LAYOUT_DIRECTION_RTL
|
||||||
val Drawable.isRtl: Boolean
|
val Drawable.isRtl: Boolean
|
||||||
get() = layoutDirection == View.LAYOUT_DIRECTION_RTL
|
get() = DrawableCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve system bar insets in a version-aware manner. This can be used to apply padding to a view
|
* Resolve system bar insets in a version-aware manner. This can be used to apply padding to a view
|
||||||
|
|
|
@ -172,12 +172,10 @@
|
||||||
<string name="fmt_songs_loaded">已加载 %d 首曲目</string>
|
<string name="fmt_songs_loaded">已加载 %d 首曲目</string>
|
||||||
|
|
||||||
<plurals name="fmt_song_count">
|
<plurals name="fmt_song_count">
|
||||||
<item quantity="one">%d 首歌曲</item>
|
|
||||||
<item quantity="other">"%d 首歌曲"</item>
|
<item quantity="other">"%d 首歌曲"</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
<plurals name="fmt_album_count">
|
<plurals name="fmt_album_count">
|
||||||
<item quantity="one">%d 张专辑</item>
|
|
||||||
<item quantity="other">"%d 张专辑"</item>
|
<item quantity="other">"%d 张专辑"</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<integer name="detail_app_bar_title_anim_duration">150</integer>
|
<integer name="detail_app_bar_title_anim_duration">150</integer>
|
||||||
|
|
||||||
|
<!-- FIXME: This is really stupid, figure out how we can unify it with the C object-->
|
||||||
<!-- Preference values -->
|
<!-- Preference values -->
|
||||||
<string-array name="entries_theme">
|
<string-array name="entries_theme">
|
||||||
<item>@string/set_theme_auto</item>
|
<item>@string/set_theme_auto</item>
|
||||||
|
|
|
@ -150,58 +150,8 @@ system events, such as when a button is pressed on a headset. It should **never*
|
||||||
|
|
||||||
#### Data Integers
|
#### Data Integers
|
||||||
Integer representations of data/UI elements are used heavily in Auxio, primarily for efficiency.
|
Integer representations of data/UI elements are used heavily in Auxio, primarily for efficiency.
|
||||||
To prevent any strange bugs, all integer representations must be unique. A table of all current integers used are shown below:
|
To prevent any strange bugs, all integer representations must be unique. To see a table of all current integers, see the `C` class within
|
||||||
|
the project.
|
||||||
```
|
|
||||||
0xA0XX | UI Integer Space [Required by android]
|
|
||||||
|
|
||||||
0xA000 | SongViewHolder
|
|
||||||
0xA001 | AlbumViewHolder
|
|
||||||
0xA002 | ArtistViewHolder
|
|
||||||
0xA003 | GenreViewHolder
|
|
||||||
0xA004 | HeaderViewHolder
|
|
||||||
0xA005 | ActionHeaderViewHolder
|
|
||||||
|
|
||||||
0xA006 | AlbumDetailViewHolder
|
|
||||||
0xA007 | AlbumSongViewHolder
|
|
||||||
0xA008 | ArtistDetailViewHolder
|
|
||||||
0xA009 | ArtistAlbumViewHolder
|
|
||||||
0xA00A | ArtistSongViewHolder
|
|
||||||
0xA00B | GenreDetailViewHolder
|
|
||||||
0xA00C | GenreSongViewHolder
|
|
||||||
|
|
||||||
0xA00D | QueueSongViewHolder
|
|
||||||
|
|
||||||
0xA0A0 | Auxio notification code
|
|
||||||
0xA0C0 | Auxio request code
|
|
||||||
|
|
||||||
0xA1XX | Data Integer Space [Stored for IO efficency]
|
|
||||||
|
|
||||||
0xA100 | LoopMode.NONE
|
|
||||||
0xA101 | LoopMode.ALL
|
|
||||||
0xA102 | LoopMode.TRACK
|
|
||||||
|
|
||||||
0xA103 | PlaybackMode.IN_GENRE
|
|
||||||
0xA104 | PlaybackMode.IN_ARTIST
|
|
||||||
0xA105 | PlaybackMode.IN_ALBUM
|
|
||||||
0xA106 | PlaybackMode.ALL_SONGS
|
|
||||||
|
|
||||||
0xA107 | Null DisplayMode [Filter Nothing]
|
|
||||||
0xA108 | DisplayMode.SHOW_GENRES
|
|
||||||
0xA109 | DisplayMode.SHOW_ARTISTS
|
|
||||||
0xA10A | DisplayMode.SHOW_ALBUMS
|
|
||||||
0xA10B | DisplayMode.SHOW_SONGS
|
|
||||||
|
|
||||||
0xA10C | Sort.Name
|
|
||||||
0xA10D | Sort.Artist
|
|
||||||
0xA10E | Sort.Album
|
|
||||||
0xA10F | Sort.Year
|
|
||||||
|
|
||||||
0xA110 | ReplayGainMode.OFF
|
|
||||||
0xA111 | ReplayGainMode.TRACK
|
|
||||||
0xA112 | ReplayGainMode.ALBUM
|
|
||||||
0xA113 | ReplayGainMode.DYNAMIC
|
|
||||||
```
|
|
||||||
|
|
||||||
Some datatypes [like `Tab` and `Sort`] have even more fine-grained integer representations for other data. More information can be found in
|
Some datatypes [like `Tab` and `Sort`] have even more fine-grained integer representations for other data. More information can be found in
|
||||||
the documentation for those datatypes.
|
the documentation for those datatypes.
|
||||||
|
|
Loading…
Reference in a new issue