Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit e3330f89 authored by Wolf-Martell Montwé's avatar Wolf-Martell Montwé
Browse files

Change MessageListSwipeCallback for Material 3

This changes the implementation to use ColorRoles
parent 011dcbb1
Loading
Loading
Loading
Loading
+59 −21
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.View.MeasureSpec
@@ -15,12 +16,29 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import app.k9mail.ui.utils.itemtouchhelper.ItemTouchHelper
import com.fsck.k9.SwipeAction
import com.fsck.k9.ui.R
import com.google.android.material.color.ColorRoles
import kotlin.math.abs

private data class SwipeActionConfig(
    private val colorRoles: ColorRoles,
    val icon: Drawable,
    val iconToggled: Drawable? = null,
    val actionName: String,
    val actionNameToggled: String? = null,
) {
    fun getForegroundColor(isReversed: Boolean): Int {
        return if (isReversed) colorRoles.onAccent else colorRoles.accent
    }

    fun getBackgroundColor(isReversed: Boolean): Int {
        return if (isReversed) colorRoles.accent else colorRoles.onAccent
    }
}

@SuppressLint("InflateParams")
class MessageListSwipeCallback(
    context: Context,
    private val resourceProvider: SwipeResourceProvider,
    resourceProvider: SwipeResourceProvider,
    private val swipeActionSupportProvider: SwipeActionSupportProvider,
    private val swipeRightAction: SwipeAction,
    private val swipeLeftAction: SwipeAction,
@@ -37,6 +55,8 @@ class MessageListSwipeCallback(
    private val swipeLeftLayout: View
    private val swipeLeftIcon: ImageView
    private val swipeLeftText: TextView
    private val swipeRightConfig: SwipeActionConfig
    private val swipeLeftConfig: SwipeActionConfig

    private var maxSwipeRightDistance: Int = -1
    private var maxSwipeLeftDistance: Int = -1
@@ -52,6 +72,9 @@ class MessageListSwipeCallback(

        swipeLeftIcon = swipeLeftLayout.findViewById(R.id.swipe_action_icon)
        swipeLeftText = swipeLeftLayout.findViewById(R.id.swipe_action_text)

        swipeRightConfig = setupSwipeAction(swipeRightAction, resourceProvider)
        swipeLeftConfig = setupSwipeAction(swipeLeftAction, resourceProvider)
    }

    override fun isFlingEnabled(): Boolean {
@@ -152,7 +175,8 @@ class MessageListSwipeCallback(
            canvas.withTranslation(x = view.left.toFloat(), y = view.top.toFloat()) {
                if (isCurrentlyActive || !success) {
                    val holder = viewHolder as MessageViewHolder
                    drawLayout(dX, viewWidth, viewHeight, holder)
                    val item = adapter.getItemById(holder.uniqueId) ?: return@withTranslation
                    drawLayout(dX, viewWidth, viewHeight, item)
                } else {
                    drawBackground(dX, viewWidth, viewHeight)
                }
@@ -163,10 +187,9 @@ class MessageListSwipeCallback(
    }

    private fun Canvas.drawBackground(dX: Float, width: Int, height: Int) {
        val swipeAction = if (dX > 0) swipeRightAction else swipeLeftAction
        val backgroundColor = resourceProvider.getBackgroundColor(swipeAction)
        val swipeActionConfig = if (dX > 0) swipeRightConfig else swipeLeftConfig

        backgroundColorPaint.color = backgroundColor
        backgroundColorPaint.color = swipeActionConfig.getBackgroundColor(false)
        drawRect(
            0F,
            0F,
@@ -176,36 +199,35 @@ class MessageListSwipeCallback(
        )
    }

    private fun Canvas.drawLayout(dX: Float, width: Int, height: Int, viewHolder: MessageViewHolder) {
        val item = adapter.getItemById(viewHolder.uniqueId) ?: return
        val isSelected = adapter.isSelected(item)

    private fun Canvas.drawLayout(dX: Float, width: Int, height: Int, item: MessageListItem) {
        val swipeRight = dX > 0
        val swipeThresholdReached = abs(dX) > swipeThreshold

        val swipeLayout = if (swipeRight) swipeRightLayout else swipeLeftLayout
        val swipeAction = if (swipeRight) swipeRightAction else swipeLeftAction
        val swipeActionConfig = if (swipeRight) swipeRightConfig else swipeLeftConfig
        val swipeIcon = if (swipeRight) swipeRightIcon else swipeLeftIcon
        val swipeText = if (swipeRight) swipeRightText else swipeLeftText

        val foregroundColor: Int
        val backgroundColor: Int
        if (swipeThresholdReached) {
            foregroundColor = resourceProvider.iconTint
            backgroundColor = resourceProvider.getBackgroundColor(swipeAction)
        } else {
            foregroundColor = resourceProvider.getBackgroundColor(swipeAction)
            backgroundColor = resourceProvider.getBackgroundColor(SwipeAction.None)
        }
        val foregroundColor = swipeActionConfig.getForegroundColor(swipeThresholdReached)

        swipeLayout.setBackgroundColor(backgroundColor)
        swipeLayout.setBackgroundColor(swipeActionConfig.getBackgroundColor(swipeThresholdReached))

        val icon = resourceProvider.getIcon(item, swipeAction)
        val icon = if (isToggable(swipeAction, item)) {
            swipeActionConfig.iconToggled ?: error("action has no toggled icon")
        } else {
            swipeActionConfig.icon
        }
        icon.setTint(foregroundColor)

        swipeIcon.setImageDrawable(icon)

        swipeText.text = resourceProvider.getActionName(item, swipeAction, isSelected)
        val isSelected = adapter.isSelected(item)
        swipeText.text = if (isToggable(swipeAction, item) || isSelected) {
            swipeActionConfig.actionNameToggled ?: error("action has no toggled name")
        } else {
            swipeActionConfig.actionName
        }
        swipeText.setTextColor(foregroundColor)

        if (swipeLayout.isDirty) {
@@ -250,6 +272,22 @@ class MessageListSwipeCallback(
        return (super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy) * percentage).toLong()
    }

    private fun setupSwipeAction(swipeAction: SwipeAction, resourceProvider: SwipeResourceProvider) = SwipeActionConfig(
        colorRoles = resourceProvider.getActionColorRoles(swipeAction),
        icon = resourceProvider.getActionIcon(swipeAction),
        iconToggled = resourceProvider.getActionIconToggled(swipeAction),
        actionName = resourceProvider.getActionName(swipeAction),
        actionNameToggled = resourceProvider.getActionNameToggled(swipeAction),
    )

    private fun isToggable(swipeAction: SwipeAction, item: MessageListItem): Boolean {
        return when (swipeAction) {
            SwipeAction.ToggleRead -> item.isRead
            SwipeAction.ToggleStar -> item.isStarred
            else -> false
        }
    }

    private val ViewHolder.messageListItem: MessageListItem?
        get() = (this as? MessageViewHolder)?.uniqueId?.let { adapter.getItemById(it) }
}
+37 −36
Original line number Diff line number Diff line
@@ -10,28 +10,18 @@ import androidx.core.content.res.ResourcesCompat
import app.k9mail.core.ui.legacy.designsystem.atom.icon.Icons
import com.fsck.k9.SwipeAction
import com.fsck.k9.ui.R
import com.google.android.material.color.ColorRoles
import com.google.android.material.color.MaterialColors

class SwipeResourceProvider(private val context: Context) {

    val iconTint = context.resolveColorAttribute(R.attr.messageListSwipeIconTint)

    fun getIcon(item: MessageListItem, action: SwipeAction): Drawable {
    fun getActionIcon(action: SwipeAction): Drawable {
        return context.loadDrawable(
            when (action) {
                SwipeAction.None -> error("action == SwipeAction.None")
                SwipeAction.ToggleSelection -> Icons.Outlined.CheckCircle
                SwipeAction.ToggleRead -> if (item.isRead) {
                    Icons.Outlined.MarkEmailUnread
                } else {
                    Icons.Outlined.MarkEmailRead
                }

                SwipeAction.ToggleStar -> if (item.isStarred) {
                    Icons.Outlined.Star
                } else {
                    Icons.Filled.Star
                }

                SwipeAction.ToggleRead -> Icons.Outlined.MarkEmailRead
                SwipeAction.ToggleStar -> Icons.Filled.Star
                SwipeAction.Archive -> Icons.Outlined.Archive
                SwipeAction.Delete -> Icons.Outlined.Delete
                SwipeAction.Spam -> Icons.Outlined.Report
@@ -40,11 +30,26 @@ class SwipeResourceProvider(private val context: Context) {
        )
    }

    fun getActionIconToggled(action: SwipeAction): Drawable? {
        return when (action) {
            SwipeAction.None -> error("action == SwipeAction.None")
            SwipeAction.ToggleRead -> context.loadDrawable(Icons.Outlined.MarkEmailUnread)
            SwipeAction.ToggleStar -> context.loadDrawable(Icons.Outlined.Star)

            else -> null
        }
    }

    fun getActionColorRoles(action: SwipeAction): ColorRoles {
        val harmonizedColor = MaterialColors.harmonizeWithPrimary(context, getActionColor(action))
        return MaterialColors.getColorRoles(context, harmonizedColor)
    }

    @ColorInt
    fun getBackgroundColor(action: SwipeAction): Int {
    private fun getActionColor(action: SwipeAction): Int {
        return context.resolveColorAttribute(
            when (action) {
                SwipeAction.None -> R.attr.messageListSwipeDisabledBackgroundColor
                SwipeAction.None -> error("action == SwipeAction.None")
                SwipeAction.ToggleSelection -> R.attr.messageListSwipeSelectBackgroundColor
                SwipeAction.ToggleRead -> R.attr.messageListSwipeToggleReadBackgroundColor
                SwipeAction.ToggleStar -> R.attr.messageListSwipeToggleStarBackgroundColor
@@ -56,28 +61,13 @@ class SwipeResourceProvider(private val context: Context) {
        )
    }

    fun getActionName(item: MessageListItem, action: SwipeAction, isSelected: Boolean): String {
    fun getActionName(action: SwipeAction): String {
        return context.loadString(
            when (action) {
                SwipeAction.None -> error("action == SwipeAction.None")
                SwipeAction.ToggleSelection -> if (isSelected) {
                    R.string.swipe_action_deselect
                } else {
                    R.string.swipe_action_select
                }

                SwipeAction.ToggleRead -> if (item.isRead) {
                    R.string.swipe_action_mark_as_unread
                } else {
                    R.string.swipe_action_mark_as_read
                }

                SwipeAction.ToggleStar -> if (item.isStarred) {
                    R.string.swipe_action_remove_star
                } else {
                    R.string.swipe_action_add_star
                }

                SwipeAction.ToggleSelection -> R.string.swipe_action_select
                SwipeAction.ToggleRead -> R.string.swipe_action_mark_as_read
                SwipeAction.ToggleStar -> R.string.swipe_action_add_star
                SwipeAction.Archive -> R.string.swipe_action_archive
                SwipeAction.Delete -> R.string.swipe_action_delete
                SwipeAction.Spam -> R.string.swipe_action_spam
@@ -85,6 +75,17 @@ class SwipeResourceProvider(private val context: Context) {
            },
        )
    }

    fun getActionNameToggled(action: SwipeAction): String? {
        return when (action) {
            SwipeAction.None -> error("action == SwipeAction.None")
            SwipeAction.ToggleSelection -> context.loadString(R.string.swipe_action_deselect)
            SwipeAction.ToggleRead -> context.loadString(R.string.swipe_action_mark_as_unread)
            SwipeAction.ToggleStar -> context.loadString(R.string.swipe_action_remove_star)

            else -> null
        }
    }
}

private fun Context.loadDrawable(@DrawableRes drawableResId: Int): Drawable {
+1 −3
Original line number Diff line number Diff line
@@ -21,8 +21,7 @@
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:src="@drawable/ic_mark_email_unread"
        tools:tint="?attr/messageListSwipeIconTint" />
        tools:src="@drawable/ic_mark_email_unread" />

    <TextView
        android:id="@+id/swipe_action_text"
@@ -36,7 +35,6 @@
        android:gravity="right"
        android:maxLines="1"
        android:textAppearance="?attr/textAppearanceBody2"
        android:textColor="?attr/messageListSwipeIconTint"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
+1 −3
Original line number Diff line number Diff line
@@ -21,8 +21,7 @@
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:src="@drawable/ic_check"
        tools:tint="?attr/messageListSwipeIconTint" />
        tools:src="@drawable/ic_check" />

    <TextView
        android:id="@+id/swipe_action_text"
@@ -36,7 +35,6 @@
        android:gravity="left"
        android:maxLines="1"
        android:textAppearance="?attr/textAppearanceBody2"
        android:textColor="?attr/messageListSwipeIconTint"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
+0 −2
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@
        <attr name="messageListReadTextColor" format="reference|color"/>
        <attr name="messageListPreviewTextColor" format="reference|color"/>
        <attr name="messageListDividerColor" format="reference|color"/>
        <attr name="messageListSwipeIconTint" format="reference|color"/>
        <attr name="messageListSwipeDisabledBackgroundColor" format="reference|color"/>
        <attr name="messageListSwipeSelectBackgroundColor" format="reference|color"/>
        <attr name="messageListSwipeToggleReadBackgroundColor" format="reference|color"/>
        <attr name="messageListSwipeToggleStarBackgroundColor" format="reference|color"/>
Loading