Loading legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListAdapter.kt +43 −10 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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>() { Loading Loading @@ -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( Loading Loading @@ -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, Loading @@ -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 -> Loading @@ -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, Loading @@ -289,6 +316,7 @@ class MessageListAdapter internal constructor( isSelected = isSelected(messageListItem), ) } } TYPE_FOOTER -> { val footerViewHolder = holder as FooterViewHolder Loading Loading @@ -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>, Loading legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt +1 −0 Original line number Diff line number Diff line Loading @@ -344,6 +344,7 @@ class MessageListFragment : listItemListener = this, appearance = messageListAppearance, relativeDateTimeFormatter = RelativeDateTimeFormatter(requireContext(), clock), themeProvider = featureThemeProvider, featureFlagProvider = featureFlagProvider, ).apply { activeMessage = this@MessageListFragment.activeMessage Loading legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListSwipeCallback.kt +8 −6 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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 { Loading legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt +26 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -432,7 +436,8 @@ class MessageListAdapterTest : RobolectricTest() { listItemListener = listItemListener, appearance = appearance, relativeDateTimeFormatter = RelativeDateTimeFormatter(context, TestClock()), featureFlagProvider = { FeatureFlagResult.Disabled }, themeProvider = FakeThemeProvider(), featureFlagProvider = FakeFeatureFlagProvider(), ) } Loading Loading @@ -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 } } Loading
legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListAdapter.kt +43 −10 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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>() { Loading Loading @@ -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( Loading Loading @@ -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, Loading @@ -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 -> Loading @@ -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, Loading @@ -289,6 +316,7 @@ class MessageListAdapter internal constructor( isSelected = isSelected(messageListItem), ) } } TYPE_FOOTER -> { val footerViewHolder = holder as FooterViewHolder Loading Loading @@ -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>, Loading
legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt +1 −0 Original line number Diff line number Diff line Loading @@ -344,6 +344,7 @@ class MessageListFragment : listItemListener = this, appearance = messageListAppearance, relativeDateTimeFormatter = RelativeDateTimeFormatter(requireContext(), clock), themeProvider = featureThemeProvider, featureFlagProvider = featureFlagProvider, ).apply { activeMessage = this@MessageListFragment.activeMessage Loading
legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListSwipeCallback.kt +8 −6 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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 { Loading
legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt +26 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -432,7 +436,8 @@ class MessageListAdapterTest : RobolectricTest() { listItemListener = listItemListener, appearance = appearance, relativeDateTimeFormatter = RelativeDateTimeFormatter(context, TestClock()), featureFlagProvider = { FeatureFlagResult.Disabled }, themeProvider = FakeThemeProvider(), featureFlagProvider = FakeFeatureFlagProvider(), ) } Loading Loading @@ -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 } }