diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f2355bce..e4f49155f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,9 @@ #### What's New - Added a new view for song properties (Such as Bitrate) - Folders on external drives can now be excluded on Android Q+ [#134] -- Playback bar now has a skip action -- When playing, the cover now shows an animated indicator +- The playback bar now has a new design, with an improved progress +indicator and a skip action +- When playing, covers now shows an animated indicator #### What's Improved - The toolbar in the home UI now collapses when scrolling @@ -20,7 +21,7 @@ - Songs with no data (i.e size of 0) are now filtered out #### Dev/Meta -- New translations [Fjuro -> Czech] +- New translations [Fjuro -> Czech, Konstantin Tutsch -> German] - Moved music loading to a foreground service - Phased out `ImageButton` for `MaterialButton` - Unified icon sizing diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt index d78b981a7..641c97e83 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -110,6 +110,10 @@ class DetailViewModel : ViewModel(), MusicStore.Callback { generateDetailSong(context, song) } + fun clearSong() { + _currentSong.value = null + } + fun setAlbumId(id: Long) { if (_currentAlbum.value?.id == id) return val library = unlikelyToBeNull(musicStore.library) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index 346eb5a77..cea5d44f0 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -119,7 +119,6 @@ class GenreDetailFragment : DetailFragment(), DetailAdapter.Listener { logD("Navigating to another album") findNavController().navigate(GenreDetailFragmentDirections.actionShowAlbum(item.id)) } - // All items will launch new detail fragments. is Artist -> { logD("Navigating to another artist") findNavController() diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ReadOnlyTextInput.kt b/app/src/main/java/org/oxycblt/auxio/detail/ReadOnlyTextInput.kt index f62689353..4882907a7 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ReadOnlyTextInput.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ReadOnlyTextInput.kt @@ -44,6 +44,7 @@ class ReadOnlyTextInput : TextInputEditText { ) : super(context, attrs, defStyleAttr) init { + setTextIsSelectable(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { focusable = View.FOCUSABLE_AUTO } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt index 1b97baa96..743fb1f90 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/SongDetailDialog.kt @@ -50,6 +50,11 @@ class SongDetailDialog : ViewBindingDialogFragment() { launch { detailModel.currentSong.collect(::updateSong) } } + override fun onDestroy() { + super.onDestroy() + detailModel.clearSong() + } + private fun updateSong(song: DetailViewModel.DetailSong?) { val binding = requireBinding() diff --git a/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt b/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt index c3e1314ab..234b496d8 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/recycler/DetailAdapter.kt @@ -95,6 +95,7 @@ abstract class DetailAdapter( } } + // TODO: Pause indicator animation when not playing viewHolder.itemView.isActivated = shouldHighlightViewHolder(item) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt index baa6a819c..0aff6cfa9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/excluded/ExcludedDialog.kt @@ -115,7 +115,6 @@ class ExcludedDialog : override fun onRemoveDirectory(dir: Dir.Relative) { excludedAdapter.data.remove(dir) - requireBinding().excludedEmpty.isVisible = excludedAdapter.data.currentList.isEmpty() } private fun addDocTreePath(uri: Uri?) { diff --git a/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPrefDialog.kt b/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPrefDialog.kt index d991c8099..80b4cd516 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPrefDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/pref/IntListPrefDialog.kt @@ -37,6 +37,7 @@ class IntListPreferenceDialog : PreferenceDialogFragmentCompat() { builder.setTitle(listPreference.title) builder.setPositiveButton(null, null) builder.setNegativeButton(R.string.lbl_cancel, null) + // TODO: Replace this with an in-house view builder.setSingleChoiceItems(listPreference.entries, listPreference.getValueIndex()) { _, index -> diff --git a/app/src/main/java/org/oxycblt/auxio/ui/DialogRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/ui/DialogRecyclerView.kt new file mode 100644 index 000000000..42a8d5ea3 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/ui/DialogRecyclerView.kt @@ -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 . + */ + +package org.oxycblt.auxio.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.ViewGroup +import androidx.annotation.AttrRes +import androidx.core.view.isInvisible +import androidx.core.view.updatePadding +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.divider.MaterialDivider +import org.oxycblt.auxio.R +import org.oxycblt.auxio.util.getDimenSizeSafe +import org.oxycblt.auxio.util.logD + +/** + * A RecyclerView that enables something resembling the android:scrollIndicators attribute. + * Only used in dialogs. + * @author OxygenCobalt + */ +class DialogRecyclerView +@JvmOverloads +constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : + RecyclerView(context, attrs, defStyleAttr) { + private val topDivider = MaterialDivider(context) + private val bottomDivider = MaterialDivider(context) + + private val spacingMedium = context.getDimenSizeSafe(R.dimen.spacing_medium) + + init { + updatePadding(top = spacingMedium) + overScrollMode = OVER_SCROLL_NEVER + + overlay.apply { + add(topDivider) + add(bottomDivider) + } + + addOnScrollListener( + object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + + val manager = recyclerView.layoutManager as LinearLayoutManager + logD("top invisible: ${manager.findFirstCompletelyVisibleItemPosition() < 1}") + // logD( + // "bottom invisible: + // ${manager.findLastCompletelyVisibleItemPosition() < (manager.itemCount - + // 1)}") + topDivider.isInvisible = manager.findFirstCompletelyVisibleItemPosition() < 1 + bottomDivider.isInvisible = + manager.findLastCompletelyVisibleItemPosition() == (manager.itemCount - 1) + } + }) + } + + override fun onMeasure(widthSpec: Int, heightSpec: Int) { + super.onMeasure(widthSpec, heightSpec) + measureDivider(topDivider) + measureDivider(bottomDivider) + } + + private fun measureDivider(divider: MaterialDivider) { + val widthMeasureSpec = + ViewGroup.getChildMeasureSpec( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + 0, + divider.layoutParams.width) + + val heightMeasureSpec = + ViewGroup.getChildMeasureSpec( + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), + 0, + divider.layoutParams.height) + + divider.measure(widthMeasureSpec, heightMeasureSpec) + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + super.onLayout(changed, l, t, r, b) + topDivider.layout(l, spacingMedium, r, spacingMedium + topDivider.measuredHeight) + bottomDivider.layout(l, measuredHeight - bottomDivider.measuredHeight, r, b) + } +} diff --git a/app/src/main/res/layout/dialog_accent.xml b/app/src/main/res/layout/dialog_accent.xml index 4734531ea..7e5b9e04c 100644 --- a/app/src/main/res/layout/dialog_accent.xml +++ b/app/src/main/res/layout/dialog_accent.xml @@ -1,15 +1,12 @@ - + android:layout_height="match_parent" + style="@style/Widget.Auxio.Dialog.NestedScrollView"> + android:layout_height="match_parent"> + android:layout_height="match_parent" + style="@style/Widget.Auxio.Dialog.NestedScrollView"> + tools:visibility="visible" + android:showDividers="middle"> - + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles_android.xml b/app/src/main/res/values/styles_android.xml index 0a427fa71..310fa72a3 100644 --- a/app/src/main/res/values/styles_android.xml +++ b/app/src/main/res/values/styles_android.xml @@ -33,6 +33,12 @@ 0dp + + +