From f5ec295b2c7933d27d08c33e2f8fea80c2d275f7 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 5 Dec 2022 04:24:18 +0000 Subject: [PATCH] ui: animate selection Animate the check mark and background change when a item is selected. This produces a nicer UX overall. If possible, I'm planning to also port this to the other indicators in ImageGroup, albeit doing that is signifigantly harder. --- .../org/oxycblt/auxio/image/ImageGroup.kt | 24 ++++++++++++++++++- .../oxycblt/auxio/ui/recycler/ViewHolders.kt | 4 ---- ...ckground.xml => sel_item_activated_bg.xml} | 1 - .../main/res/drawable/sel_item_ripple_bg.xml | 19 +++++++++++++++ app/src/main/res/drawable/ui_item_ripple.xml | 2 +- .../main/res/layout/item_picker_choice.xml | 4 ++-- 6 files changed, 45 insertions(+), 9 deletions(-) rename app/src/main/res/color/{sel_activatable_background.xml => sel_item_activated_bg.xml} (82%) create mode 100644 app/src/main/res/drawable/sel_item_ripple_bg.xml diff --git a/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt b/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt index 299d07972..f92dde359 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/ImageGroup.kt @@ -26,7 +26,9 @@ import android.widget.FrameLayout import android.widget.ImageView import androidx.annotation.AttrRes import androidx.core.view.updateMarginsRelative +import androidx.transition.TransitionManager import com.google.android.material.shape.MaterialShapeDrawable +import com.google.android.material.transition.MaterialFade import org.oxycblt.auxio.R import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist @@ -142,6 +144,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr private fun invalidatePlayingIndicator() { if (isSelected) { + // TODO: Animate the other indicators? customView?.alpha = 0f inner.alpha = 0f playingIndicator.alpha = 1f @@ -153,7 +156,26 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr } private fun invalidateSelectionIndicator() { - selectionIndicator.alpha = if (isActivated) 1f else 0f + val targetVis: Int + val targetDuration: Long + + if (isActivated) { + targetVis = VISIBLE + targetDuration = 150L + } else { + targetVis = INVISIBLE + targetDuration = 84L + } + + if (selectionIndicator.visibility == targetVis) { + return + } + + TransitionManager.beginDelayedTransition(this, MaterialFade().apply { + duration = targetDuration + }) + + selectionIndicator.visibility = targetVis } fun bind(song: Song) { diff --git a/app/src/main/java/org/oxycblt/auxio/ui/recycler/ViewHolders.kt b/app/src/main/java/org/oxycblt/auxio/ui/recycler/ViewHolders.kt index f60bba90d..9808f6713 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/recycler/ViewHolders.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/recycler/ViewHolders.kt @@ -43,7 +43,6 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) : binding.songName.text = item.resolveName(binding.context) binding.songInfo.text = item.resolveArtistContents(binding.context) - binding.songAlbumCover.setOnClickListener { listener.onSelect(item) } binding.songMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.root.apply { setOnClickListener { listener.onItemClick(item) } @@ -88,7 +87,6 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding binding.parentName.text = item.resolveName(binding.context) binding.parentInfo.text = item.resolveArtistContents(binding.context) - binding.parentImage.setOnClickListener { listener.onSelect(item) } binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.root.apply { setOnClickListener { listener.onItemClick(item) } @@ -145,7 +143,6 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin binding.context.getPlural(R.plurals.fmt_album_count, item.albums.size) } - binding.parentImage.setOnClickListener { listener.onSelect(item) } binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.root.apply { setOnClickListener { listener.onItemClick(item) } @@ -196,7 +193,6 @@ class GenreViewHolder private constructor(private val binding: ItemParentBinding binding.context.getPlural(R.plurals.fmt_artist_count, item.artists.size), binding.context.getPlural(R.plurals.fmt_song_count, item.songs.size)) - binding.parentImage.setOnClickListener { listener.onSelect(item) } binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.root.apply { setOnClickListener { listener.onItemClick(item) } diff --git a/app/src/main/res/color/sel_activatable_background.xml b/app/src/main/res/color/sel_item_activated_bg.xml similarity index 82% rename from app/src/main/res/color/sel_activatable_background.xml rename to app/src/main/res/color/sel_item_activated_bg.xml index 76c3633ce..77812254d 100644 --- a/app/src/main/res/color/sel_activatable_background.xml +++ b/app/src/main/res/color/sel_item_activated_bg.xml @@ -1,5 +1,4 @@ - \ No newline at end of file diff --git a/app/src/main/res/drawable/sel_item_ripple_bg.xml b/app/src/main/res/drawable/sel_item_ripple_bg.xml new file mode 100644 index 000000000..152b48a05 --- /dev/null +++ b/app/src/main/res/drawable/sel_item_ripple_bg.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ui_item_ripple.xml b/app/src/main/res/drawable/ui_item_ripple.xml index c1501325f..7b0474254 100644 --- a/app/src/main/res/drawable/ui_item_ripple.xml +++ b/app/src/main/res/drawable/ui_item_ripple.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/item_picker_choice.xml b/app/src/main/res/layout/item_picker_choice.xml index 8c844b7d2..0799ca380 100644 --- a/app/src/main/res/layout/item_picker_choice.xml +++ b/app/src/main/res/layout/item_picker_choice.xml @@ -5,9 +5,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" - android:paddingStart="@dimen/spacing_mid_large" + android:paddingStart="@dimen/spacing_large" android:paddingTop="@dimen/spacing_medium" - android:paddingEnd="@dimen/spacing_mid_large" + android:paddingEnd="@dimen/spacing_large" android:paddingBottom="@dimen/spacing_medium">