Skip to content

Commit 3b759b5

Browse files
Merge pull request #9836 from rafaeltonholo/fix/9819/message-list-load-more-not-showing
fix(message-list): message list skipping first item and load more footer also doesn't show up
2 parents 80b25fc + 8211505 commit 3b759b5

File tree

4 files changed

+99
-73
lines changed

4 files changed

+99
-73
lines changed

legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListAdapter.kt

Lines changed: 78 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import android.view.ViewGroup
1111
import androidx.compose.ui.platform.ComposeView
1212
import androidx.recyclerview.widget.DiffUtil
1313
import androidx.recyclerview.widget.RecyclerView
14-
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
1514
import app.k9mail.feature.launcher.FeatureLauncherActivity
1615
import app.k9mail.feature.launcher.FeatureLauncherTarget
1716
import app.k9mail.legacy.message.controller.MessageReference
@@ -31,6 +30,7 @@ import net.thunderbird.core.ui.theme.api.FeatureThemeProvider
3130
import net.thunderbird.feature.notification.api.ui.action.NotificationAction
3231

3332
private const val FOOTER_ID = 1L
33+
private const val IN_APP_NOTIFICATION_BANNER_INLINE_LIST_ID = -1L
3434

3535
private const val TYPE_MESSAGE = 0
3636
private const val TYPE_FOOTER = 1
@@ -51,14 +51,15 @@ class MessageListAdapter internal constructor(
5151

5252
val colors: MessageViewHolderColors = MessageViewHolderColors.resolveColors(theme)
5353

54-
var messages: List<MessageListItem> = emptyList()
54+
var viewItems: List<MessageListViewItem> = emptyList()
5555
@SuppressLint("NotifyDataSetChanged")
5656
set(value) {
5757
val oldMessageList = field
5858

5959
field = value
60-
accountUuids = value.map { it.account.uuid }.toSet()
61-
messagesMap = value.associateBy { it.uniqueId }
60+
val messages = value.filterMessageListItem()
61+
accountUuids = messages.map { it.account.uuid }.toSet()
62+
messagesMap = messages.associateBy { it.uniqueId }
6263

6364
if (selected.isNotEmpty()) {
6465
val uniqueIds = messagesMap.keys
@@ -71,6 +72,7 @@ class MessageListAdapter internal constructor(
7172
diffResult.dispatchUpdatesTo(this)
7273
}
7374

75+
private val messages get() = viewItems.filterMessageListItem()
7476
private var messagesMap = emptyMap<Long, MessageListItem>()
7577
private var accountUuids = emptySet<String>()
7678

@@ -122,34 +124,6 @@ class MessageListAdapter internal constructor(
122124
var selectedCount: Int = 0
123125
private set
124126

125-
var footerText: String? = null
126-
set(value) {
127-
if (field == value) return
128-
129-
val hadFooterText = field != null
130-
val previousFooterPosition = footerPosition
131-
field = value
132-
133-
if (hadFooterText) {
134-
if (value == null) {
135-
notifyItemRemoved(previousFooterPosition)
136-
} else {
137-
notifyItemChanged(footerPosition)
138-
}
139-
} else {
140-
notifyItemInserted(footerPosition)
141-
}
142-
}
143-
144-
private val hasFooter: Boolean
145-
get() = footerText != null
146-
147-
private val lastMessagePosition: Int
148-
get() = messages.lastIndex
149-
150-
private val footerPosition: Int
151-
get() = if (hasFooter) lastMessagePosition + 1 else NO_POSITION
152-
153127
private val messageClickedListener = OnClickListener { view: View ->
154128
val messageListItem = getItemFromView(view) ?: return@OnClickListener
155129
listItemListener.onMessageClicked(messageListItem)
@@ -185,48 +159,48 @@ class MessageListAdapter internal constructor(
185159
setHasStableIds(true)
186160
}
187161

188-
override fun getItemCount(): Int = messages.size + if (hasFooter) 1 else 0
162+
override fun getItemCount(): Int = viewItems.size
189163

190164
override fun getItemId(position: Int): Long {
191-
return if (position <= lastMessagePosition) {
192-
messages[position].uniqueId
193-
} else {
194-
FOOTER_ID
195-
}
165+
return viewItems[position].viewId
196166
}
197167

198168
override fun getItemViewType(position: Int): Int {
199-
return when {
200-
position == 0 && isInAppNotificationEnabled -> TYPE_IN_APP_NOTIFICATION_BANNER_INLINE_LIST
201-
position <= lastMessagePosition -> TYPE_MESSAGE
202-
else -> TYPE_FOOTER
203-
}
169+
return viewItems[position].viewType
204170
}
205171

206-
private fun getItem(position: Int): MessageListItem = messages[position]
172+
private fun getItem(position: Int): MessageListItem = (viewItems[position] as MessageListViewItem.Message).item
207173

208174
fun getItemById(uniqueId: Long): MessageListItem? {
209175
return messagesMap[uniqueId]
210176
}
211177

212178
fun getItem(messageReference: MessageReference): MessageListItem? {
213-
return messages.firstOrNull {
214-
it.account.uuid == messageReference.accountUuid &&
215-
it.folderId == messageReference.folderId &&
216-
it.messageUid == messageReference.uid
217-
}
179+
return viewItems
180+
.filterMessageListItem()
181+
.firstOrNull {
182+
it.account.uuid == messageReference.accountUuid &&
183+
it.folderId == messageReference.folderId &&
184+
it.messageUid == messageReference.uid
185+
}
218186
}
219187

220188
fun getPosition(messageListItem: MessageListItem): Int? {
221-
return messages.indexOf(messageListItem).takeIf { it != -1 }
189+
return viewItems
190+
.map { (it as? MessageListViewItem.Message)?.item }
191+
.indexOf(messageListItem).takeIf { it != -1 }
222192
}
223193

224194
private fun getPosition(messageReference: MessageReference?): Int? {
225195
if (messageReference == null) return null
226196

227-
return messages.indexOfFirst {
228-
messageReference.equals(it.account.uuid, it.folderId, it.messageUid)
229-
}.takeIf { it != -1 }
197+
return viewItems
198+
.map { (it as? MessageListViewItem.Message)?.item }
199+
.indexOfFirst {
200+
it != null &&
201+
messageReference.equals(it.account.uuid, it.folderId, it.messageUid)
202+
}
203+
.takeIf { it != -1 }
230204
}
231205

232206
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageListViewHolder {
@@ -241,6 +215,7 @@ class MessageListAdapter internal constructor(
241215
}
242216

243217
TYPE_FOOTER -> FooterViewHolder.create(layoutInflater, parent, footerClickListener)
218+
244219
TYPE_IN_APP_NOTIFICATION_BANNER_INLINE_LIST if isInAppNotificationEnabled ->
245220
BannerInlineListInAppNotificationViewHolder(
246221
view = ComposeView(context = parent.context),
@@ -325,7 +300,8 @@ class MessageListAdapter internal constructor(
325300

326301
TYPE_FOOTER -> {
327302
val footerViewHolder = holder as FooterViewHolder
328-
footerViewHolder.bind(footerText)
303+
val footer = viewItems[position] as MessageListViewItem.Footer
304+
footerViewHolder.bind(footer.text)
329305
}
330306

331307
else -> {
@@ -386,18 +362,17 @@ class MessageListAdapter internal constructor(
386362
}
387363

388364
private fun calculateSelectionCount(): Int {
389-
if (selected.isEmpty()) {
390-
return 0
391-
}
392-
393-
if (!appearance.showingThreadedList) {
394-
return selected.size
365+
return when {
366+
selected.isEmpty() -> 0
367+
!appearance.showingThreadedList -> selected.size
368+
else ->
369+
viewItems
370+
.asSequence()
371+
.filterIsInstance<MessageListViewItem.Message>()
372+
.map { it.item }
373+
.filter { it.uniqueId in selected }
374+
.sumOf { it.threadCount.coerceAtLeast(1) }
395375
}
396-
397-
return messages
398-
.asSequence()
399-
.filter { it.uniqueId in selected }
400-
.sumOf { it.threadCount.coerceAtLeast(1) }
401376
}
402377

403378
private fun getItemFromView(view: View): MessageListItem? {
@@ -409,18 +384,33 @@ class MessageListAdapter internal constructor(
409384
return getItemById(messageViewHolder.uniqueId)
410385
}
411386
}
387+
388+
private fun List<MessageListViewItem>.filterMessageListItem(): List<MessageListItem> =
389+
filterIsInstance<MessageListViewItem.Message>()
390+
.map { it.item }
412391
}
413392

414393
private class MessageListDiffCallback(
415-
private val oldMessageList: List<MessageListItem>,
416-
private val newMessageList: List<MessageListItem>,
394+
private val oldMessageList: List<MessageListViewItem>,
395+
private val newMessageList: List<MessageListViewItem>,
417396
) : DiffUtil.Callback() {
418397
override fun getOldListSize(): Int = oldMessageList.size
419398

420399
override fun getNewListSize(): Int = newMessageList.size
421400

422401
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
423-
return oldMessageList[oldItemPosition].uniqueId == newMessageList[newItemPosition].uniqueId
402+
val oldItem = oldMessageList[oldItemPosition]
403+
val newItem = newMessageList[newItemPosition]
404+
return when (oldItem) {
405+
is MessageListViewItem.InAppNotificationBannerList
406+
if newItem is MessageListViewItem.InAppNotificationBannerList -> true
407+
408+
is MessageListViewItem.Message
409+
if newItem is MessageListViewItem.Message -> oldItem.item.uniqueId == newItem.item.uniqueId
410+
411+
is MessageListViewItem.Footer if newItem is MessageListViewItem.Footer -> true
412+
else -> false
413+
}
424414
}
425415

426416
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
@@ -434,3 +424,23 @@ interface MessageListItemActionListener {
434424
fun onToggleMessageFlag(item: MessageListItem)
435425
fun onFooterClicked()
436426
}
427+
428+
sealed interface MessageListViewItem {
429+
val viewId: Long
430+
val viewType: Int
431+
432+
data object InAppNotificationBannerList : MessageListViewItem {
433+
override val viewId: Long = IN_APP_NOTIFICATION_BANNER_INLINE_LIST_ID
434+
override val viewType: Int = TYPE_IN_APP_NOTIFICATION_BANNER_INLINE_LIST
435+
}
436+
437+
data class Message(val item: MessageListItem) : MessageListViewItem {
438+
override val viewId: Long get() = item.uniqueId
439+
override val viewType: Int = TYPE_MESSAGE
440+
}
441+
442+
data class Footer(val text: String) : MessageListViewItem {
443+
override val viewId: Long = FOOTER_ID
444+
override val viewType: Int = TYPE_FOOTER
445+
}
446+
}

legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,11 +1131,20 @@ class MessageListFragment :
11311131
}
11321132

11331133
fun updateFooterText(text: String?) {
1134-
adapter.footerText = text
1134+
val currentItems = adapter
1135+
.viewItems
1136+
.filter { it !is MessageListViewItem.Footer }
1137+
.toMutableList()
1138+
1139+
if (!text.isNullOrEmpty()) {
1140+
currentItems.add(MessageListViewItem.Footer(text))
1141+
}
1142+
1143+
adapter.viewItems = currentItems
11351144
}
11361145

11371146
private fun selectAll() {
1138-
if (adapter.messages.isEmpty()) {
1147+
if (adapter.viewItems.isEmpty()) {
11391148
// Nothing to do if there are no messages
11401149
return
11411150
}
@@ -1452,6 +1461,7 @@ class MessageListFragment :
14521461
destinationFolderId,
14531462
)
14541463
}
1464+
14551465
FolderOperation.MOVE -> {
14561466
messagingController.moveMessages(
14571467
account.id,
@@ -1460,6 +1470,7 @@ class MessageListFragment :
14601470
destinationFolderId,
14611471
)
14621472
}
1473+
14631474
FolderOperation.COPY if showingThreadedList -> {
14641475
messagingController.copyMessagesInThread(
14651476
account.id,
@@ -1468,6 +1479,7 @@ class MessageListFragment :
14681479
destinationFolderId,
14691480
)
14701481
}
1482+
14711483
FolderOperation.COPY -> {
14721484
messagingController.copyMessages(
14731485
account.id,
@@ -1735,7 +1747,12 @@ class MessageListFragment :
17351747
}
17361748
}
17371749

1738-
adapter.messages = messageListItems
1750+
adapter.viewItems = buildList {
1751+
if (featureFlagProvider.provide(FeatureFlagKey.DisplayInAppNotifications).isEnabled()) {
1752+
add(MessageListViewItem.InAppNotificationBannerList)
1753+
}
1754+
addAll(messageListItems.map { MessageListViewItem.Message(it) })
1755+
}
17391756

17401757
rememberedSelected?.let {
17411758
rememberedSelected = null

legacy/ui/legacy/src/main/res/layout/message_list_fragment.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
android:layout_width="match_parent"
5050
android:layout_height="wrap_content"
5151
android:layout_gravity="top"
52-
android:background="@color/pink"
5352
/>
5453

5554
</androidx.core.view.insets.ProtectionLayout>

legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ class MessageListAdapterTest : RobolectricTest() {
531531
}
532532

533533
fun MessageListAdapter.createAndBindView(item: MessageListItem = createMessageListItem()): View {
534-
messages = listOf(item)
534+
viewItems = listOf(MessageListViewItem.Message(item))
535535
val holder = onCreateViewHolder(LinearLayout(context), 0)
536536
onBindViewHolder(holder, 0)
537537
return holder.itemView

0 commit comments

Comments
 (0)