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

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

feat(message-list): add feature flag to message list adapter and swipe callback

parent 0cd0810c
Loading
Loading
Loading
Loading
+43 −10
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@ import app.k9mail.feature.launcher.FeatureLauncherTarget
import app.k9mail.legacy.message.controller.MessageReference
import com.fsck.k9.contacts.ContactPictureLoader
import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
import com.fsck.k9.ui.messagelist.MessageListFeatureFlags.UseComposeForMessageListItems
import com.fsck.k9.ui.messagelist.item.BannerInlineListInAppNotificationViewHolder
import com.fsck.k9.ui.messagelist.item.ComposableMessageViewHolder
import com.fsck.k9.ui.messagelist.item.FooterViewHolder
import com.fsck.k9.ui.messagelist.item.MessageListViewHolder
import com.fsck.k9.ui.messagelist.item.MessageViewHolder
@@ -25,6 +27,7 @@ import com.fsck.k9.ui.messagelist.item.MessageViewHolderColors
import net.thunderbird.core.featureflag.FeatureFlagKey
import net.thunderbird.core.featureflag.FeatureFlagProvider
import net.thunderbird.core.featureflag.FeatureFlagResult
import net.thunderbird.core.ui.theme.api.FeatureThemeProvider
import net.thunderbird.feature.notification.api.ui.action.NotificationAction

private const val FOOTER_ID = 1L
@@ -42,6 +45,7 @@ class MessageListAdapter internal constructor(
    private val listItemListener: MessageListItemActionListener,
    private val appearance: MessageListAppearance,
    private val relativeDateTimeFormatter: RelativeDateTimeFormatter,
    private val themeProvider: FeatureThemeProvider,
    private val featureFlagProvider: FeatureFlagProvider,
) : RecyclerView.Adapter<MessageListViewHolder>() {

@@ -227,7 +231,15 @@ class MessageListAdapter internal constructor(

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageListViewHolder {
        return when (viewType) {
            TYPE_MESSAGE -> createMessageViewHolder(parent)
            TYPE_MESSAGE -> {
                val result = featureFlagProvider.provide(UseComposeForMessageListItems)
                if (result.isEnabled()) {
                    createComposableMessageViewHolder(parent)
                } else {
                    createMessageViewHolder(parent)
                }
            }

            TYPE_FOOTER -> FooterViewHolder.create(layoutInflater, parent, footerClickListener)
            TYPE_IN_APP_NOTIFICATION_BANNER_INLINE_LIST if isInAppNotificationEnabled ->
                BannerInlineListInAppNotificationViewHolder(
@@ -259,7 +271,7 @@ class MessageListAdapter internal constructor(
        }
    }

    private fun createMessageViewHolder(parent: ViewGroup?): MessageViewHolder =
    private fun createMessageViewHolder(parent: ViewGroup): MessageViewHolder =
        MessageViewHolder.create(
            layoutInflater = layoutInflater,
            parent = parent,
@@ -275,6 +287,12 @@ class MessageListAdapter internal constructor(
            starClickListener = starClickListener,
        )

    private fun createComposableMessageViewHolder(parent: ViewGroup): MessageListViewHolder =
        ComposableMessageViewHolder.create(
            context = parent.context,
            themeProvider = themeProvider,
        )

    override fun onBindViewHolder(holder: MessageListViewHolder, position: Int) {
        when (val viewType = getItemViewType(position)) {
            TYPE_IN_APP_NOTIFICATION_BANNER_INLINE_LIST if isInAppNotificationEnabled ->
@@ -282,6 +300,15 @@ class MessageListAdapter internal constructor(

            TYPE_MESSAGE -> {
                val messageListItem = getItem(position)
                val result = featureFlagProvider.provide(UseComposeForMessageListItems)
                if (result.isEnabled()) {
                    val messageViewHolder = holder as ComposableMessageViewHolder
                    messageViewHolder.bind(
                        item = messageListItem,
                        isActive = isActiveMessage(messageListItem),
                        isSelected = isSelected(messageListItem),
                    )
                } else {
                    val messageViewHolder = holder as MessageViewHolder
                    messageViewHolder.bind(
                        messageListItem = messageListItem,
@@ -289,6 +316,7 @@ class MessageListAdapter internal constructor(
                        isSelected = isSelected(messageListItem),
                    )
                }
            }

            TYPE_FOOTER -> {
                val footerViewHolder = holder as FooterViewHolder
@@ -368,10 +396,15 @@ class MessageListAdapter internal constructor(
    }

    private fun getItemFromView(view: View): MessageListItem? {
        if (featureFlagProvider.provide(UseComposeForMessageListItems).isEnabled()) {
            val messageViewHolder = view.tag as ComposableMessageViewHolder
            return getItemById(messageViewHolder.uniqueId)
        } else {
            val messageViewHolder = view.tag as MessageViewHolder
            return getItemById(messageViewHolder.uniqueId)
        }
    }
}

private class MessageListDiffCallback(
    private val oldMessageList: List<MessageListItem>,
+1 −0
Original line number Diff line number Diff line
@@ -344,6 +344,7 @@ class MessageListFragment :
            listItemListener = this,
            appearance = messageListAppearance,
            relativeDateTimeFormatter = RelativeDateTimeFormatter(requireContext(), clock),
            themeProvider = featureThemeProvider,
            featureFlagProvider = featureFlagProvider,
        ).apply {
            activeMessage = this@MessageListFragment.activeMessage
+8 −6
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import app.k9mail.ui.utils.itemtouchhelper.ItemTouchHelper
import com.fsck.k9.ui.R
import com.fsck.k9.ui.messagelist.item.ComposableMessageViewHolder
import com.fsck.k9.ui.messagelist.item.MessageViewHolder
import com.google.android.material.color.ColorRoles
import com.google.android.material.textview.MaterialTextView
@@ -81,9 +82,7 @@ class MessageListSwipeCallback(
        }

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: ViewHolder): Int {
        if (viewHolder !is MessageViewHolder) return 0

        val item = adapter.getItemById(viewHolder.uniqueId) ?: return 0
        val item = viewHolder.messageListItem ?: return 0
        val (swipeLeftAction, swipeRightAction) = item.swipeActions

        var swipeFlags = 0
@@ -178,8 +177,7 @@ class MessageListSwipeCallback(

        if (dX != 0F) {
            canvas.withTranslation(x = view.left.toFloat(), y = view.top.toFloat()) {
                val holder = viewHolder as MessageViewHolder
                val item = adapter.getItemById(holder.uniqueId) ?: return@withTranslation
                val item = viewHolder.messageListItem ?: return@withTranslation
                if (isCurrentlyActive || !success) {
                    drawLayout(dX, viewWidth, viewHeight, item)
                } else {
@@ -377,7 +375,11 @@ class MessageListSwipeCallback(
    }

    private val ViewHolder.messageListItem: MessageListItem?
        get() = (this as? MessageViewHolder)?.uniqueId?.let { adapter.getItemById(it) }
        get() = when (this) {
            is MessageViewHolder -> adapter.getItemById(uniqueId)
            is ComposableMessageViewHolder -> adapter.getItemById(uniqueId)
            else -> null
        }
}

fun interface SwipeActionSupportProvider {
+26 −1
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.Composable
import androidx.core.view.isGone
import androidx.core.view.isVisible
import assertk.Assert
@@ -31,8 +32,11 @@ import kotlin.time.ExperimentalTime
import net.thunderbird.core.android.account.Identity
import net.thunderbird.core.android.account.LegacyAccount
import net.thunderbird.core.android.testing.RobolectricTest
import net.thunderbird.core.featureflag.FeatureFlagKey
import net.thunderbird.core.featureflag.FeatureFlagProvider
import net.thunderbird.core.featureflag.FeatureFlagResult
import net.thunderbird.core.testing.TestClock
import net.thunderbird.core.ui.theme.api.FeatureThemeProvider
import net.thunderbird.feature.account.AccountIdFactory
import net.thunderbird.feature.account.storage.profile.AvatarDto
import net.thunderbird.feature.account.storage.profile.AvatarTypeDto
@@ -432,7 +436,8 @@ class MessageListAdapterTest : RobolectricTest() {
            listItemListener = listItemListener,
            appearance = appearance,
            relativeDateTimeFormatter = RelativeDateTimeFormatter(context, TestClock()),
            featureFlagProvider = { FeatureFlagResult.Disabled },
            themeProvider = FakeThemeProvider(),
            featureFlagProvider = FakeFeatureFlagProvider(),
        )
    }

@@ -578,4 +583,24 @@ class MessageListAdapterTest : RobolectricTest() {

    private val MaterialTextView.textString: String
        get() = text.toString()

    private class FakeThemeProvider : FeatureThemeProvider {
        @Composable
        override fun WithTheme(content: @Composable (() -> Unit)) {
            content()
        }

        @Composable
        override fun WithTheme(
            darkTheme: Boolean,
            content: @Composable (() -> Unit),
        ) {
            content()
        }
    }

    private class FakeFeatureFlagProvider : FeatureFlagProvider {
        // Disabled as the test is primarily concerned with the XML based UI
        override fun provide(key: FeatureFlagKey): FeatureFlagResult = FeatureFlagResult.Disabled
    }
}