Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/CryptoStatusItem.kt 0 → 100644 +52 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messagedetails import android.content.res.ColorStateList import android.view.View import android.widget.ImageView import android.widget.TextView import com.fsck.k9.ui.R import com.fsck.k9.ui.resolveColorAttribute import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.items.AbstractItem internal class CryptoStatusItem(val cryptoDetails: CryptoDetails) : AbstractItem<CryptoStatusItem.ViewHolder>() { override val type = R.id.message_details_crypto_status override val layoutRes = R.layout.message_details_crypto_status_item override fun getViewHolder(v: View) = ViewHolder(v) class ViewHolder(view: View) : FastAdapter.ViewHolder<CryptoStatusItem>(view) { private val titleTextView = view.findViewById<TextView>(R.id.crypto_status_title) private val descriptionTextView = view.findViewById<TextView>(R.id.crypto_status_description) private val imageView = view.findViewById<ImageView>(R.id.crypto_status_icon) private val originalBackground = view.background override fun bindView(item: CryptoStatusItem, payloads: List<Any>) { val context = itemView.context val cryptoDetails = item.cryptoDetails val cryptoStatus = cryptoDetails.cryptoStatus imageView.setImageResource(cryptoStatus.statusIconRes) val tintColor = context.theme.resolveColorAttribute(cryptoStatus.colorAttr) imageView.imageTintList = ColorStateList.valueOf(tintColor) cryptoStatus.titleTextRes?.let { stringResId -> titleTextView.text = context.getString(stringResId) } cryptoStatus.descriptionTextRes?.let { stringResId -> descriptionTextView.text = context.getString(stringResId) } if (!cryptoDetails.isClickable) { itemView.background = null } } override fun unbindView(item: CryptoStatusItem) { imageView.setImageDrawable(null) titleTextView.text = null descriptionTextView.text = null itemView.background = originalBackground } } } app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsFragment.kt +64 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messagedetails import android.app.PendingIntent import android.content.Intent import android.net.Uri import android.os.Bundle Loading @@ -11,13 +12,16 @@ import android.widget.ProgressBar import androidx.annotation.StringRes import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResult import androidx.recyclerview.widget.RecyclerView import app.k9mail.ui.utils.bottomsheet.ToolbarBottomSheetDialogFragment import com.fsck.k9.activity.MessageCompose import com.fsck.k9.contacts.ContactPictureLoader import com.fsck.k9.controller.MessageReference import com.fsck.k9.mail.Address import com.fsck.k9.mailstore.CryptoResultAnnotation import com.fsck.k9.ui.R import com.fsck.k9.ui.observe import com.fsck.k9.ui.withArguments Loading @@ -36,6 +40,9 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { private lateinit var messageReference: MessageReference // FIXME: Replace this with a mechanism that survives process death var cryptoResult: CryptoResultAnnotation? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading @@ -54,6 +61,10 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) cryptoResult?.let { viewModel.cryptoResult = it } val dialog = checkNotNull(dialog) dialog.isDismissWithAnimation = true Loading @@ -71,6 +82,14 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { val errorView = view.findViewById<View>(R.id.message_details_error) val recyclerView = view.findViewById<RecyclerView>(R.id.message_details_list) viewModel.uiEvents.observe(this) { event -> when (event) { is MessageDetailEvent.ShowCryptoKeys -> showCryptoKeys(event.pendingIntent) MessageDetailEvent.SearchCryptoKeys -> searchCryptoKeys() MessageDetailEvent.ShowCryptoWarning -> showCryptoWarning() } } viewModel.loadData(messageReference).observe(this) { state -> when (state) { MessageDetailsState.Loading -> { Loading @@ -97,6 +116,10 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { val itemAdapter = ItemAdapter<GenericItem>().apply { add(MessageDateItem(details.date ?: getString(R.string.message_details_missing_date))) if (details.cryptoDetails != null) { add(CryptoStatusItem(details.cryptoDetails)) } addParticipants(details.from, R.string.message_details_from_section_title, showContactPicture) addParticipants(details.sender, R.string.message_details_sender_section_title, showContactPicture) addParticipants(details.replyTo, R.string.message_details_replyto_section_title, showContactPicture) Loading @@ -109,6 +132,7 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } val adapter = FastAdapter.with(itemAdapter).apply { addEventHook(cryptoStatusClickEventHook) addEventHook(participantClickEventHook) addEventHook(addToContactsClickEventHook) addEventHook(composeClickEventHook) Loading @@ -133,6 +157,27 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } } private val cryptoStatusClickEventHook = object : ClickEventHook<CryptoStatusItem>() { override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { return if (viewHolder is CryptoStatusItem.ViewHolder) { viewHolder.itemView } else { null } } override fun onClick( v: View, position: Int, fastAdapter: FastAdapter<CryptoStatusItem>, item: CryptoStatusItem ) { if (item.cryptoDetails.isClickable) { viewModel.onCryptoStatusClicked() } } } private val participantClickEventHook = object : ClickEventHook<ParticipantItem>() { override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { return if (viewHolder is ParticipantItem.ViewHolder) { Loading Loading @@ -237,9 +282,28 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } } private fun showCryptoKeys(pendingIntent: PendingIntent) { requireActivity().startIntentSender(pendingIntent.intentSender, null, 0, 0, 0) } private fun searchCryptoKeys() { setFragmentResult(FRAGMENT_RESULT_KEY, bundleOf(RESULT_ACTION to ACTION_SEARCH_KEYS)) dismiss() } private fun showCryptoWarning() { setFragmentResult(FRAGMENT_RESULT_KEY, bundleOf(RESULT_ACTION to ACTION_SHOW_WARNING)) dismiss() } companion object { private const val ARG_REFERENCE = "reference" const val FRAGMENT_RESULT_KEY = "messageDetailsResult" const val RESULT_ACTION = "action" const val ACTION_SEARCH_KEYS = "search_keys" const val ACTION_SHOW_WARNING = "show_warning" fun create(messageReference: MessageReference): MessageDetailsFragment { return MessageDetailsFragment().withArguments( ARG_REFERENCE to messageReference.toIdentityString() Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsUi.kt +7 −0 Original line number Diff line number Diff line Loading @@ -2,9 +2,11 @@ package com.fsck.k9.ui.messagedetails import android.net.Uri import com.fsck.k9.mail.Address import com.fsck.k9.view.MessageCryptoDisplayStatus data class MessageDetailsUi( val date: String?, val cryptoDetails: CryptoDetails?, val from: List<Participant>, val sender: List<Participant>, val replyTo: List<Participant>, Loading @@ -13,6 +15,11 @@ data class MessageDetailsUi( val bcc: List<Participant> ) data class CryptoDetails( val cryptoStatus: MessageCryptoDisplayStatus, val isClickable: Boolean ) data class Participant( val address: Address, val contactLookupUri: Uri? Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsViewModel.kt +47 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messagedetails import android.app.PendingIntent import android.content.res.Resources import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope Loading @@ -7,14 +8,18 @@ import com.fsck.k9.controller.MessageReference import com.fsck.k9.helper.ClipboardManager import com.fsck.k9.helper.Contacts import com.fsck.k9.mail.Address import com.fsck.k9.mailstore.CryptoResultAnnotation import com.fsck.k9.mailstore.MessageDate import com.fsck.k9.mailstore.MessageRepository import com.fsck.k9.ui.R import com.fsck.k9.view.MessageCryptoDisplayStatus import java.text.DateFormat import java.util.Locale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch internal class MessageDetailsViewModel( Loading @@ -26,6 +31,10 @@ internal class MessageDetailsViewModel( ) : ViewModel() { private val dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault()) private val uiState = MutableStateFlow<MessageDetailsState>(MessageDetailsState.Loading) private val eventChannel = Channel<MessageDetailEvent>() val uiEvents = eventChannel.receiveAsFlow() var cryptoResult: CryptoResultAnnotation? = null fun loadData(messageReference: MessageReference): StateFlow<MessageDetailsState> { viewModelScope.launch(Dispatchers.IO) { Loading @@ -35,6 +44,7 @@ internal class MessageDetailsViewModel( val senderList = messageDetails.sender?.let { listOf(it) } ?: emptyList() val messageDetailsUi = MessageDetailsUi( date = buildDisplayDate(messageDetails.date), cryptoDetails = cryptoResult?.toCryptoDetails(), from = messageDetails.from.toParticipants(), sender = senderList.toParticipants(), replyTo = messageDetails.replyTo.toParticipants(), Loading Loading @@ -63,6 +73,15 @@ internal class MessageDetailsViewModel( } } private fun CryptoResultAnnotation.toCryptoDetails(): CryptoDetails { val messageCryptoDisplayStatus = MessageCryptoDisplayStatus.fromResultAnnotation(this) return CryptoDetails( cryptoStatus = messageCryptoDisplayStatus, isClickable = messageCryptoDisplayStatus.hasAssociatedKey() || messageCryptoDisplayStatus.isUnknownKey || hasOpenPgpInsecureWarningPendingIntent() ) } private fun List<Address>.toParticipants(): List<Participant> { return this.map { address -> Participant( Loading @@ -72,6 +91,28 @@ internal class MessageDetailsViewModel( } } fun onCryptoStatusClicked() { val cryptoResult = cryptoResult ?: return val cryptoStatus = MessageCryptoDisplayStatus.fromResultAnnotation(cryptoResult) if (cryptoStatus.hasAssociatedKey()) { val pendingIntent = cryptoResult.openPgpSigningKeyIntentIfAny if (pendingIntent != null) { viewModelScope.launch { eventChannel.send(MessageDetailEvent.ShowCryptoKeys(pendingIntent)) } } } else if (cryptoStatus.isUnknownKey) { viewModelScope.launch { eventChannel.send(MessageDetailEvent.SearchCryptoKeys) } } else if (cryptoResult.hasOpenPgpInsecureWarningPendingIntent()) { viewModelScope.launch { eventChannel.send(MessageDetailEvent.ShowCryptoWarning) } } } fun onCopyEmailAddressToClipboard(participant: Participant) { val label = resources.getString(R.string.clipboard_label_email_address) val emailAddress = participant.address.address Loading @@ -93,3 +134,9 @@ sealed interface MessageDetailsState { val details: MessageDetailsUi ) : MessageDetailsState } sealed interface MessageDetailEvent { data class ShowCryptoKeys(val pendingIntent: PendingIntent) : MessageDetailEvent object SearchCryptoKeys : MessageDetailEvent object ShowCryptoWarning : MessageDetailEvent } app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoPresenter.java +4 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,10 @@ public class MessageCryptoPresenter implements OnCryptoClickListener { this.messageCryptoMvpView = messageCryptoMvpView; } public CryptoResultAnnotation getCryptoResultAnnotation() { return cryptoResultAnnotation; } public void onResume() { if (reloadOnResumeWithoutRecreateFlag) { reloadOnResumeWithoutRecreateFlag = false; Loading Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/CryptoStatusItem.kt 0 → 100644 +52 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messagedetails import android.content.res.ColorStateList import android.view.View import android.widget.ImageView import android.widget.TextView import com.fsck.k9.ui.R import com.fsck.k9.ui.resolveColorAttribute import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.items.AbstractItem internal class CryptoStatusItem(val cryptoDetails: CryptoDetails) : AbstractItem<CryptoStatusItem.ViewHolder>() { override val type = R.id.message_details_crypto_status override val layoutRes = R.layout.message_details_crypto_status_item override fun getViewHolder(v: View) = ViewHolder(v) class ViewHolder(view: View) : FastAdapter.ViewHolder<CryptoStatusItem>(view) { private val titleTextView = view.findViewById<TextView>(R.id.crypto_status_title) private val descriptionTextView = view.findViewById<TextView>(R.id.crypto_status_description) private val imageView = view.findViewById<ImageView>(R.id.crypto_status_icon) private val originalBackground = view.background override fun bindView(item: CryptoStatusItem, payloads: List<Any>) { val context = itemView.context val cryptoDetails = item.cryptoDetails val cryptoStatus = cryptoDetails.cryptoStatus imageView.setImageResource(cryptoStatus.statusIconRes) val tintColor = context.theme.resolveColorAttribute(cryptoStatus.colorAttr) imageView.imageTintList = ColorStateList.valueOf(tintColor) cryptoStatus.titleTextRes?.let { stringResId -> titleTextView.text = context.getString(stringResId) } cryptoStatus.descriptionTextRes?.let { stringResId -> descriptionTextView.text = context.getString(stringResId) } if (!cryptoDetails.isClickable) { itemView.background = null } } override fun unbindView(item: CryptoStatusItem) { imageView.setImageDrawable(null) titleTextView.text = null descriptionTextView.text = null itemView.background = originalBackground } } }
app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsFragment.kt +64 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messagedetails import android.app.PendingIntent import android.content.Intent import android.net.Uri import android.os.Bundle Loading @@ -11,13 +12,16 @@ import android.widget.ProgressBar import androidx.annotation.StringRes import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResult import androidx.recyclerview.widget.RecyclerView import app.k9mail.ui.utils.bottomsheet.ToolbarBottomSheetDialogFragment import com.fsck.k9.activity.MessageCompose import com.fsck.k9.contacts.ContactPictureLoader import com.fsck.k9.controller.MessageReference import com.fsck.k9.mail.Address import com.fsck.k9.mailstore.CryptoResultAnnotation import com.fsck.k9.ui.R import com.fsck.k9.ui.observe import com.fsck.k9.ui.withArguments Loading @@ -36,6 +40,9 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { private lateinit var messageReference: MessageReference // FIXME: Replace this with a mechanism that survives process death var cryptoResult: CryptoResultAnnotation? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading @@ -54,6 +61,10 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) cryptoResult?.let { viewModel.cryptoResult = it } val dialog = checkNotNull(dialog) dialog.isDismissWithAnimation = true Loading @@ -71,6 +82,14 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { val errorView = view.findViewById<View>(R.id.message_details_error) val recyclerView = view.findViewById<RecyclerView>(R.id.message_details_list) viewModel.uiEvents.observe(this) { event -> when (event) { is MessageDetailEvent.ShowCryptoKeys -> showCryptoKeys(event.pendingIntent) MessageDetailEvent.SearchCryptoKeys -> searchCryptoKeys() MessageDetailEvent.ShowCryptoWarning -> showCryptoWarning() } } viewModel.loadData(messageReference).observe(this) { state -> when (state) { MessageDetailsState.Loading -> { Loading @@ -97,6 +116,10 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { val itemAdapter = ItemAdapter<GenericItem>().apply { add(MessageDateItem(details.date ?: getString(R.string.message_details_missing_date))) if (details.cryptoDetails != null) { add(CryptoStatusItem(details.cryptoDetails)) } addParticipants(details.from, R.string.message_details_from_section_title, showContactPicture) addParticipants(details.sender, R.string.message_details_sender_section_title, showContactPicture) addParticipants(details.replyTo, R.string.message_details_replyto_section_title, showContactPicture) Loading @@ -109,6 +132,7 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } val adapter = FastAdapter.with(itemAdapter).apply { addEventHook(cryptoStatusClickEventHook) addEventHook(participantClickEventHook) addEventHook(addToContactsClickEventHook) addEventHook(composeClickEventHook) Loading @@ -133,6 +157,27 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } } private val cryptoStatusClickEventHook = object : ClickEventHook<CryptoStatusItem>() { override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { return if (viewHolder is CryptoStatusItem.ViewHolder) { viewHolder.itemView } else { null } } override fun onClick( v: View, position: Int, fastAdapter: FastAdapter<CryptoStatusItem>, item: CryptoStatusItem ) { if (item.cryptoDetails.isClickable) { viewModel.onCryptoStatusClicked() } } } private val participantClickEventHook = object : ClickEventHook<ParticipantItem>() { override fun onBind(viewHolder: RecyclerView.ViewHolder): View? { return if (viewHolder is ParticipantItem.ViewHolder) { Loading Loading @@ -237,9 +282,28 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() { } } private fun showCryptoKeys(pendingIntent: PendingIntent) { requireActivity().startIntentSender(pendingIntent.intentSender, null, 0, 0, 0) } private fun searchCryptoKeys() { setFragmentResult(FRAGMENT_RESULT_KEY, bundleOf(RESULT_ACTION to ACTION_SEARCH_KEYS)) dismiss() } private fun showCryptoWarning() { setFragmentResult(FRAGMENT_RESULT_KEY, bundleOf(RESULT_ACTION to ACTION_SHOW_WARNING)) dismiss() } companion object { private const val ARG_REFERENCE = "reference" const val FRAGMENT_RESULT_KEY = "messageDetailsResult" const val RESULT_ACTION = "action" const val ACTION_SEARCH_KEYS = "search_keys" const val ACTION_SHOW_WARNING = "show_warning" fun create(messageReference: MessageReference): MessageDetailsFragment { return MessageDetailsFragment().withArguments( ARG_REFERENCE to messageReference.toIdentityString() Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsUi.kt +7 −0 Original line number Diff line number Diff line Loading @@ -2,9 +2,11 @@ package com.fsck.k9.ui.messagedetails import android.net.Uri import com.fsck.k9.mail.Address import com.fsck.k9.view.MessageCryptoDisplayStatus data class MessageDetailsUi( val date: String?, val cryptoDetails: CryptoDetails?, val from: List<Participant>, val sender: List<Participant>, val replyTo: List<Participant>, Loading @@ -13,6 +15,11 @@ data class MessageDetailsUi( val bcc: List<Participant> ) data class CryptoDetails( val cryptoStatus: MessageCryptoDisplayStatus, val isClickable: Boolean ) data class Participant( val address: Address, val contactLookupUri: Uri? Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/messagedetails/MessageDetailsViewModel.kt +47 −0 Original line number Diff line number Diff line package com.fsck.k9.ui.messagedetails import android.app.PendingIntent import android.content.res.Resources import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope Loading @@ -7,14 +8,18 @@ import com.fsck.k9.controller.MessageReference import com.fsck.k9.helper.ClipboardManager import com.fsck.k9.helper.Contacts import com.fsck.k9.mail.Address import com.fsck.k9.mailstore.CryptoResultAnnotation import com.fsck.k9.mailstore.MessageDate import com.fsck.k9.mailstore.MessageRepository import com.fsck.k9.ui.R import com.fsck.k9.view.MessageCryptoDisplayStatus import java.text.DateFormat import java.util.Locale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch internal class MessageDetailsViewModel( Loading @@ -26,6 +31,10 @@ internal class MessageDetailsViewModel( ) : ViewModel() { private val dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault()) private val uiState = MutableStateFlow<MessageDetailsState>(MessageDetailsState.Loading) private val eventChannel = Channel<MessageDetailEvent>() val uiEvents = eventChannel.receiveAsFlow() var cryptoResult: CryptoResultAnnotation? = null fun loadData(messageReference: MessageReference): StateFlow<MessageDetailsState> { viewModelScope.launch(Dispatchers.IO) { Loading @@ -35,6 +44,7 @@ internal class MessageDetailsViewModel( val senderList = messageDetails.sender?.let { listOf(it) } ?: emptyList() val messageDetailsUi = MessageDetailsUi( date = buildDisplayDate(messageDetails.date), cryptoDetails = cryptoResult?.toCryptoDetails(), from = messageDetails.from.toParticipants(), sender = senderList.toParticipants(), replyTo = messageDetails.replyTo.toParticipants(), Loading Loading @@ -63,6 +73,15 @@ internal class MessageDetailsViewModel( } } private fun CryptoResultAnnotation.toCryptoDetails(): CryptoDetails { val messageCryptoDisplayStatus = MessageCryptoDisplayStatus.fromResultAnnotation(this) return CryptoDetails( cryptoStatus = messageCryptoDisplayStatus, isClickable = messageCryptoDisplayStatus.hasAssociatedKey() || messageCryptoDisplayStatus.isUnknownKey || hasOpenPgpInsecureWarningPendingIntent() ) } private fun List<Address>.toParticipants(): List<Participant> { return this.map { address -> Participant( Loading @@ -72,6 +91,28 @@ internal class MessageDetailsViewModel( } } fun onCryptoStatusClicked() { val cryptoResult = cryptoResult ?: return val cryptoStatus = MessageCryptoDisplayStatus.fromResultAnnotation(cryptoResult) if (cryptoStatus.hasAssociatedKey()) { val pendingIntent = cryptoResult.openPgpSigningKeyIntentIfAny if (pendingIntent != null) { viewModelScope.launch { eventChannel.send(MessageDetailEvent.ShowCryptoKeys(pendingIntent)) } } } else if (cryptoStatus.isUnknownKey) { viewModelScope.launch { eventChannel.send(MessageDetailEvent.SearchCryptoKeys) } } else if (cryptoResult.hasOpenPgpInsecureWarningPendingIntent()) { viewModelScope.launch { eventChannel.send(MessageDetailEvent.ShowCryptoWarning) } } } fun onCopyEmailAddressToClipboard(participant: Participant) { val label = resources.getString(R.string.clipboard_label_email_address) val emailAddress = participant.address.address Loading @@ -93,3 +134,9 @@ sealed interface MessageDetailsState { val details: MessageDetailsUi ) : MessageDetailsState } sealed interface MessageDetailEvent { data class ShowCryptoKeys(val pendingIntent: PendingIntent) : MessageDetailEvent object SearchCryptoKeys : MessageDetailEvent object ShowCryptoWarning : MessageDetailEvent }
app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoPresenter.java +4 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,10 @@ public class MessageCryptoPresenter implements OnCryptoClickListener { this.messageCryptoMvpView = messageCryptoMvpView; } public CryptoResultAnnotation getCryptoResultAnnotation() { return cryptoResultAnnotation; } public void onResume() { if (reloadOnResumeWithoutRecreateFlag) { reloadOnResumeWithoutRecreateFlag = false; Loading