diff --git a/README.md b/README.md index c41a9d029..55324be1a 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ I primarily built Auxio for myself, but you can use it too, I guess. - Search Functionality - Audio Focus / Headset Management - No internet connectivity whatsoever -- No rounded album corners +- No rounded album covers ## To possibly come in the future: diff --git a/app/build.gradle b/app/build.gradle index 373e6165c..e5d3281f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,7 +63,7 @@ dependencies { // --- SUPPORT --- // General - implementation "androidx.core:core-ktx:1.6.0" + implementation "androidx.core:core-ktx:1.7.0" implementation "androidx.activity:activity-ktx:1.3.1" implementation 'androidx.fragment:fragment-ktx:1.3.6' @@ -74,7 +74,7 @@ dependencies { implementation "androidx.viewpager2:viewpager2:1.1.0-beta01" // Lifecycle - def lifecycle_version = "2.3.1" + def lifecycle_version = "2.4.0" implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index 5dd36946b..442dde45f 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -26,8 +26,6 @@ import android.view.ViewGroup import android.widget.Button import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.res.ResourcesCompat -import androidx.core.view.isVisible -import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import com.google.android.material.snackbar.Snackbar @@ -35,8 +33,6 @@ import org.oxycblt.auxio.databinding.FragmentMainBinding import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.playback.PlaybackViewModel -import org.oxycblt.auxio.util.applyEdge -import org.oxycblt.auxio.util.applyMaterialDrawable import org.oxycblt.auxio.util.logD /** @@ -65,25 +61,26 @@ class MainFragment : Fragment() { binding.lifecycleOwner = viewLifecycleOwner - binding.applyEdge { bars -> - binding.mainPlayback.updatePadding(bottom = bars.bottom) + // --- VIEWMODEL SETUP --- + + if (playbackModel.song.value != null) { + binding.mainBarLayout.showBar() + } else { + binding.mainBarLayout.hideBar() } - binding.mainPlayback.applyMaterialDrawable() - - // --- VIEWMODEL SETUP --- + playbackModel.song.observe(viewLifecycleOwner) { song -> + if (song != null) { + binding.mainBarLayout.showBar() + } else { + binding.mainBarLayout.hideBar() + } + } // Initialize music loading. Unlike MainFragment, we can not only do this here on startup // but also show a SnackBar in a reasonable place in this fragment. musicModel.loadMusic(requireContext()) - // Change CompactPlaybackFragment's visibility here so that an animation occurs. - binding.mainPlayback.isVisible = playbackModel.song.value != null - - playbackModel.song.observe(viewLifecycleOwner) { song -> - binding.mainPlayback.isVisible = song != null - } - // Handle the music loader response. musicModel.loaderResponse.observe(viewLifecycleOwner) { response -> // Handle the loader response. diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt index 584598f78..cd9bd0365 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt @@ -24,7 +24,6 @@ import androidx.activity.OnBackPressedCallback import androidx.annotation.MenuRes import androidx.appcompat.widget.PopupMenu import androidx.core.view.forEach -import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -35,8 +34,6 @@ import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.SortMode import org.oxycblt.auxio.ui.memberBinding -import org.oxycblt.auxio.util.applyEdge -import org.oxycblt.auxio.util.applyEdgeRespectingBar import org.oxycblt.auxio.util.isLandscape /** @@ -49,12 +46,6 @@ abstract class DetailFragment : Fragment() { protected val binding by memberBinding(FragmentDetailBinding::inflate) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - binding.applyEdge { bars -> - binding.detailAppbar.updatePadding(top = bars.top) - } - - binding.detailRecycler.applyEdgeRespectingBar(playbackModel, viewLifecycleOwner) - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback) } diff --git a/app/src/main/java/org/oxycblt/auxio/excluded/ExcludedViewModel.kt b/app/src/main/java/org/oxycblt/auxio/excluded/ExcludedViewModel.kt index 4e3fbf67b..dcd22b2aa 100644 --- a/app/src/main/java/org/oxycblt/auxio/excluded/ExcludedViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/excluded/ExcludedViewModel.kt @@ -95,7 +95,7 @@ class ExcludedViewModel(context: Context) : ViewModel() { fun isModified() = dbPaths != paths.value class Factory(private val context: Context) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { + override fun create(modelClass: Class): T { check(modelClass.isAssignableFrom(ExcludedViewModel::class.java)) { "ExcludedViewModel.Factory does not support this class" } diff --git a/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt b/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt new file mode 100644 index 000000000..fa2f68b76 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Auxio Project + * EdgeFloatingActionButton.kt is part of Auxio. + * + * 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.home + +import android.content.Context +import android.util.AttributeSet +import android.view.WindowInsets +import android.widget.FrameLayout +import androidx.core.view.updatePadding +import org.oxycblt.auxio.util.systemBarsCompat + +class FloatingActionButtonContainer @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = -1 +) : FrameLayout(context, attrs, defStyleAttr) { + override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { + updatePadding(bottom = insets.systemBarsCompat.bottom) + + return insets + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index c46e3b00f..8b331f89a 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -25,7 +25,6 @@ import android.view.View import android.view.ViewGroup import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.iterator -import androidx.core.view.updatePadding import androidx.core.view.updatePaddingRelative import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -52,7 +51,6 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.SortMode -import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logE @@ -73,19 +71,12 @@ class HomeFragment : Fragment() { savedInstanceState: Bundle? ): View { val binding = FragmentHomeBinding.inflate(inflater) - var bottomPadding = 0 val sortItem: MenuItem // --- UI SETUP --- binding.lifecycleOwner = viewLifecycleOwner - binding.applyEdge { bars -> - bottomPadding = bars.bottom - updateFabPadding(binding, bottomPadding) - binding.homeAppbar.updatePadding(top = bars.top) - } - binding.homeAppbar.apply { // I have no idea how to clip the collapsing toolbar while still making the elevation // overlay bleed into the status bar, so I take the easy way out and just fade the @@ -298,10 +289,6 @@ class HomeFragment : Fragment() { } } - playbackModel.song.observe(viewLifecycleOwner) { - updateFabPadding(binding, bottomPadding) - } - logD("Fragment Created.") return binding.root @@ -323,23 +310,6 @@ class HomeFragment : Fragment() { } } - private fun updateFabPadding( - binding: FragmentHomeBinding, - bottomPadding: Int - ) { - // To get our FAB to work with edge-to-edge, we need keep track of the bar view and update - // the padding based off of that. However, we can't use the shared method here since FABs - // don't respect padding, so we duplicate the code here except with the margins instead. - val fabParams = binding.homeFab.layoutParams as CoordinatorLayout.LayoutParams - val baseSpacing = resources.getDimensionPixelSize(R.dimen.spacing_medium) - - if (playbackModel.song.value == null) { - fabParams.bottomMargin = baseSpacing + bottomPadding - } else { - fabParams.bottomMargin = baseSpacing - } - } - private val DisplayMode.viewId: Int get() = when (this) { DisplayMode.SHOW_SONGS -> R.id.home_song_list DisplayMode.SHOW_ALBUMS -> R.id.home_album_list diff --git a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt index 419fb9dda..b1898588c 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt @@ -30,6 +30,7 @@ import android.view.MotionEvent import android.view.View import android.view.ViewConfiguration import android.view.ViewGroup +import android.view.WindowInsets import android.widget.FrameLayout import android.widget.TextView import androidx.appcompat.widget.AppCompatTextView @@ -66,6 +67,7 @@ import kotlin.math.abs * - Added drag listener * - TODO: Added documentation * - TODO: Popup will center itself to the thumb when possible + * - TODO: Stabilize how I'm using padding */ class FastScrollRecyclerView @JvmOverloads constructor( context: Context, @@ -107,6 +109,14 @@ class FastScrollRecyclerView @JvmOverloads constructor( hideScrollbar() } + private val initialPadding = Rect( + paddingLeft, paddingTop, paddingRight, paddingBottom + ) + + private val scrollerPadding = Rect( + 0, 0, 0, 0 + ) + init { val thumbDrawable = R.drawable.ui_scroll_thumb.resolveDrawable(context) @@ -207,7 +217,10 @@ class FastScrollRecyclerView @JvmOverloads constructor( width - paddingRight - thumbWidth } - trackView.layout(trackLeft, paddingTop, trackLeft + thumbWidth, height - paddingBottom) + trackView.layout( + trackLeft, paddingTop, trackLeft + thumbWidth, + height - scrollerPadding.bottom + ) val thumbLeft = if (isRtl) { paddingLeft @@ -237,14 +250,14 @@ class FastScrollRecyclerView @JvmOverloads constructor( val widthMeasureSpec = ViewGroup.getChildMeasureSpec( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - paddingLeft + paddingRight + thumbWidth + popupLayoutParams.leftMargin + - popupLayoutParams.rightMargin, + scrollerPadding.left + scrollerPadding.right + thumbWidth + + popupLayoutParams.leftMargin + popupLayoutParams.rightMargin, popupLayoutParams.width ) val heightMeasureSpec = ViewGroup.getChildMeasureSpec( MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), - paddingTop + paddingBottom + popupLayoutParams.topMargin + + scrollerPadding.top + scrollerPadding.bottom + popupLayoutParams.topMargin + popupLayoutParams.bottomMargin, popupLayoutParams.height ) @@ -255,9 +268,9 @@ class FastScrollRecyclerView @JvmOverloads constructor( val popupWidth = popupView.measuredWidth val popupHeight = popupView.measuredHeight val popupLeft = if (layoutDirection == View.LAYOUT_DIRECTION_RTL) { - paddingLeft + thumbWidth + popupLayoutParams.leftMargin + scrollerPadding.left + thumbWidth + popupLayoutParams.leftMargin } else { - width - paddingRight - thumbWidth - popupLayoutParams.rightMargin - popupWidth + width - scrollerPadding.right - thumbWidth - popupLayoutParams.rightMargin - popupWidth } // We handle RTL separately, so it's okay if Gravity.RIGHT is used here @@ -280,8 +293,8 @@ class FastScrollRecyclerView @JvmOverloads constructor( val popupTop = MathUtils.clamp( thumbTop + thumbAnchorY - popupAnchorY, - paddingTop + popupLayoutParams.topMargin, - height - paddingBottom - popupLayoutParams.bottomMargin - popupHeight + scrollerPadding.top + popupLayoutParams.topMargin, + height - scrollerPadding.bottom - popupLayoutParams.bottomMargin - popupHeight ) popupView.layout( @@ -310,6 +323,17 @@ class FastScrollRecyclerView @JvmOverloads constructor( didRelayout = changed } + override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { + setPadding( + initialPadding.left, initialPadding.top, initialPadding.right, + initialPadding.bottom + insets.systemWindowInsetBottom + ) + + scrollerPadding.bottom = insets.systemWindowInsetBottom + + return insets + } + private fun updateScrollbarState() { if (!canScroll() || childCount == 0) { return @@ -348,7 +372,7 @@ class FastScrollRecyclerView @JvmOverloads constructor( val scrollOffset = paddingTop + (itemPos * itemHeight) - itemTop // The range of pixels where the thumb is not present - val thumbOffsetRange = height - paddingTop - paddingBottom - thumbHeight + val thumbOffsetRange = height - scrollerPadding.top - scrollerPadding.bottom - thumbHeight // Finally, we can calculate the thumb position, which is just: // [proportion of scroll position to scroll range] * [total thumb range] @@ -375,7 +399,7 @@ class FastScrollRecyclerView @JvmOverloads constructor( if (isInViewTouchTarget(thumbView, eventX, eventY)) { dragStartThumbOffset = thumbOffset } else { - dragStartThumbOffset = (eventY - paddingTop - thumbHeight / 2f).toInt() + dragStartThumbOffset = (eventY - scrollerPadding.top - thumbHeight / 2f).toInt() scrollToThumbOffset(dragStartThumbOffset) } @@ -392,7 +416,7 @@ class FastScrollRecyclerView @JvmOverloads constructor( dragStartThumbOffset = thumbOffset } else { dragStartY = eventY - dragStartThumbOffset = (eventY - paddingTop - thumbHeight / 2f).toInt() + dragStartThumbOffset = (eventY - scrollerPadding.top - thumbHeight / 2f).toInt() scrollToThumbOffset(dragStartThumbOffset) } setDragging(true) @@ -577,7 +601,7 @@ class FastScrollRecyclerView @JvmOverloads constructor( private val thumbOffsetRange: Int get() { - return height - paddingTop - paddingBottom - thumbHeight + return height - scrollerPadding.top - scrollerPadding.bottom - thumbHeight } private val itemCount: Int diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/HomeListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/HomeListFragment.kt index 6d252fb3e..0bd5de2ad 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/HomeListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/HomeListFragment.kt @@ -31,7 +31,6 @@ import org.oxycblt.auxio.home.HomeViewModel import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.memberBinding -import org.oxycblt.auxio.util.applyEdgeRespectingBar import org.oxycblt.auxio.util.applySpans /** @@ -67,7 +66,6 @@ abstract class HomeListFragment : Fragment() { adapter = homeAdapter setHasFixedSize(true) applySpans() - applyEdgeRespectingBar(playbackModel, viewLifecycleOwner) } // Make sure that this RecyclerView has data before startup diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarLayout.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarLayout.kt new file mode 100644 index 000000000..03d5c5df9 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarLayout.kt @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021 Auxio Project + * PlaybackBarLayout.kt is part of Auxio. + * + * 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.playback + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Insets +import android.os.Build +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.view.WindowInsets +import android.widget.FrameLayout +import androidx.annotation.AttrRes +import androidx.annotation.StyleRes +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.children +import androidx.core.view.isVisible +import androidx.core.view.updatePadding +import com.google.android.material.shape.MaterialShapeDrawable +import org.oxycblt.auxio.R +import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.resolveAttr +import org.oxycblt.auxio.util.systemBarsCompat + +/** + * A layout that manages the bottom playback bar while still enabling edge-to-edge to work + * properly. The mechanism is mostly inspired by Material Files' PersistentBarLayout, however + * this class was primarily written by me and I plan to expand this layout to become part of + * the playback navigation process. + */ +class PlaybackBarLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + @AttrRes defStyleAttr: Int = 0, + @StyleRes defStyleRes: Int = 0 +) : ViewGroup(context, attrs, defStyleAttr, defStyleRes) { + private val barLayout = FrameLayout(context) + private val playbackFragment = CompactPlaybackFragment() + private var lastInsets: WindowInsets? = null + + init { + addView(barLayout) + + barLayout.apply { + id = R.id.main_playback + + elevation = resources.getDimensionPixelSize(R.dimen.elevation_normal).toFloat() + + (layoutParams as LayoutParams).apply { + width = ViewGroup.LayoutParams.MATCH_PARENT + height = ViewGroup.LayoutParams.WRAP_CONTENT + isBar = true + } + + background = MaterialShapeDrawable.createWithElevationOverlay(context).apply { + elevation = barLayout.elevation + fillColor = ColorStateList.valueOf(R.attr.colorSurface.resolveAttr(context)) + } + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + if (isInEditMode) { + return + } + + // By default, using a FragmentContainerView in this view will result in + // the fragment disappearing on a recreate. Who knows why. + (context as AppCompatActivity).supportFragmentManager.apply { + this + .beginTransaction() + .replace(R.id.main_playback, playbackFragment) + .commit() + } + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + + val widthSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSize = MeasureSpec.getSize(heightMeasureSpec) + + setMeasuredDimension(widthSize, heightSize) + + val barParams = barLayout.layoutParams as LayoutParams + + val barWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, barParams.width) + val barHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, barParams.height) + barLayout.measure(barWidthSpec, barHeightSpec) + + val barHeightAdjusted = (barLayout.measuredHeight * barParams.offset).toInt() + + val contentWidth = measuredWidth + val contentHeight = measuredHeight - barHeightAdjusted + + for (child in children) { + if (child.visibility == View.GONE) continue + + val childParams = child.layoutParams as LayoutParams + + if (!childParams.isBar) { + val childWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY) + val childHeightSpec = MeasureSpec.makeMeasureSpec(contentHeight, MeasureSpec.EXACTLY) + + child.measure(childWidthSpec, childHeightSpec) + } + } + + updateWindowInsets() + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + val barHeight = if (barLayout.isVisible) { + barLayout.measuredHeight + } else { + 0 + } + + val barHeightAdjusted = (barHeight * (barLayout.layoutParams as LayoutParams).offset).toInt() + + for (child in children) { + if (child.visibility == View.GONE) continue + + val childParams = child.layoutParams as LayoutParams + + if (childParams.isBar) { + child.layout( + 0, height - barHeightAdjusted, + width, height + (barHeight - barHeightAdjusted) + ) + } else { + child.layout(0, 0, child.measuredWidth, child.measuredHeight) + } + } + } + + override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets { + lastInsets = insets + + barLayout.updatePadding(bottom = insets.systemBarsCompat.bottom) + updateWindowInsets() + + return insets + } + + private fun updateWindowInsets() { + val insets = lastInsets + + if (insets != null) { + super.dispatchApplyWindowInsets(mutateInsets(insets)) + } + } + + private fun mutateInsets(insets: WindowInsets): WindowInsets { + if (barLayout.isVisible) { + val barParams = barLayout.layoutParams as LayoutParams + val childConsumedInset = (barLayout.measuredHeight * barParams.offset).toInt() + + logD(childConsumedInset) + + val bars = insets.systemBarsCompat + + // TODO: Q support + when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + return WindowInsets.Builder(insets) + .setInsets( + WindowInsets.Type.systemBars(), + Insets.of( + bars.left, bars.top, + bars.right, (bars.bottom - childConsumedInset).coerceAtLeast(0) + ) + ) + .build() + } + } + } + + return insets + } + + fun showBar() { + (barLayout.layoutParams as LayoutParams).offset = 1f + updateWindowInsets() + } + + fun hideBar() { + (barLayout.layoutParams as LayoutParams).offset = 0f + updateWindowInsets() + } + + // --- LAYOUT PARAMS --- + + override fun generateLayoutParams(attrs: AttributeSet): ViewGroup.LayoutParams { + return LayoutParams(context, attrs) + } + + override fun generateLayoutParams( + layoutParams: ViewGroup.LayoutParams + ): ViewGroup.LayoutParams = + when (layoutParams) { + is LayoutParams -> LayoutParams(layoutParams) + is MarginLayoutParams -> LayoutParams(layoutParams) + else -> LayoutParams(layoutParams) + } + + override fun generateDefaultLayoutParams(): ViewGroup.LayoutParams = + LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + + override fun checkLayoutParams(layoutParams: ViewGroup.LayoutParams): Boolean = + layoutParams is LayoutParams && super.checkLayoutParams(layoutParams) + + @Suppress("UNUSED") + class LayoutParams : ViewGroup.LayoutParams { + var isBar = false + var offset = 0f + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + constructor(width: Int, height: Int) : super(width, height) + + constructor(source: LayoutParams) : super(source) + + constructor(source: ViewGroup.LayoutParams) : super(source) + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt index 3c2f6acb1..d0d2696ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt @@ -32,8 +32,8 @@ import org.oxycblt.auxio.databinding.FragmentPlaybackBinding import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.playback.state.LoopMode import org.oxycblt.auxio.ui.memberBinding -import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.systemBarsCompat /** * A [Fragment] that displays more information about the song, along with more media controls. @@ -60,11 +60,15 @@ class PlaybackFragment : Fragment() { binding.playbackModel = playbackModel binding.detailModel = detailModel - binding.applyEdge { bars -> + binding.root.setOnApplyWindowInsetsListener { v, insets -> + val bars = insets.systemBarsCompat + binding.root.updatePadding( top = bars.top, bottom = bars.bottom ) + + insets } binding.playbackToolbar.apply { 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 4c1b46531..e7d1fd40d 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 @@ -22,14 +22,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.ItemTouchHelper import org.oxycblt.auxio.databinding.FragmentQueueBinding import org.oxycblt.auxio.playback.PlaybackViewModel -import org.oxycblt.auxio.util.applyEdge /** * A [Fragment] that contains both the user queue and the next queue, with the ability to @@ -58,11 +56,6 @@ class QueueFragment : Fragment() { binding.lifecycleOwner = viewLifecycleOwner - binding.applyEdge { bars -> - binding.queueAppbar.updatePadding(top = bars.top) - binding.queueRecycler.updatePadding(bottom = bars.bottom) - } - binding.queueToolbar.setNavigationOnClickListener { findNavController().navigateUp() } diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt index c9ab03b15..3bba4cab0 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -24,7 +24,6 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import androidx.core.view.postDelayed -import androidx.core.view.updatePadding import androidx.core.widget.addTextChangedListener import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -42,8 +41,6 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.newMenu -import org.oxycblt.auxio.util.applyEdge -import org.oxycblt.auxio.util.applyEdgeRespectingBar import org.oxycblt.auxio.util.applySpans import org.oxycblt.auxio.util.getSystemServiceSafe import org.oxycblt.auxio.util.logD @@ -77,10 +74,6 @@ class SearchFragment : Fragment() { binding.lifecycleOwner = viewLifecycleOwner - binding.applyEdge { bars -> - binding.searchAppbar.updatePadding(top = bars.top) - } - binding.searchToolbar.apply { val itemId = when (searchModel.filterMode) { DisplayMode.SHOW_SONGS -> R.id.option_filter_songs @@ -128,8 +121,6 @@ class SearchFragment : Fragment() { applySpans { pos -> searchAdapter.currentList[pos] is Header } - - applyEdgeRespectingBar(playbackModel, viewLifecycleOwner) } // --- VIEWMODEL SETUP --- diff --git a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt index d6ad557d0..a1223473f 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt @@ -36,9 +36,9 @@ import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentAboutBinding import org.oxycblt.auxio.home.HomeViewModel -import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.showToast +import org.oxycblt.auxio.util.systemBarsCompat /** * A [BottomSheetDialogFragment] that shows Auxio's about screen. @@ -54,9 +54,9 @@ class AboutFragment : Fragment() { ): View { val binding = FragmentAboutBinding.inflate(layoutInflater) - binding.applyEdge { bars -> - binding.aboutAppbar.updatePadding(top = bars.top) - binding.aboutContents.updatePadding(bottom = bars.bottom) + binding.aboutContents.setOnApplyWindowInsetsListener { v, insets -> + binding.aboutContents.updatePadding(bottom = insets.systemBarsCompat.bottom) + insets } binding.aboutToolbar.setNavigationOnClickListener { diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt index 6566a1b38..4b0ef7dfc 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt @@ -22,11 +22,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.databinding.FragmentSettingsBinding -import org.oxycblt.auxio.util.applyEdge /** * A container [Fragment] for the settings menu. @@ -46,13 +44,6 @@ class SettingsFragment : Fragment() { } } - binding.applyEdge { bars -> - binding.settingsAppbar.updatePadding(top = bars.top) - - // The padding + clipToPadding method does not work with a - // FragmentContainerView. Do it directly in SettingsListFragment instead. - } - binding.settingsAppbar.liftOnScrollTargetViewId = androidx.preference.R.id.recycler_view return binding.root diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt index 709145287..3c1574da5 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -39,10 +39,10 @@ import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.settings.pref.IntListPrefDialog import org.oxycblt.auxio.settings.pref.IntListPreference import org.oxycblt.auxio.settings.tabs.TabCustomizeDialog -import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.showToast +import org.oxycblt.auxio.util.systemBarsCompat /** * The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat]. @@ -65,8 +65,10 @@ class SettingsListFragment : PreferenceFragmentCompat() { view.findViewById(androidx.preference.R.id.recycler_view).apply { clipToPadding = false - applyEdge { bars -> - updatePadding(bottom = bars.bottom) + setOnApplyWindowInsetsListener { v, insets -> + updatePadding(bottom = insets.systemBarsCompat.bottom) + + insets } } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt new file mode 100644 index 000000000..93d2f9184 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Auxio Project + * EdgeRecyclerView.kt is part of Auxio. + * + * 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.WindowInsets +import androidx.core.view.updatePadding +import androidx.recyclerview.widget.RecyclerView +import org.oxycblt.auxio.util.systemBarsCompat + +/** + * A [RecyclerView] that automatically applies insets to itself. + */ +class EdgeRecyclerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = -1 +) : RecyclerView(context, attrs, defStyleAttr) { + override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { + updatePadding(bottom = insets.systemBarsCompat.bottom) + return insets + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/ui/LiftAppBarLayout.kt b/app/src/main/java/org/oxycblt/auxio/ui/LiftAppBarLayout.kt index 327255026..83335e614 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/LiftAppBarLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/LiftAppBarLayout.kt @@ -23,11 +23,14 @@ import android.util.AttributeSet import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver +import android.view.WindowInsets import androidx.annotation.StyleRes import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.res.ResourcesCompat +import androidx.core.view.updatePadding import com.google.android.material.appbar.AppBarLayout import org.oxycblt.auxio.util.logE +import org.oxycblt.auxio.util.systemBarsCompat /** * An [AppBarLayout] that fixes a bug with the default implementation where the lifted state @@ -61,6 +64,20 @@ class LiftAppBarLayout @JvmOverloads constructor( viewTreeObserver.addOnPreDrawListener(onPreDraw) } + override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets { + super.dispatchApplyWindowInsets(insets) + + return onApplyWindowInsets(insets) + } + + override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { + super.onApplyWindowInsets(insets) + + updatePadding(top = insets.systemBarsCompat.top) + + return insets + } + override fun onDetachedFromWindow() { super.onDetachedFromWindow() diff --git a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt index 4e83b44f8..7729585e9 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt @@ -32,14 +32,10 @@ import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat -import androidx.core.view.updatePadding -import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView -import androidx.viewbinding.ViewBinding import com.google.android.material.shape.MaterialShapeDrawable import org.oxycblt.auxio.R -import org.oxycblt.auxio.playback.PlaybackViewModel /** * Apply a [MaterialShapeDrawable] to this view, automatically initializing the elevation overlay @@ -142,84 +138,24 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int { return color.resolveColor(context) } -/** - * Apply edge-to-edge tweaks to the root of a [ViewBinding]. - * @param onApply What to do when the system bar insets are provided - */ -fun ViewBinding.applyEdge(onApply: (Rect) -> Unit) { - root.applyEdge(onApply) -} - -/** - * Apply edge-to-edge tweaks to a [View]. - * @param onApply What to do when the system bar insets are provided - */ -fun View.applyEdge(onApply: (Rect) -> Unit) { - when { +val WindowInsets.systemBarsCompat: Rect get() { + return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { - setOnApplyWindowInsetsListener { _, insets -> - val bars = insets.getInsets(WindowInsets.Type.systemBars()).run { - Rect(left, top, right, bottom) - } - - onApply(bars) - - insets + getInsets(WindowInsets.Type.systemBars()).run { + Rect(left, top, right, bottom) } } Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> { - setOnApplyWindowInsetsListener { _, insets -> - @Suppress("DEPRECATION") - val bars = Rect( - insets.systemWindowInsetLeft, - insets.systemWindowInsetTop, - insets.systemWindowInsetRight, - insets.systemWindowInsetBottom - ) - - onApply(bars) - insets - } + @Suppress("DEPRECATION") + Rect( + systemWindowInsetLeft, + systemWindowInsetTop, + systemWindowInsetRight, + systemWindowInsetBottom + ) } - // Not on a version that supports edge-to-edge [yet], don't do anything - } -} - -/** - * Stopgap measure to make edge-to-edge work on views that also have a playback bar. - * The issue is that while we can apply padding initially, the padding will still be applied - * when the bar is shown, which is very ungood. We mitigate this by just checking the song state - * and removing the padding if there is one, which is a stupidly fragile band-aid but it - * works. - * - * TODO: Dumpster this and replace it with a dedicated layout. Only issue with that is how - * nested our layouts are, which basically forces us to do recursion magic. Hai Zhang's Material - * Files layout may help in this task. - */ -fun View.applyEdgeRespectingBar( - playbackModel: PlaybackViewModel, - viewLifecycleOwner: LifecycleOwner, - initialPadding: Int = 0 -) { - var bottomPadding = 0 - - applyEdge { - bottomPadding = it.bottom - - if (playbackModel.song.value == null) { - updatePadding(bottom = bottomPadding) - } else { - updatePadding(bottom = initialPadding) - } - } - - playbackModel.song.observe(viewLifecycleOwner) { song -> - if (song == null) { - updatePadding(bottom = bottomPadding) - } else { - updatePadding(bottom = initialPadding) - } + else -> Rect(0, 0, 0, 0) } } diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt index d6cfa2e2b..103865a49 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt @@ -41,10 +41,14 @@ private fun createViews( return views } -private fun RemoteViews.applyMeta(context: Context, state: WidgetState) { +private fun RemoteViews.applyMeta(state: WidgetState): RemoteViews { setTextViewText(R.id.widget_song, state.song.name) setTextViewText(R.id.widget_artist, state.song.album.artist.resolvedName) + return this +} + +private fun RemoteViews.applyCover(context: Context, state: WidgetState): RemoteViews { if (state.albumArt != null) { setImageViewBitmap(R.id.widget_cover, state.albumArt) setContentDescription( @@ -54,9 +58,10 @@ private fun RemoteViews.applyMeta(context: Context, state: WidgetState) { setImageViewResource(R.id.widget_cover, R.drawable.ic_song) setContentDescription(R.id.widget_cover, context.getString(R.string.desc_no_cover)) } -} -private fun RemoteViews.applyControls(context: Context, state: WidgetState) { + return this +} +private fun RemoteViews.applyControls(context: Context, state: WidgetState): RemoteViews { setOnClickPendingIntent( R.id.widget_skip_prev, context.newBroadcastIntent( @@ -86,53 +91,21 @@ private fun RemoteViews.applyControls(context: Context, state: WidgetState) { R.drawable.ic_play } ) + + return this } -fun createDefaultWidget(context: Context): RemoteViews { - return createViews(context, R.layout.widget_default) -} +private fun RemoteViews.applyFullControls(context: Context, state: WidgetState): RemoteViews { + applyControls(context, state) -fun createTinyWidget(context: Context, state: WidgetState): RemoteViews { - val views = createViews(context, R.layout.widget_tiny) - views.applyMeta(context, state) - views.applyControls(context, state) - return views -} - -fun createWideWidget(context: Context, state: WidgetState): RemoteViews { - val views = createViews(context, R.layout.widget_wide) - views.applyMeta(context, state) - views.applyControls(context, state) - return views -} - -fun createSmallWidget(context: Context, state: WidgetState): RemoteViews { - val views = createViews(context, R.layout.widget_small) - views.applyMeta(context, state) - views.applyControls(context, state) - return views -} - -fun createMediumWidget(context: Context, state: WidgetState): RemoteViews { - val views = createViews(context, R.layout.widget_medium) - views.applyMeta(context, state) - views.applyControls(context, state) - return views -} - -fun createLargeWidget(context: Context, state: WidgetState): RemoteViews { - val views = createViews(context, R.layout.widget_large) - views.applyMeta(context, state) - views.applyControls(context, state) - - views.setOnClickPendingIntent( + setOnClickPendingIntent( R.id.widget_loop, context.newBroadcastIntent( PlaybackService.ACTION_LOOP ) ) - views.setOnClickPendingIntent( + setOnClickPendingIntent( R.id.widget_shuffle, context.newBroadcastIntent( PlaybackService.ACTION_SHUFFLE @@ -154,8 +127,46 @@ fun createLargeWidget(context: Context, state: WidgetState): RemoteViews { LoopMode.TRACK -> R.drawable.ic_loop_one } - views.setImageViewResource(R.id.widget_shuffle, shuffleRes) - views.setImageViewResource(R.id.widget_loop, loopRes) + setImageViewResource(R.id.widget_shuffle, shuffleRes) + setImageViewResource(R.id.widget_loop, loopRes) - return views + return this +} + +fun createDefaultWidget(context: Context): RemoteViews { + return createViews(context, R.layout.widget_default) +} + +fun createTinyWidget(context: Context, state: WidgetState): RemoteViews { + return createViews(context, R.layout.widget_tiny) + .applyMeta(state) + .applyCover(context, state) + .applyControls(context, state) +} + +fun createWideWidget(context: Context, state: WidgetState): RemoteViews { + return createViews(context, R.layout.widget_wide) + .applyMeta(state) + .applyCover(context, state) + .applyFullControls(context, state) +} + +fun createSmallWidget(context: Context, state: WidgetState): RemoteViews { + return createViews(context, R.layout.widget_small) + .applyMeta(state) + .applyControls(context, state) +} + +fun createMediumWidget(context: Context, state: WidgetState): RemoteViews { + return createViews(context, R.layout.widget_medium) + .applyMeta(state) + .applyCover(context, state) + .applyControls(context, state) +} + +fun createLargeWidget(context: Context, state: WidgetState): RemoteViews { + return createViews(context, R.layout.widget_large) + .applyMeta(state) + .applyCover(context, state) + .applyFullControls(context, state) } diff --git a/app/src/main/res/layout-land/item_detail.xml b/app/src/main/res/layout-land/item_detail.xml index b12f7489c..ef06b8166 100644 --- a/app/src/main/res/layout-land/item_detail.xml +++ b/app/src/main/res/layout-land/item_detail.xml @@ -28,7 +28,6 @@ android:ellipsize="end" android:layout_height="wrap_content" android:layout_marginStart="@dimen/spacing_medium" - android:layout_marginEnd="@dimen/spacing_medium" app:layout_constraintBottom_toTopOf="@+id/detail_subhead" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 5a0f4035c..a5839eb56 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -10,7 +10,7 @@ android:background="?attr/colorSurface" android:orientation="vertical"> - - + - - + android:layout_height="match_parent"> - + - + - + - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index d2b07f82d..52fbed9d8 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -47,16 +47,23 @@ app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" tools:layout="@layout/fragment_home_list" /> - + app:layout_anchorGravity="bottom|end"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home_list.xml b/app/src/main/res/layout/fragment_home_list.xml index d58e02755..ec69a5dd2 100644 --- a/app/src/main/res/layout/fragment_home_list.xml +++ b/app/src/main/res/layout/fragment_home_list.xml @@ -8,6 +8,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" + android:paddingBottom="88dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" tools:listitem="@layout/item_artist" /> diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 3c76cb158..2a87f271f 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -4,8 +4,8 @@ xmlns:tools="http://schemas.android.com/tools" tools:context=".MainFragment"> - - - - - \ No newline at end of file + + diff --git a/app/src/main/res/layout/fragment_queue.xml b/app/src/main/res/layout/fragment_queue.xml index 13394d1a5..2a4271793 100644 --- a/app/src/main/res/layout/fragment_queue.xml +++ b/app/src/main/res/layout/fragment_queue.xml @@ -29,7 +29,7 @@ - - + diff --git a/app/src/main/res/values-night-v31/styles_core.xml b/app/src/main/res/values-night-v31/styles_core.xml index 9fda29495..b25502acd 100644 --- a/app/src/main/res/values-night-v31/styles_core.xml +++ b/app/src/main/res/values-night-v31/styles_core.xml @@ -60,7 +60,7 @@ @android:color/system_accent2_800 ?android:attr/colorAccent ?android:attr/colorAccent - @color/m3_sys_color_dynamic_dark_inverse_surface + ?android:attr/colorControlNormal ?android:attr/colorControlHighlight \ No newline at end of file diff --git a/app/src/main/res/values-v31/styles_core.xml b/app/src/main/res/values-v31/styles_core.xml index f579255c0..b66de3181 100644 --- a/app/src/main/res/values-v31/styles_core.xml +++ b/app/src/main/res/values-v31/styles_core.xml @@ -60,7 +60,7 @@ @android:color/system_accent1_50 ?android:attr/colorAccent ?android:attr/colorAccent - @color/m3_sys_color_dynamic_light_inverse_surface + ?android:attr/colorControlNormal ?android:attr/colorControlHighlight \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 21bbd907d..7e92b50ea 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -4,4 +4,9 @@ + + + + + \ No newline at end of file