豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit b695d98

Browse files
authored
fix(message-list): onSaveInstance crash (#10583)
2 parents 40de7a9 + 9e78416 commit b695d98

File tree

8 files changed

+206
-124
lines changed

8 files changed

+206
-124
lines changed

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

Lines changed: 20 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.fsck.k9.ui.messagelist
33
import android.app.SearchManager
44
import android.content.Context
55
import android.content.Intent
6-
import android.os.Build
76
import android.os.Bundle
87
import android.os.SystemClock
98
import android.view.LayoutInflater
@@ -38,7 +37,6 @@ import androidx.fragment.app.setFragmentResultListener
3837
import androidx.lifecycle.Lifecycle
3938
import androidx.lifecycle.Observer
4039
import androidx.lifecycle.lifecycleScope
41-
import androidx.lifecycle.repeatOnLifecycle
4240
import androidx.recyclerview.widget.RecyclerView
4341
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
4442
import app.k9mail.core.android.common.contact.ContactRepository
@@ -81,9 +79,7 @@ import kotlin.time.Clock
8179
import kotlin.time.ExperimentalTime
8280
import kotlinx.collections.immutable.persistentSetOf
8381
import kotlinx.coroutines.Dispatchers
84-
import kotlinx.coroutines.flow.Flow
8582
import kotlinx.coroutines.flow.StateFlow
86-
import kotlinx.coroutines.flow.collectLatest
8783
import kotlinx.coroutines.flow.distinctUntilChanged
8884
import kotlinx.coroutines.flow.drop
8985
import kotlinx.coroutines.flow.launchIn
@@ -106,8 +102,8 @@ import net.thunderbird.core.featureflag.FeatureFlagProvider
106102
import net.thunderbird.core.featureflag.FeatureFlagResult
107103
import net.thunderbird.core.logging.Logger
108104
import net.thunderbird.core.outcome.Outcome
109-
import net.thunderbird.core.preference.GeneralSettings
110105
import net.thunderbird.core.preference.GeneralSettingsManager
106+
import net.thunderbird.core.preference.display.visualSettings.message.list.DisplayMessageListSettings
111107
import net.thunderbird.core.preference.interaction.InteractionSettings
112108
import net.thunderbird.core.ui.theme.api.FeatureThemeProvider
113109
import net.thunderbird.feature.account.AccountId
@@ -273,6 +269,8 @@ abstract class BaseMessageListFragment :
273269
private var messageListSwipeCallback: MessageListSwipeCallback? = null
274270
private val interactionSettings: InteractionSettings
275271
get() = generalSettingsManager.getConfig().interaction
272+
private val messageListSettings: DisplayMessageListSettings
273+
get() = generalSettingsManager.getConfig().display.visualSettings.messageListSettings
276274

277275
/**
278276
* Set this to `true` when the fragment should be considered active. When active, the fragment adds its actions to
@@ -287,10 +285,6 @@ abstract class BaseMessageListFragment :
287285
maybeHideFloatingActionButton()
288286
}
289287

290-
private lateinit var messageListAppearance: MessageListAppearance
291-
private var pendingMessageListInfo: MessageListInfo? = null
292-
private var pendingAdapterDependentFunctionExecution = mutableListOf<() -> Unit>()
293-
294288
fun isSearchViewCollapsed(): Boolean {
295289
return searchView?.isIconified != false
296290
}
@@ -322,6 +316,12 @@ abstract class BaseMessageListFragment :
322316
return
323317
}
324318

319+
viewModel.getMessageListLiveData().observe(this) { messageListInfo: MessageListInfo ->
320+
setMessageList(messageListInfo)
321+
}
322+
323+
adapter = createMessageListAdapter()
324+
325325
generalSettingsManager.getSettingsFlow()
326326
/**
327327
* Skips the first emitted item from the settings flow,
@@ -351,18 +351,6 @@ abstract class BaseMessageListFragment :
351351
initialSearchViewIconified = savedInstanceState.getBoolean(STATE_SEARCH_VIEW_ICONIFIED, true)
352352
val messageReferenceString = savedInstanceState.getString(STATE_ACTIVE_MESSAGE)
353353
activeMessage = MessageReference.parse(messageReferenceString)
354-
355-
messageListAppearance = requireNotNull(
356-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
357-
savedInstanceState.getParcelable(STATE_MESSAGE_LIST_APPEARANCE, MessageListAppearance::class.java)
358-
} else {
359-
@Suppress("DEPRECATION")
360-
savedInstanceState.getParcelable(STATE_MESSAGE_LIST_APPEARANCE)
361-
},
362-
) {
363-
"Could not restore MessageListAppearance. Missing parcelable extra '$STATE_MESSAGE_LIST_APPEARANCE'. " +
364-
"Extras: $savedInstanceState"
365-
}
366354
}
367355

368356
private fun restoreSelectedMessages(savedInstanceState: Bundle) {
@@ -416,7 +404,7 @@ abstract class BaseMessageListFragment :
416404
layoutInflater = layoutInflater,
417405
contactsPictureLoader = ContactPicture.getContactPictureLoader(),
418406
listItemListener = this,
419-
appearance = ::messageListAppearance,
407+
appearance = messageListAppearance,
420408
relativeDateTimeFormatter = RelativeDateTimeFormatter(requireContext(), clock),
421409
themeProvider = featureThemeProvider,
422410
featureFlagProvider = featureFlagProvider,
@@ -446,27 +434,6 @@ abstract class BaseMessageListFragment :
446434
}
447435

448436
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
449-
lifecycleScope.launch {
450-
viewLifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.CREATED) {
451-
fetchMessageListAppearance()
452-
.distinctUntilChanged()
453-
.collectLatest { appearance ->
454-
messageListAppearance = appearance
455-
if (recyclerView == null) {
456-
initializeRecyclerView(requireView())
457-
}
458-
}
459-
}
460-
}
461-
462-
viewModel.getMessageListLiveData().observe(viewLifecycleOwner) { messageListInfo: MessageListInfo ->
463-
if (::adapter.isInitialized) {
464-
setMessageList(messageListInfo)
465-
} else {
466-
pendingMessageListInfo = messageListInfo
467-
}
468-
}
469-
470437
val menuHost: MenuHost = requireActivity()
471438

472439
menuHost.addMenuProvider(
@@ -499,17 +466,6 @@ abstract class BaseMessageListFragment :
499466
}
500467
}
501468

502-
protected open suspend fun fetchMessageListAppearance(): Flow<MessageListAppearance> {
503-
return generalSettingsManager
504-
.getConfigFlow()
505-
.map { config ->
506-
if (showingThreadedList != config.display.inboxSettings.isThreadedViewEnabled) {
507-
showingThreadedList = config.display.inboxSettings.isThreadedViewEnabled
508-
}
509-
createMessageListAppearance(config)
510-
}
511-
}
512-
513469
private fun initializeErrorLayout(view: View) {
514470
val errorMessageView = view.findViewById<MaterialTextView>(R.id.message_list_error_message)
515471
errorMessageView.text = getString(error!!.errorText)
@@ -518,6 +474,7 @@ abstract class BaseMessageListFragment :
518474
private fun initializeMessageListLayout(view: View) {
519475
initializeSwipeRefreshLayout(view)
520476
initializeFloatingActionButton(view)
477+
initializeRecyclerView(view)
521478
initializeRecentChangesSnackbar()
522479

523480
// This needs to be done before loading the message list below
@@ -602,12 +559,6 @@ abstract class BaseMessageListFragment :
602559
}
603560

604561
private fun initializeRecyclerView(view: View) {
605-
adapter = createMessageListAdapter()
606-
pendingMessageListInfo?.let { messageListInfo ->
607-
setMessageList(messageListInfo)
608-
pendingMessageListInfo = null
609-
}
610-
611562
val recyclerView = view.findViewById<RecyclerView>(R.id.message_list)
612563

613564
if (!isShowFloatingActionButton) {
@@ -658,11 +609,6 @@ abstract class BaseMessageListFragment :
658609

659610
this.recyclerView = recyclerView
660611
this.itemTouchHelper = itemTouchHelper
661-
if (pendingAdapterDependentFunctionExecution.isNotEmpty()) {
662-
logger.debug(logTag) { "Executing pending adapter dependent functions" }
663-
pendingAdapterDependentFunctionExecution.forEach { it() }
664-
pendingAdapterDependentFunctionExecution.clear()
665-
}
666612
}
667613

668614
private fun requireCoordinatorLayout(): CoordinatorLayout {
@@ -761,17 +707,7 @@ abstract class BaseMessageListFragment :
761707
viewModel.loadMessageList(config, forceUpdate)
762708
}
763709

764-
private fun executeOnlyAfterAdapterIsReady(function: () -> Unit) {
765-
if (::adapter.isInitialized.not()) {
766-
pendingAdapterDependentFunctionExecution.add {
767-
function()
768-
}
769-
} else {
770-
function()
771-
}
772-
}
773-
774-
fun folderLoading(folderId: Long, loading: Boolean) = executeOnlyAfterAdapterIsReady {
710+
fun folderLoading(folderId: Long, loading: Boolean) {
775711
currentFolder?.let {
776712
if (it.databaseId == folderId) {
777713
it.loading = loading
@@ -897,7 +833,6 @@ abstract class BaseMessageListFragment :
897833
itemTouchHelper = null
898834
swipeRefreshLayout = null
899835
floatingActionButton = null
900-
pendingAdapterDependentFunctionExecution.clear()
901836

902837
if (isNewMessagesView && !requireActivity().isChangingConfigurations) {
903838
account?.id?.let { messagingController.clearNewMessages(it) }
@@ -924,25 +859,24 @@ abstract class BaseMessageListFragment :
924859
if (activeMessage != null) {
925860
outState.putString(STATE_ACTIVE_MESSAGE, activeMessage!!.toIdentityString())
926861
}
927-
outState.putParcelable(STATE_MESSAGE_LIST_APPEARANCE, messageListAppearance)
928862
}
929863

930-
protected fun createMessageListAppearance(config: GeneralSettings): MessageListAppearance {
931-
val displaySettings = config.display
932-
val inboxSettings = displaySettings.inboxSettings
933-
val messageListSettings = displaySettings.visualSettings.messageListSettings
934-
return MessageListAppearance(
864+
private val messageListAppearance: MessageListAppearance
865+
get() = MessageListAppearance(
935866
fontSizes = K9.fontSizes,
936867
previewLines = messageListSettings.previewLines,
937-
stars = !isOutbox && displaySettings.inboxSettings.isShowMessageListStars,
938-
senderAboveSubject = inboxSettings.isMessageListSenderAboveSubject,
868+
stars = !isOutbox && generalSettingsManager.getConfig().display.inboxSettings.isShowMessageListStars,
869+
senderAboveSubject = generalSettingsManager
870+
.getConfig()
871+
.display
872+
.inboxSettings
873+
.isMessageListSenderAboveSubject,
939874
showContactPicture = messageListSettings.isShowContactPicture,
940875
showingThreadedList = showingThreadedList,
941876
backGroundAsReadIndicator = messageListSettings.isUseBackgroundAsUnreadIndicator,
942877
showAccountIndicator = isShowAccountIndicator,
943878
density = messageListSettings.uiDensity,
944879
)
945-
}
946880

947881
private fun getFolderInfoHolder(account: LegacyAccount, folderId: Long): FolderInfoHolder {
948882
val localStore = localStoreProvider.getInstanceByLegacyAccount(account)
@@ -2786,6 +2720,5 @@ abstract class BaseMessageListFragment :
27862720
protected const val STATE_REMOTE_SEARCH_PERFORMED = "remoteSearchPerformed"
27872721
protected const val STATE_SEARCH_VIEW_QUERY = "searchViewQuery"
27882722
protected const val STATE_SEARCH_VIEW_ICONIFIED = "searchViewIconified"
2789-
protected const val STATE_MESSAGE_LIST_APPEARANCE = "messageListAppearance"
27902723
}
27912724
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class MessageListAdapter internal constructor(
4444
private val layoutInflater: LayoutInflater,
4545
private val contactsPictureLoader: ContactPictureLoader,
4646
private val listItemListener: MessageListItemActionListener,
47-
private val appearance: () -> MessageListAppearance,
47+
private val appearance: MessageListAppearance,
4848
private val relativeDateTimeFormatter: RelativeDateTimeFormatter,
4949
private val themeProvider: FeatureThemeProvider,
5050
private val featureFlagProvider: FeatureFlagProvider,
@@ -350,7 +350,7 @@ class MessageListAdapter internal constructor(
350350
private fun calculateSelectionCount(): Int {
351351
return when {
352352
selected.isEmpty() -> 0
353-
!appearance().showingThreadedList -> selected.size
353+
!appearance.showingThreadedList -> selected.size
354354
else ->
355355
viewItems
356356
.asSequence()
Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
package com.fsck.k9.ui.messagelist
22

3-
import android.os.Parcelable
43
import com.fsck.k9.FontSizes
5-
import kotlinx.parcelize.IgnoredOnParcel
6-
import kotlinx.parcelize.Parcelize
74
import net.thunderbird.core.preference.display.visualSettings.message.list.UiDensity
85

9-
@Parcelize
106
data class MessageListAppearance(
11-
@IgnoredOnParcel
12-
val fontSizes: FontSizes = FontSizes(),
7+
val fontSizes: FontSizes,
138
val previewLines: Int,
149
val stars: Boolean,
1510
val senderAboveSubject: Boolean,
@@ -21,4 +16,4 @@ data class MessageListAppearance(
2116
*/
2217
val showAccountIndicator: Boolean,
2318
val density: UiDensity,
24-
) : Parcelable
19+
)

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

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,14 @@ import androidx.core.os.bundleOf
77
import androidx.lifecycle.Lifecycle
88
import androidx.lifecycle.lifecycleScope
99
import androidx.lifecycle.repeatOnLifecycle
10-
import kotlinx.coroutines.flow.Flow
1110
import kotlinx.coroutines.flow.SharingStarted
1211
import kotlinx.coroutines.flow.StateFlow
1312
import kotlinx.coroutines.flow.map
14-
import kotlinx.coroutines.flow.mapNotNull
1513
import kotlinx.coroutines.flow.stateIn
1614
import kotlinx.coroutines.launch
1715
import net.thunderbird.core.common.action.SwipeActions
1816
import net.thunderbird.feature.account.AccountId
1917
import net.thunderbird.feature.account.AccountIdFactory
20-
import net.thunderbird.feature.mail.message.list.preferences.MessageListPreferences
2118
import net.thunderbird.feature.mail.message.list.ui.MessageListContract
2219
import net.thunderbird.feature.search.legacy.LocalMessageSearch
2320
import net.thunderbird.feature.search.legacy.serialization.LocalMessageSearchSerializer
@@ -58,21 +55,6 @@ class MessageListFragment : BaseMessageListFragment() {
5855
}
5956
}
6057

61-
override suspend fun fetchMessageListAppearance(): Flow<MessageListAppearance> = viewModel
62-
.state
63-
.mapNotNull { state -> state.preferences?.toMessageListAppearance() }
64-
65-
private fun MessageListPreferences.toMessageListAppearance(): MessageListAppearance = MessageListAppearance(
66-
previewLines = excerptLines,
67-
stars = showFavouriteButton,
68-
senderAboveSubject = senderAboveSubject,
69-
showContactPicture = showMessageAvatar,
70-
showingThreadedList = groupConversations,
71-
backGroundAsReadIndicator = colorizeBackgroundWhenRead,
72-
showAccountIndicator = isShowAccountIndicator,
73-
density = density,
74-
)
75-
7658
companion object Factory : BaseMessageListFragment.Factory {
7759
override fun newInstance(
7860
search: LocalMessageSearch,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class ComposableMessageViewHolder(
1919
private val onLongClick: (MessageListItem) -> Unit,
2020
private val onAvatarClick: (MessageListItem) -> Unit,
2121
private val onFavouriteClick: (MessageListItem) -> Unit,
22-
private val appearance: () -> MessageListAppearance,
22+
private val appearance: MessageListAppearance,
2323
private val contactRepository: ContactRepository,
2424
private val avatarMonogramCreator: AvatarMonogramCreator,
2525
) : MessageListViewHolder(composeView) {
@@ -41,7 +41,7 @@ class ComposableMessageViewHolder(
4141
onLongClick = { onLongClick(item) },
4242
onAvatarClick = { onAvatarClick(item) },
4343
onFavouriteClick = { onFavouriteClick(item) },
44-
appearance = appearance(),
44+
appearance = appearance,
4545
)
4646
}
4747
}
@@ -58,7 +58,7 @@ class ComposableMessageViewHolder(
5858
onLongClick: (MessageListItem) -> Unit,
5959
onFavouriteClick: (MessageListItem) -> Unit,
6060
onAvatarClick: (MessageListItem) -> Unit,
61-
appearance: () -> MessageListAppearance,
61+
appearance: MessageListAppearance,
6262
): ComposableMessageViewHolder {
6363
val composeView = ComposeView(context)
6464

0 commit comments

Comments
 (0)