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

Unverified Commit ed88e505 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #6287 from thundernest/move_selection_to_adapter

Move code to select message list items to `MessageListAdapter`
parents cc9f2fa8 20e70f8f
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
package com.fsck.k9.helper

/**
 * Returns a [Set] containing the results of applying the given [transform] function to each element in the original
 * collection.
 *
 * If you know the size of the output or can make an educated guess, specify [expectedSize] as an optimization.
 * The initial capacity of the `Set` will be derived from this value.
 */
inline fun <T, R> Iterable<T>.mapToSet(expectedSize: Int? = null, transform: (T) -> R): Set<R> {
    return if (expectedSize != null) {
        mapTo(LinkedHashSet(setCapacity(expectedSize)), transform)
    } else {
        mapTo(mutableSetOf(), transform)
    }
}

/**
 * Returns a [Set] containing the results of applying the given [transform] function to each element in the original
 * collection.
 *
 * The size of the output is expected to be equal to the size of the input. If that's not the case, please use
 * [mapToSet] instead.
 */
inline fun <T, R> Collection<T>.mapCollectionToSet(transform: (T) -> R): Set<R> {
    return mapToSet(expectedSize = size, transform)
}

// A copy of Kotlin's internal mapCapacity() for the JVM
fun setCapacity(expectedSize: Int): Int = when {
    // We are not coercing the value to a valid one and not throwing an exception. It is up to the caller to
    // properly handle negative values.
    expectedSize < 0 -> expectedSize
    expectedSize < 3 -> expectedSize + 1
    expectedSize < INT_MAX_POWER_OF_TWO -> ((expectedSize / 0.75F) + 1.0F).toInt()
    // any large value
    else -> Int.MAX_VALUE
}

private const val INT_MAX_POWER_OF_TWO: Int = 1 shl (Int.SIZE_BITS - 2)
+86 −0
Original line number Diff line number Diff line
@@ -56,6 +56,12 @@ class MessageListAdapter internal constructor(
        set(value) {
            field = value
            messagesMap = value.associateBy { it.uniqueId }

            if (selected.isNotEmpty()) {
                val uniqueIds = messagesMap.keys
                selected = selected.intersect(uniqueIds)
            }

            notifyDataSetChanged()
        }

@@ -64,6 +70,20 @@ class MessageListAdapter internal constructor(
    var activeMessage: MessageReference? = null

    var selected: Set<Long> = emptySet()
        private set(value) {
            field = value
            selectedCount = calculateSelectionCount()
            notifyDataSetChanged()
        }

    val selectedMessages: List<MessageListItem>
        get() = selected.map { messagesMap[it]!! }

    val isAllSelected: Boolean
        get() = selected.isNotEmpty() && selected.size == messages.size

    var selectedCount: Int = 0
        private set

    private inline val subjectViewFontSize: Int
        get() = if (appearance.senderAboveSubject) {
@@ -103,6 +123,18 @@ class MessageListAdapter internal constructor(
        return messagesMap[uniqueId]!!
    }

    fun getItem(messageReference: MessageReference): MessageListItem? {
        return messages.firstOrNull {
            it.account.uuid == messageReference.accountUuid &&
                it.folderId == messageReference.folderId &&
                it.messageUid == messageReference.uid
        }
    }

    fun getPosition(messageListItem: MessageListItem): Int? {
        return messages.indexOf(messageListItem).takeIf { it != -1 }
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val message = getItem(position)
        val view: View = convertView ?: newView(parent)
@@ -302,6 +334,60 @@ class MessageListAdapter internal constructor(
            item.folderId == activeMessage.folderId &&
            item.messageUid == activeMessage.uid
    }

    fun toggleSelection(item: MessageListItem) {
        if (messagesMap[item.uniqueId] == null) {
            // MessageListItem is no longer in the list
            return
        }

        if (item.uniqueId in selected) {
            deselectMessage(item)
        } else {
            selectMessage(item)
        }
    }

    private fun selectMessage(item: MessageListItem) {
        selected = selected + item.uniqueId
    }

    private fun deselectMessage(item: MessageListItem) {
        selected = selected - item.uniqueId
    }

    fun selectAll() {
        val uniqueIds = messagesMap.keys.toSet()
        selected = uniqueIds
    }

    fun clearSelected() {
        selected = emptySet()
    }

    fun restoreSelected(selectedIds: Set<Long>) {
        if (selectedIds.isEmpty()) {
            clearSelected()
        } else {
            val uniqueIds = messagesMap.keys
            selected = selectedIds.intersect(uniqueIds)
        }
    }

    private fun calculateSelectionCount(): Int {
        if (selected.isEmpty()) {
            return 0
        }

        if (!appearance.showingThreadedList) {
            return selected.size
        }

        return messages
            .asSequence()
            .filter { it.uniqueId in selected }
            .sumOf { it.threadCount.coerceAtLeast(1) }
    }
}

interface MessageListItemActionListener {
+112 −261

File changed.

Preview size limit exceeded, changes collapsed.

+0 −14

File changed.

Preview size limit exceeded, changes collapsed.