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

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

refactor(message-list): move create to view holder

^ Conflicts:
^	legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListAdapter.kt
^	legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/item/MessageListViewHolder.kt
parent 6d65b654
Loading
Loading
Loading
Loading
+9 −109
Original line number Diff line number Diff line
@@ -8,23 +8,16 @@ import android.view.View
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.ViewGroup
import androidx.annotation.DimenRes
import androidx.constraintlayout.widget.Guideline
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
import app.k9mail.legacy.message.controller.MessageReference
import com.fsck.k9.UiDensity
import com.fsck.k9.contacts.ContactPictureLoader
import com.fsck.k9.ui.R
import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
import com.fsck.k9.ui.messagelist.item.FooterViewHolder
import com.fsck.k9.ui.messagelist.item.MessageListViewHolder
import com.fsck.k9.ui.messagelist.item.MessageViewHolder
import com.fsck.k9.ui.messagelist.item.MessageViewHolderColors
import kotlin.math.max

private const val FOOTER_ID = 1L

@@ -41,16 +34,6 @@ class MessageListAdapter internal constructor(
    private val relativeDateTimeFormatter: RelativeDateTimeFormatter,
) : RecyclerView.Adapter<MessageListViewHolder>() {

    private val compactVerticalPadding = res.getDimensionPixelSize(R.dimen.messageListCompactVerticalPadding)
    private val compactTextViewMarginTop = res.getDimensionPixelSize(R.dimen.messageListCompactTextViewMargin)
    private val compactLineSpacingMultiplier = res.getFloatCompat(R.dimen.messageListCompactLineSpacingMultiplier)
    private val defaultVerticalPadding = res.getDimensionPixelSize(R.dimen.messageListDefaultVerticalPadding)
    private val defaultTextViewMarginTop = res.getDimensionPixelSize(R.dimen.messageListDefaultTextViewMargin)
    private val defaultLineSpacingMultiplier = res.getFloatCompat(R.dimen.messageListDefaultLineSpacingMultiplier)
    private val relaxedVerticalPadding = res.getDimensionPixelSize(R.dimen.messageListRelaxedVerticalPadding)
    private val relaxedTextViewMarginTop = res.getDimensionPixelSize(R.dimen.messageListRelaxedTextViewMargin)
    private val relaxedLineSpacingMultiplier = res.getFloatCompat(R.dimen.messageListRelaxedLineSpacingMultiplier)

    val colors: MessageViewHolderColors = MessageViewHolderColors.resolveColors(theme)

    var messages: List<MessageListItem> = emptyList()
@@ -150,13 +133,6 @@ class MessageListAdapter internal constructor(
    private val footerPosition: Int
        get() = if (hasFooter) lastMessagePosition + 1 else NO_POSITION

    private inline val subjectViewFontSize: Int
        get() = if (appearance.senderAboveSubject) {
            appearance.fontSizes.messageListSender
        } else {
            appearance.fontSizes.messageListSubject
        }

    private val messageClickedListener = OnClickListener { view: View ->
        val messageListItem = getItemFromView(view) ?: return@OnClickListener
        listItemListener.onMessageClicked(messageListItem)
@@ -232,97 +208,27 @@ class MessageListAdapter internal constructor(
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageListViewHolder {
        return when (viewType) {
            TYPE_MESSAGE -> createMessageViewHolder(parent)
            TYPE_FOOTER -> createFooterViewHolder(parent)
            TYPE_FOOTER -> FooterViewHolder.create(layoutInflater, parent, footerClickListener)
            else -> error("Unsupported type: $viewType")
        }
    }

    private fun createMessageViewHolder(parent: ViewGroup?): MessageViewHolder {
        val view = layoutInflater.inflate(R.layout.message_list_item, parent, false)
        view.setOnClickListener(messageClickedListener)
        view.setOnLongClickListener(messageLongClickedListener)

        val holder = MessageViewHolder(
            view = view,
    private fun createMessageViewHolder(parent: ViewGroup?): MessageViewHolder =
        MessageViewHolder.create(
            layoutInflater = layoutInflater,
            parent = parent,
            appearance = appearance,
            res = res,
            contactsPictureLoader = contactsPictureLoader,
            relativeDateTimeFormatter = relativeDateTimeFormatter,
            colors = colors,
            theme = theme,
            onClickListener = messageClickedListener,
            onLongClickListener = messageLongClickedListener,
            contactPictureContainerClickListener = contactPictureContainerClickListener,
            starClickListener = starClickListener,
        )

        val contactPictureClickArea = view.findViewById<View>(R.id.contact_picture_click_area)
        if (appearance.showContactPicture) {
            contactPictureClickArea.setOnClickListener(contactPictureContainerClickListener)
        } else {
            contactPictureClickArea.isVisible = false
            holder.selectedView.isVisible = false
            holder.contactPictureView.isVisible = false
        }

        holder.chipView.isVisible = appearance.showAccountChip

        appearance.fontSizes.setViewTextSize(holder.subjectView, subjectViewFontSize)
        appearance.fontSizes.setViewTextSize(holder.dateView, appearance.fontSizes.messageListDate)

        // 1 preview line is needed even if it is set to 0, because subject is part of the same text view
        holder.previewView.maxLines = max(appearance.previewLines, 1)
        appearance.fontSizes.setViewTextSize(holder.previewView, appearance.fontSizes.messageListPreview)
        appearance.fontSizes.setViewTextSize(
            holder.threadCountView,
            appearance.fontSizes.messageListSubject,
        ) // thread count is next to subject

        holder.starView.isVisible = appearance.stars
        holder.starClickAreaView.isVisible = appearance.stars
        holder.starClickAreaView.setOnClickListener(starClickListener)

        applyDensityValue(holder, appearance.density)

        view.tag = holder

        return holder
    }

    private fun applyDensityValue(holder: MessageViewHolder, density: UiDensity) {
        val verticalPadding: Int
        val textViewMarginTop: Int
        val lineSpacingMultiplier: Float
        when (density) {
            UiDensity.Compact -> {
                verticalPadding = compactVerticalPadding
                textViewMarginTop = compactTextViewMarginTop
                lineSpacingMultiplier = compactLineSpacingMultiplier
            }

            UiDensity.Default -> {
                verticalPadding = defaultVerticalPadding
                textViewMarginTop = defaultTextViewMarginTop
                lineSpacingMultiplier = defaultLineSpacingMultiplier
            }

            UiDensity.Relaxed -> {
                verticalPadding = relaxedVerticalPadding
                textViewMarginTop = relaxedTextViewMarginTop
                lineSpacingMultiplier = relaxedLineSpacingMultiplier
            }
        }

        holder.itemView.findViewById<Guideline>(R.id.top_guideline).setGuidelineBegin(verticalPadding)
        holder.itemView.findViewById<Guideline>(R.id.bottom_guideline).setGuidelineEnd(verticalPadding)
        holder.previewView.apply {
            setMarginTop(textViewMarginTop)
            setLineSpacing(lineSpacingExtra, lineSpacingMultiplier)
        }
    }

    private fun createFooterViewHolder(parent: ViewGroup): MessageListViewHolder {
        val view = layoutInflater.inflate(R.layout.message_list_item_footer, parent, false)
        view.setOnClickListener(footerClickListener)
        return FooterViewHolder(view)
    }

    override fun onBindViewHolder(holder: MessageListViewHolder, position: Int) {
        when (val viewType = getItemViewType(position)) {
            TYPE_MESSAGE -> {
@@ -418,12 +324,6 @@ class MessageListAdapter internal constructor(
    }
}

private fun Resources.getFloatCompat(@DimenRes resId: Int) = ResourcesCompat.getFloat(this, resId)

private fun View.setMarginTop(margin: Int) {
    (layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin = margin
}

private class MessageListDiffCallback(
    private val oldMessageList: List<MessageListItem>,
    private val newMessageList: List<MessageListItem>,
+14 −0
Original line number Diff line number Diff line
package com.fsck.k9.ui.messagelist.item

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.fsck.k9.ui.R
import com.google.android.material.textview.MaterialTextView

@@ -10,4 +12,16 @@ class FooterViewHolder(view: View) : MessageListViewHolder(view) {
    fun bind(listItem: String?) {
        textView.text = listItem
    }

    companion object {
        fun create(
            layoutInflater: LayoutInflater,
            parent: ViewGroup,
            onClickListener: View.OnClickListener,
        ): FooterViewHolder {
            val view = layoutInflater.inflate(R.layout.message_list_item_footer, parent, false)
            view.setOnClickListener(onClickListener)
            return FooterViewHolder(view)
        }
    }
}
+0 −2
Original line number Diff line number Diff line
@@ -2,7 +2,5 @@ package com.fsck.k9.ui.messagelist.item

import android.view.View
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.fsck.k9.ui.messagelist.MessageListItem

sealed class MessageListViewHolder(view: View) : ViewHolder(view)
+116 −0
Original line number Diff line number Diff line
@@ -8,14 +8,19 @@ import android.text.SpannableStringBuilder
import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DimenRes
import androidx.constraintlayout.widget.Guideline
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isVisible
import app.k9mail.core.ui.legacy.designsystem.atom.icon.Icons
import com.fsck.k9.FontSizes
import com.fsck.k9.UiDensity
import com.fsck.k9.contacts.ContactPictureLoader
import com.fsck.k9.mail.Address
import com.fsck.k9.ui.R
@@ -25,6 +30,7 @@ import com.fsck.k9.ui.messagelist.MessageListItem
import com.fsck.k9.ui.messagelist.MlfUtils
import com.google.android.material.textview.MaterialTextView
import java.util.Locale
import kotlin.math.max

class MessageViewHolder(
    view: View,
@@ -248,4 +254,114 @@ class MessageViewHolder(
            null
        }
    }

    companion object {

        @Suppress("LongParameterList")
        fun create(
            layoutInflater: LayoutInflater,
            parent: ViewGroup?,
            appearance: MessageListAppearance,
            theme: Resources.Theme,
            res: Resources,
            contactsPictureLoader: ContactPictureLoader,
            relativeDateTimeFormatter: RelativeDateTimeFormatter,
            colors: MessageViewHolderColors,
            onClickListener: View.OnClickListener,
            onLongClickListener: View.OnLongClickListener,
            contactPictureContainerClickListener: View.OnClickListener,
            starClickListener: View.OnClickListener,
        ): MessageViewHolder {
            val view = layoutInflater.inflate(R.layout.message_list_item, parent, false)
            view.setOnClickListener(onClickListener)
            view.setOnLongClickListener(onLongClickListener)

            val holder = MessageViewHolder(
                view = view,
                appearance = appearance,
                theme = theme,
                res = res,
                contactsPictureLoader = contactsPictureLoader,
                relativeDateTimeFormatter = relativeDateTimeFormatter,
                colors = colors,
            )

            applyFontSizes(holder, appearance.fontSizes, appearance.senderAboveSubject)
            applyDensityValue(holder, appearance.density, res)

            if (appearance.showContactPicture) {
                holder.contactPictureClickArea.setOnClickListener(contactPictureContainerClickListener)
            } else {
                holder.contactPictureClickArea.isVisible = false
                holder.selectedView.isVisible = false
                holder.contactPictureView.isVisible = false
            }

            holder.chipView.isVisible = appearance.showAccountChip

            // 1 preview line is needed even if it is set to 0, because subject is part of the same text view
            holder.previewView.maxLines = max(appearance.previewLines, 1)
            appearance.fontSizes.setViewTextSize(holder.previewView, appearance.fontSizes.messageListPreview)
            appearance.fontSizes.setViewTextSize(
                holder.threadCountView,
                appearance.fontSizes.messageListSubject,
            ) // thread count is next to subject

            holder.starView.isVisible = appearance.stars
            holder.starClickAreaView.isVisible = appearance.stars
            holder.starClickAreaView.setOnClickListener(starClickListener)

            view.tag = holder

            return holder
        }

        private fun applyFontSizes(holder: MessageViewHolder, fontSizes: FontSizes, senderAboveSubject: Boolean) {
            if (senderAboveSubject) {
                fontSizes.setViewTextSize(holder.subjectView, fontSizes.messageListSender)
            } else {
                fontSizes.setViewTextSize(holder.subjectView, fontSizes.messageListSubject)
            }

            fontSizes.setViewTextSize(holder.dateView, fontSizes.messageListDate)
        }

        private fun applyDensityValue(holder: MessageViewHolder, density: UiDensity, res: Resources) {
            val verticalPadding: Int
            val textViewMarginTop: Int
            val lineSpacingMultiplier: Float
            when (density) {
                UiDensity.Compact -> {
                    verticalPadding = res.getDimensionPixelSize(R.dimen.messageListCompactVerticalPadding)
                    textViewMarginTop = res.getDimensionPixelSize(R.dimen.messageListCompactTextViewMargin)
                    lineSpacingMultiplier = res.getFloatCompat(R.dimen.messageListCompactLineSpacingMultiplier)
                }

                UiDensity.Default -> {
                    verticalPadding = res.getDimensionPixelSize(R.dimen.messageListDefaultVerticalPadding)
                    textViewMarginTop = res.getDimensionPixelSize(R.dimen.messageListDefaultTextViewMargin)
                    lineSpacingMultiplier = res.getFloatCompat(R.dimen.messageListDefaultLineSpacingMultiplier)
                }

                UiDensity.Relaxed -> {
                    verticalPadding = res.getDimensionPixelSize(R.dimen.messageListRelaxedVerticalPadding)
                    textViewMarginTop = res.getDimensionPixelSize(R.dimen.messageListRelaxedTextViewMargin)
                    lineSpacingMultiplier = res.getFloatCompat(R.dimen.messageListRelaxedLineSpacingMultiplier)
                }
            }

            holder.itemView.findViewById<Guideline>(R.id.top_guideline).setGuidelineBegin(verticalPadding)
            holder.itemView.findViewById<Guideline>(R.id.bottom_guideline).setGuidelineEnd(verticalPadding)
            holder.previewView.apply {
                setMarginTop(textViewMarginTop)
                setLineSpacing(lineSpacingExtra, lineSpacingMultiplier)
            }
        }

        private fun View.setMarginTop(margin: Int) {
            (layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin = margin
        }

        private fun Resources.getFloatCompat(@DimenRes resId: Int) = ResourcesCompat.getFloat(this, resId)
    }
}