image: use shapeappearance in coverview
This commit is contained in:
parent
6c640909f7
commit
fc90d460dc
7 changed files with 52 additions and 49 deletions
|
@ -33,9 +33,8 @@ import android.view.Gravity
|
|||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.res.getIntOrThrow
|
||||
import androidx.annotation.Px
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.updateMarginsRelative
|
||||
|
@ -45,6 +44,7 @@ import coil.request.ImageRequest
|
|||
import coil.util.CoilUtils
|
||||
import com.google.android.material.R as MR
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.google.android.material.shape.ShapeAppearanceModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.R
|
||||
|
@ -58,7 +58,6 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.ui.UISettings
|
||||
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||
import org.oxycblt.auxio.util.getColorCompat
|
||||
import org.oxycblt.auxio.util.getDimen
|
||||
import org.oxycblt.auxio.util.getDimenPixels
|
||||
import org.oxycblt.auxio.util.getDrawableCompat
|
||||
import org.oxycblt.auxio.util.getInteger
|
||||
|
@ -91,16 +90,15 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
|
||||
private val playbackIndicator: PlaybackIndicator?
|
||||
private val selectionBadge: ImageView?
|
||||
|
||||
private val sizing: Int
|
||||
@DimenRes private val iconSizeRes: Int?
|
||||
@DimenRes private var cornerRadiusRes: Int?
|
||||
private val iconSize: Int?
|
||||
|
||||
private var fadeAnimator: ValueAnimator? = null
|
||||
private val indicatorMatrix = Matrix()
|
||||
private val indicatorMatrixSrc = RectF()
|
||||
private val indicatorMatrixDst = RectF()
|
||||
|
||||
private val shapeAppearance: ShapeAppearanceModel
|
||||
|
||||
private data class Cover(
|
||||
val songs: Collection<Song>,
|
||||
val desc: String,
|
||||
|
@ -114,9 +112,21 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
@SuppressLint("CustomViewStyleable")
|
||||
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.CoverView)
|
||||
|
||||
sizing = styledAttrs.getIntOrThrow(R.styleable.CoverView_sizing)
|
||||
iconSizeRes = SIZING_ICON_SIZE[sizing]
|
||||
cornerRadiusRes = getCornerRadiusRes()
|
||||
val shapeAppearanceRes = styledAttrs.getResourceId(R.styleable.CoverView_shapeAppearance, 0)
|
||||
shapeAppearance =
|
||||
if (shapeAppearanceRes != 0) {
|
||||
ShapeAppearanceModel.builder(context, shapeAppearanceRes, -1).build()
|
||||
} else {
|
||||
ShapeAppearanceModel.builder(
|
||||
context,
|
||||
com.google.android.material.R.style.ShapeAppearance_Material3_Corner_Medium,
|
||||
-1)
|
||||
.build()
|
||||
}
|
||||
iconSize =
|
||||
styledAttrs.getDimensionPixelSize(R.styleable.CoverView_iconSize, -1).takeIf {
|
||||
it != -1
|
||||
}
|
||||
|
||||
val playbackIndicatorEnabled =
|
||||
styledAttrs.getBoolean(R.styleable.CoverView_enablePlaybackIndicator, true)
|
||||
|
@ -190,7 +200,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
// AnimatedVectorDrawable cannot be placed in a StyledDrawable, we must replicate the
|
||||
// behavior with a matrix.
|
||||
val playbackIndicator = (playbackIndicator ?: return).view
|
||||
val iconSize = iconSizeRes?.let(context::getDimenPixels) ?: (measuredWidth / 2)
|
||||
val iconSize = iconSize ?: (measuredWidth / 2)
|
||||
playbackIndicator.apply {
|
||||
imageMatrix =
|
||||
indicatorMatrix.apply {
|
||||
|
@ -254,14 +264,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
}
|
||||
}
|
||||
|
||||
private fun getCornerRadiusRes() =
|
||||
if (!isInEditMode && uiSettings.roundMode) {
|
||||
SIZING_CORNER_RADII[sizing]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private fun applyBackgroundsToChildren() {
|
||||
|
||||
// Add backgrounds to each child for visual consistency
|
||||
for (child in children) {
|
||||
child.apply {
|
||||
|
@ -271,7 +275,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
background =
|
||||
MaterialShapeDrawable().apply {
|
||||
fillColor = context.getColorCompat(R.color.sel_cover_bg)
|
||||
setCornerSize(cornerRadiusRes?.let(context::getDimen) ?: 0f)
|
||||
shapeAppearanceModel = shapeAppearance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,11 +406,13 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
val request =
|
||||
ImageRequest.Builder(context)
|
||||
.data(songs)
|
||||
.error(StyledDrawable(context, context.getDrawableCompat(errorRes), iconSizeRes))
|
||||
.error(StyledDrawable(context, context.getDrawableCompat(errorRes), iconSize))
|
||||
.target(image)
|
||||
|
||||
val cornersTransformation =
|
||||
RoundedRectTransformation(cornerRadiusRes?.let(context::getDimen) ?: 0f)
|
||||
RoundedRectTransformation(
|
||||
shapeAppearance.topLeftCornerSize.getCornerSize(
|
||||
RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())))
|
||||
if (imageSettings.forceSquareCovers) {
|
||||
request.transformations(SquareCropTransformation.INSTANCE, cornersTransformation)
|
||||
} else {
|
||||
|
@ -427,7 +433,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
private class StyledDrawable(
|
||||
context: Context,
|
||||
private val inner: Drawable,
|
||||
@DimenRes iconSizeRes: Int?
|
||||
@Px val iconSize: Int?
|
||||
) : Drawable() {
|
||||
init {
|
||||
// Re-tint the drawable to use the analogous "on surface" color for
|
||||
|
@ -435,12 +441,10 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
DrawableCompat.setTintList(inner, context.getColorCompat(R.color.sel_on_cover_bg))
|
||||
}
|
||||
|
||||
private val dimen = iconSizeRes?.let(context::getDimenPixels)
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
// Resize the drawable such that it's always 1/4 the size of the image and
|
||||
// centered in the middle of the canvas.
|
||||
val adj = dimen?.let { (bounds.width() - it) / 2 } ?: (bounds.width() / 4)
|
||||
val adj = iconSize?.let { (bounds.width() - it) / 2 } ?: (bounds.width() / 4)
|
||||
inner.bounds.set(adj, adj, bounds.width() - adj, bounds.height() - adj)
|
||||
inner.draw(canvas)
|
||||
}
|
||||
|
@ -457,13 +461,4 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
|
||||
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
||||
}
|
||||
|
||||
companion object {
|
||||
val SIZING_CORNER_RADII =
|
||||
arrayOf(
|
||||
R.dimen.size_corners_small,
|
||||
R.dimen.size_corners_medium,
|
||||
R.dimen.size_corners_mid_large)
|
||||
val SIZING_ICON_SIZE = arrayOf(R.dimen.size_icon_small, R.dimen.size_icon_medium, null)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?attr/colorPrimaryContainer" android:state_selected="true" />
|
||||
<item android:color="?attr/colorOnSurfaceInverse" />
|
||||
<item android:color="?attr/colorSurfaceContainer" />
|
||||
</selector>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?attr/colorOnPrimaryContainer" android:state_selected="true" />
|
||||
<item android:color="?attr/colorSurfaceInverse" />
|
||||
<item android:color="?attr/colorOnSurface" />
|
||||
</selector>
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
<org.oxycblt.auxio.image.CoverView
|
||||
android:id="@+id/menu_cover"
|
||||
style="@style/Widget.Auxio.Image.Full"
|
||||
style="@style/Widget.Auxio.Image.MidFull"
|
||||
android:layout_marginStart="@dimen/spacing_medium"
|
||||
android:layout_marginBottom="@dimen/spacing_medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -11,12 +11,8 @@
|
|||
<integer name="anim_fade_exit_duration">100</integer>
|
||||
|
||||
<declare-styleable name="CoverView">
|
||||
<attr name="cornerRadius" format="dimension" />
|
||||
<attr name="sizing" format="enum">
|
||||
<enum name="small" value="0" />
|
||||
<enum name="medium" value="1" />
|
||||
<enum name="large" value="2" />
|
||||
</attr>
|
||||
<attr name="shapeAppearance" format="reference" />
|
||||
<attr name="iconSize" format="dimension" />
|
||||
<attr name="enablePlaybackIndicator" format="boolean" />
|
||||
<attr name="enableSelectionBadge" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
<dimen name="size_icon_small">24dp</dimen>
|
||||
<dimen name="size_icon_medium">32dp</dimen>
|
||||
<dimen name="size_icon_large">40dp</dimen>
|
||||
<dimen name="size_icon_huge">48dp</dimen>
|
||||
|
||||
<dimen name="size_pre_amp_ticker">56dp</dimen>
|
||||
|
||||
|
|
|
@ -66,38 +66,48 @@
|
|||
<style name="Widget.Auxio.Image.Small" parent="">
|
||||
<item name="android:layout_width">@dimen/size_cover_compact</item>
|
||||
<item name="android:layout_height">@dimen/size_cover_compact</item>
|
||||
<item name="sizing">small</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.Medium</item>
|
||||
<item name="iconSize">@dimen/size_icon_small</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Auxio.Image.Medium" parent="">
|
||||
<item name="android:layout_width">@dimen/size_cover_medium</item>
|
||||
<item name="android:layout_height">@dimen/size_cover_medium</item>
|
||||
<item name="sizing">medium</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.Medium</item>
|
||||
<item name="iconSize">@dimen/size_icon_medium</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="Widget.Auxio.Image.Large" parent="">
|
||||
<item name="android:layout_width">@dimen/size_cover_large</item>
|
||||
<item name="android:layout_height">@dimen/size_cover_large</item>
|
||||
<item name="sizing">large</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.ExtraLarge</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Auxio.Image.MidHuge" parent="">
|
||||
<item name="android:layout_width">@dimen/size_cover_mid_huge</item>
|
||||
<item name="android:layout_height">@dimen/size_cover_mid_huge</item>
|
||||
<item name="sizing">large</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.ExtraLarge</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Auxio.Image.Huge" parent="">
|
||||
<item name="android:layout_width">@dimen/size_cover_huge</item>
|
||||
<item name="android:layout_height">@dimen/size_cover_huge</item>
|
||||
<item name="sizing">large</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.ExtraLarge</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Auxio.Image.MidFull" parent="">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">0dp</item>
|
||||
<item name="layout_constraintDimensionRatio">1</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.Large</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Auxio.Image.Full" parent="">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">0dp</item>
|
||||
<item name="layout_constraintDimensionRatio">1</item>
|
||||
<item name="sizing">large</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.ExtraLarge</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Auxio.RecyclerView.Linear" parent="">
|
||||
|
|
Loading…
Reference in a new issue