diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index fc7e6d356..339d30a3f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -9,10 +9,10 @@ import androidx.navigation.fragment.navArgs import org.oxycblt.auxio.R import org.oxycblt.auxio.detail.adapters.ArtistDetailAdapter import org.oxycblt.auxio.logD -import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.BaseModel +import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.state.PlaybackMode @@ -63,16 +63,6 @@ class ArtistDetailFragment : DetailFragment() { } ) - // We build the action header here since it's both more efficent to keep one action header - // and it also prevents the header from being constantly refreshed when the sort is updated. - - val songsHeader = ActionHeader( - id = -2, - name = getString(R.string.label_songs), - icon = detailModel.artistSortMode.value!!.iconRes, - action = detailModel::incrementArtistSortMode - ) - // --- UI SETUP --- binding.lifecycleOwner = this @@ -80,7 +70,7 @@ class ArtistDetailFragment : DetailFragment() { setupToolbar() setupRecycler(detailAdapter) { pos -> // If the item is an ActionHeader we need to also make the item full-width - pos == 0 || detailAdapter.currentList.getOrNull(pos) is ActionHeader + pos == 0 || detailAdapter.currentList.getOrNull(pos) is Header } // --- VIEWMODEL SETUP --- @@ -91,8 +81,17 @@ class ArtistDetailFragment : DetailFragment() { val artist = detailModel.currentArtist.value!! val data = mutableListOf(artist) + data.addAll(SortMode.NUMERIC_DOWN.getSortedAlbumList(artist.albums)) - data.add(songsHeader) + + data.add( + Header( + id = -2, + name = getString(R.string.label_songs), + isAction = true + ) + ) + data.addAll(mode.getSortedArtistSongList(artist.songs)) detailAdapter.submitList(data) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/adapters/ArtistDetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/adapters/ArtistDetailAdapter.kt index 8ab3d6535..17ca9b403 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/adapters/ArtistDetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/adapters/ArtistDetailAdapter.kt @@ -10,10 +10,10 @@ import org.oxycblt.auxio.databinding.ItemArtistHeaderBinding import org.oxycblt.auxio.databinding.ItemArtistSongBinding import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.logD -import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.BaseModel +import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.recycler.DiffCallback @@ -46,7 +46,7 @@ class ArtistDetailAdapter( return when (getItem(position)) { is Artist -> ARTIST_HEADER_ITEM_TYPE is Album -> ARTIST_ALBUM_ITEM_TYPE - is ActionHeader -> ARTIST_SONG_HEADER_ITEM_TYPE + is Header -> ARTIST_SONG_HEADER_ITEM_TYPE is Song -> ARTIST_SONG_ITEM_TYPE else -> -1 @@ -81,7 +81,7 @@ class ArtistDetailAdapter( when (item) { is Artist -> (holder as ArtistHeaderViewHolder).bind(item) is Album -> (holder as ArtistAlbumViewHolder).bind(item) - is ActionHeader -> (holder as ArtistSongHeaderViewHolder).bind(item) + is Header -> (holder as ArtistSongHeaderViewHolder).bind(item) is Song -> (holder as ArtistSongViewHolder).bind(item) else -> {} @@ -199,9 +199,9 @@ class ArtistDetailAdapter( inner class ArtistSongHeaderViewHolder( private val binding: ItemActionHeaderBinding - ) : BaseViewHolder(binding) { + ) : BaseViewHolder
(binding) { - override fun onBind(data: ActionHeader) { + override fun onBind(data: Header) { binding.header = data binding.headerButton.apply { @@ -211,7 +211,7 @@ class ArtistDetailAdapter( setImageResource(sortMode.value!!.iconRes) setOnClickListener { - data.action() // Should call DetailViewModel.incrementArtistSortMode + detailModel.incrementArtistSortMode() setImageResource(sortMode.value!!.iconRes) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/Models.kt b/app/src/main/java/org/oxycblt/auxio/music/Models.kt index 58f9fcab1..f361571ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Models.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Models.kt @@ -1,7 +1,6 @@ package org.oxycblt.auxio.music import android.net.Uri -import androidx.annotation.DrawableRes // --- MUSIC MODELS --- @@ -189,20 +188,10 @@ data class Genre( /** * A data object used solely for the "Header" UI element. Inherits [BaseModel]. + * @param isAction Whether this header corresponds to an action or not */ data class Header( override val id: Long, override val name: String, -) : BaseModel() - -/** - * A data object for a header with an action button. Inherits [BaseModel]. - * @property icon The icon ot apply for this header. - * @property action The callback that will be called when the action button is clicked. - */ -data class ActionHeader( - override val id: Long, - override val name: String, - @DrawableRes val icon: Int, - val action: () -> Unit, + val isAction: Boolean = false ) : BaseModel() diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt index ec52ccbcb..0913246ef 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueAdapter.kt @@ -3,17 +3,19 @@ package org.oxycblt.auxio.playback.queue import android.annotation.SuppressLint import android.view.MotionEvent import android.view.ViewGroup +import androidx.appcompat.widget.TooltipCompat import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView +import org.oxycblt.auxio.R +import org.oxycblt.auxio.databinding.ItemActionHeaderBinding import org.oxycblt.auxio.databinding.ItemQueueSongBinding import org.oxycblt.auxio.logE -import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.recycler.DiffCallback -import org.oxycblt.auxio.recycler.viewholders.ActionHeaderViewHolder import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder import org.oxycblt.auxio.recycler.viewholders.HeaderViewHolder import org.oxycblt.auxio.ui.inflater @@ -21,10 +23,12 @@ import org.oxycblt.auxio.ui.inflater /** * The single adapter for both the Next Queue and the User Queue. * @param touchHelper The [ItemTouchHelper] ***containing*** [QueueDragCallback] to be used + * @param playbackModel The [PlaybackViewModel] for updates to be dispatched to * @author OxygenCobalt */ class QueueAdapter( - private val touchHelper: ItemTouchHelper + private val touchHelper: ItemTouchHelper, + private val playbackModel: PlaybackViewModel ) : RecyclerView.Adapter() { private var data = mutableListOf() private var listDiffer = AsyncListDiffer(this, DiffCallback()) @@ -32,12 +36,15 @@ class QueueAdapter( override fun getItemCount(): Int = data.size override fun getItemViewType(position: Int): Int { - val item = data[position] + return when (val item = data[position]) { + is Header -> if (item.isAction) { + USER_QUEUE_HEADER_ITEM_TYPE + } else { + HeaderViewHolder.ITEM_TYPE + } - return when (item) { - is Header -> HeaderViewHolder.ITEM_TYPE - is ActionHeader -> ActionHeaderViewHolder.ITEM_TYPE is Song -> QUEUE_SONG_ITEM_TYPE + else -> -1 } } @@ -46,7 +53,9 @@ class QueueAdapter( return when (viewType) { HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context) - ActionHeaderViewHolder.ITEM_TYPE -> ActionHeaderViewHolder.from(parent.context) + USER_QUEUE_HEADER_ITEM_TYPE -> UserQueueHeaderViewHolder( + ItemActionHeaderBinding.inflate(parent.context.inflater) + ) QUEUE_SONG_ITEM_TYPE -> QueueSongViewHolder( ItemQueueSongBinding.inflate(parent.context.inflater) @@ -58,9 +67,13 @@ class QueueAdapter( override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (val item = data[position]) { + is Header -> if (item.isAction) { + (holder as UserQueueHeaderViewHolder).bind(item) + } else { + (holder as HeaderViewHolder).bind(item) + } + is Song -> (holder as QueueSongViewHolder).bind(item) - is Header -> (holder as HeaderViewHolder).bind(item) - is ActionHeader -> (holder as ActionHeaderViewHolder).bind(item) else -> logE("Bad data given to QueueAdapter.") } @@ -145,7 +158,31 @@ class QueueAdapter( } } + /* + * The viewholder for + */ + inner class UserQueueHeaderViewHolder( + private val binding: ItemActionHeaderBinding + ) : BaseViewHolder
(binding) { + + override fun onBind(data: Header) { + binding.header = data + + binding.headerButton.apply { + setImageResource(R.drawable.ic_clear) + + contentDescription = context.getString(R.string.description_clear_user_queue) + TooltipCompat.setTooltipText(this, contentDescription) + + setOnClickListener { + playbackModel.clearUserQueue() + } + } + } + } + companion object { const val QUEUE_SONG_ITEM_TYPE = 0xA005 + const val USER_QUEUE_HEADER_ITEM_TYPE = 0xA006 } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt index 14d46003a..981ca021f 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt @@ -13,7 +13,6 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.ItemTouchHelper import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentQueueBinding -import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.playback.PlaybackViewModel @@ -37,7 +36,7 @@ class QueueFragment : Fragment() { val callback = QueueDragCallback(playbackModel) val helper = ItemTouchHelper(callback) - val queueAdapter = QueueAdapter(helper) + val queueAdapter = QueueAdapter(helper, playbackModel) var lastShuffle = playbackModel.isShuffling.value callback.addQueueAdapter(queueAdapter) @@ -137,13 +136,10 @@ class QueueFragment : Fragment() { val nextQueue = playbackModel.nextItemsInQueue.value!! if (userQueue.isNotEmpty()) { - queue += ActionHeader( + queue += Header( id = -2, name = getString(R.string.label_next_user_queue), - icon = R.drawable.ic_clear, - action = { - playbackModel.clearUserQueue() - } + isAction = true ) queue += userQueue @@ -151,7 +147,9 @@ class QueueFragment : Fragment() { if (nextQueue.isNotEmpty()) { queue += Header( - id = -3, name = getString(R.string.format_next_from, getParentName()), + id = -3, + name = getString(R.string.format_next_from, getParentName()), + isAction = false ) queue += nextQueue diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt b/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt index 55af83fc9..b3a1d91e5 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/viewholders/ModelHolders.kt @@ -2,13 +2,11 @@ package org.oxycblt.auxio.recycler.viewholders import android.content.Context import android.view.View -import org.oxycblt.auxio.databinding.ItemActionHeaderBinding import org.oxycblt.auxio.databinding.ItemAlbumBinding import org.oxycblt.auxio.databinding.ItemArtistBinding import org.oxycblt.auxio.databinding.ItemGenreBinding import org.oxycblt.auxio.databinding.ItemHeaderBinding import org.oxycblt.auxio.databinding.ItemSongBinding -import org.oxycblt.auxio.music.ActionHeader import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre @@ -153,7 +151,9 @@ class GenreViewHolder private constructor( /** * The Shared ViewHolder for a [Header]. Instantiation should be done with [from] */ -class HeaderViewHolder(private val binding: ItemHeaderBinding) : BaseViewHolder
(binding) { +class HeaderViewHolder private constructor( + private val binding: ItemHeaderBinding +) : BaseViewHolder
(binding) { override fun onBind(data: Header) { binding.header = data @@ -172,35 +172,3 @@ class HeaderViewHolder(private val binding: ItemHeaderBinding) : BaseViewHolder< } } } - -/** - * The Shared ViewHolder for a [ActionHeader]. Instantiation should be done with [from] - */ -class ActionHeaderViewHolder( - private val binding: ItemActionHeaderBinding -) : BaseViewHolder(binding) { - - override fun onBind(data: ActionHeader) { - binding.header = data - binding.headerButton.apply { - setImageResource(data.icon) - - setOnClickListener { - data.action() - } - } - } - - companion object { - const val ITEM_TYPE = 0xA006 - - /** - * Create an instance of [ActionHeaderViewHolder] - */ - fun from(context: Context): ActionHeaderViewHolder { - return ActionHeaderViewHolder( - ItemActionHeaderBinding.inflate(context.inflater) - ) - } - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistViewModel.kt b/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistViewModel.kt index 94fb63730..7181e0839 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistViewModel.kt @@ -62,7 +62,7 @@ class BlacklistViewModel(context: Context) : ViewModel() { /** * Load the paths stored in the database to this ViewModel, will erase any pending changes. */ - fun loadDatabasePaths() { + private fun loadDatabasePaths() { viewModelScope.launch(Dispatchers.IO) { dbPaths = blacklistDatabase.readPaths() diff --git a/app/src/main/res/animator/animator_thumb.xml b/app/src/main/res/animator/animator_thumb.xml index e35ef53a5..44a8314f2 100644 --- a/app/src/main/res/animator/animator_thumb.xml +++ b/app/src/main/res/animator/animator_thumb.xml @@ -1,5 +1,4 @@ - - + diff --git a/app/src/main/res/layout-land/item_album_header.xml b/app/src/main/res/layout-land/item_album_header.xml index ae077e064..35a434b1e 100644 --- a/app/src/main/res/layout-land/item_album_header.xml +++ b/app/src/main/res/layout-land/item_album_header.xml @@ -95,9 +95,9 @@ + type="org.oxycblt.auxio.music.Header" /> @@ -22,10 +22,10 @@ android:id="@+id/scroll_thumb_text" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center" - android:textSize="@dimen/text_size_thumb" - android:textColor="?android:attr/windowBackground" android:fontFamily="@font/inter_semibold" + android:gravity="center" + android:textColor="?android:attr/windowBackground" + android:textSize="@dimen/text_size_thumb" tools:text="A" /> @@ -38,9 +38,9 @@ android:gravity="center" android:includeFontPadding="false" android:lineSpacingExtra="@dimen/spacing_tiny" + android:minWidth="@dimen/width_fast_scroll" android:paddingTop="@dimen/spacing_tiny" android:paddingBottom="@dimen/spacing_tiny" - android:minWidth="@dimen/width_fast_scroll" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index bbd3e0212..eca70cfe5 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index bbd3e0212..eca70cfe5 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 641920235..061284755 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -2,7 +2,6 @@ Musikwiedergabe - der Musikwiedergabedienst von Auxio. Wieder Versuchen diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 185318b3d..01ecb82b0 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -3,7 +3,6 @@ Een eenvoudige, rationele muziekspeler voor Android. Muziek Afspelen - De muziekweergaveservice voor Auxio. Opnieuw proberen diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 4b7edac4f..2cdd2af48 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -12,13 +12,11 @@ 2dp - 40dp 32dp 1dp 20dp - 64dp 48dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fb7dbdd38..fad109385 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,7 +3,6 @@ A simple, rational music player for android. Music Playback - The music playback service for Auxio. Retry diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index e17709756..9be4bb84e 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -8,9 +8,9 @@ app:defaultValue="@integer/theme_auto" app:entries="@array/entires_theme" app:entryValues="@array/values_theme" + app:icon="@drawable/ic_day" app:iconSpaceReserved="false" app:key="KEY_THEME2" - app:icon="@drawable/ic_day" app:title="@string/setting_theme" />