Merge pull request #6647 from thundernest/message_details_folder_name
Display folder name in message details screen
This commit is contained in:
commit
ae374bd5f4
7 changed files with 122 additions and 4 deletions
|
@ -0,0 +1,34 @@
|
||||||
|
package com.fsck.k9.ui.messagedetails
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import com.fsck.k9.ui.R
|
||||||
|
import com.mikepenz.fastadapter.FastAdapter
|
||||||
|
import com.mikepenz.fastadapter.items.AbstractItem
|
||||||
|
|
||||||
|
internal class FolderNameItem(
|
||||||
|
val displayName: String,
|
||||||
|
@DrawableRes val iconResourceId: Int
|
||||||
|
) : AbstractItem<FolderNameItem.ViewHolder>() {
|
||||||
|
override val type: Int = R.id.message_details_folder_name
|
||||||
|
override val layoutRes = R.layout.message_details_folder_name_item
|
||||||
|
|
||||||
|
override fun getViewHolder(v: View) = ViewHolder(v)
|
||||||
|
|
||||||
|
class ViewHolder(view: View) : FastAdapter.ViewHolder<FolderNameItem>(view) {
|
||||||
|
private val folderIcon: ImageView = view.findViewById(R.id.folder_icon)
|
||||||
|
private val folderName = view.findViewById<TextView>(R.id.folder_name)
|
||||||
|
|
||||||
|
override fun bindView(item: FolderNameItem, payloads: List<Any>) {
|
||||||
|
folderName.text = item.displayName
|
||||||
|
folderIcon.setImageResource(item.iconResourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unbindView(item: FolderNameItem) {
|
||||||
|
folderName.text = null
|
||||||
|
folderIcon.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,11 +8,13 @@ val messageDetailsUiModule = module {
|
||||||
MessageDetailsViewModel(
|
MessageDetailsViewModel(
|
||||||
resources = get(),
|
resources = get(),
|
||||||
messageRepository = get(),
|
messageRepository = get(),
|
||||||
|
folderRepository = get(),
|
||||||
contactSettingsProvider = get(),
|
contactSettingsProvider = get(),
|
||||||
contacts = get(),
|
contacts = get(),
|
||||||
clipboardManager = get(),
|
clipboardManager = get(),
|
||||||
accountManager = get(),
|
accountManager = get(),
|
||||||
participantFormatter = get()
|
participantFormatter = get(),
|
||||||
|
folderNameFormatter = get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
factory { ContactSettingsProvider() }
|
factory { ContactSettingsProvider() }
|
||||||
|
|
|
@ -24,6 +24,7 @@ import com.fsck.k9.controller.MessageReference
|
||||||
import com.fsck.k9.mail.Address
|
import com.fsck.k9.mail.Address
|
||||||
import com.fsck.k9.mailstore.CryptoResultAnnotation
|
import com.fsck.k9.mailstore.CryptoResultAnnotation
|
||||||
import com.fsck.k9.ui.R
|
import com.fsck.k9.ui.R
|
||||||
|
import com.fsck.k9.ui.folders.FolderIconProvider
|
||||||
import com.fsck.k9.ui.observe
|
import com.fsck.k9.ui.observe
|
||||||
import com.fsck.k9.ui.withArguments
|
import com.fsck.k9.ui.withArguments
|
||||||
import com.mikepenz.fastadapter.FastAdapter
|
import com.mikepenz.fastadapter.FastAdapter
|
||||||
|
@ -32,12 +33,14 @@ import com.mikepenz.fastadapter.adapters.ItemAdapter
|
||||||
import com.mikepenz.fastadapter.listeners.ClickEventHook
|
import com.mikepenz.fastadapter.listeners.ClickEventHook
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
import org.koin.core.parameter.parametersOf
|
||||||
|
|
||||||
class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() {
|
class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() {
|
||||||
private val viewModel: MessageDetailsViewModel by viewModel()
|
private val viewModel: MessageDetailsViewModel by viewModel()
|
||||||
private val addToContactsLauncher: AddToContactsLauncher by inject()
|
private val addToContactsLauncher: AddToContactsLauncher by inject()
|
||||||
private val showContactLauncher: ShowContactLauncher by inject()
|
private val showContactLauncher: ShowContactLauncher by inject()
|
||||||
private val contactPictureLoader: ContactPictureLoader by inject()
|
private val contactPictureLoader: ContactPictureLoader by inject()
|
||||||
|
private val folderIconProvider: FolderIconProvider by inject { parametersOf(requireContext().theme) }
|
||||||
|
|
||||||
private lateinit var messageReference: MessageReference
|
private lateinit var messageReference: MessageReference
|
||||||
|
|
||||||
|
@ -138,6 +141,10 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() {
|
||||||
addParticipants(details.to, R.string.message_details_to_section_title, showContactPicture)
|
addParticipants(details.to, R.string.message_details_to_section_title, showContactPicture)
|
||||||
addParticipants(details.cc, R.string.message_details_cc_section_title, showContactPicture)
|
addParticipants(details.cc, R.string.message_details_cc_section_title, showContactPicture)
|
||||||
addParticipants(details.bcc, R.string.message_details_bcc_section_title, showContactPicture)
|
addParticipants(details.bcc, R.string.message_details_bcc_section_title, showContactPicture)
|
||||||
|
|
||||||
|
if (details.folder != null) {
|
||||||
|
addFolderName(details.folder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val adapter = FastAdapter.with(itemAdapter).apply {
|
val adapter = FastAdapter.with(itemAdapter).apply {
|
||||||
|
@ -166,6 +173,14 @@ class MessageDetailsFragment : ToolbarBottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ItemAdapter<GenericItem>.addFolderName(folder: FolderInfoUi) {
|
||||||
|
val folderNameItem = FolderNameItem(
|
||||||
|
displayName = folder.displayName,
|
||||||
|
iconResourceId = folderIconProvider.getFolderIcon(folder.type)
|
||||||
|
)
|
||||||
|
add(folderNameItem)
|
||||||
|
}
|
||||||
|
|
||||||
private val cryptoStatusClickEventHook = object : ClickEventHook<CryptoStatusItem>() {
|
private val cryptoStatusClickEventHook = object : ClickEventHook<CryptoStatusItem>() {
|
||||||
override fun onBind(viewHolder: RecyclerView.ViewHolder): View? {
|
override fun onBind(viewHolder: RecyclerView.ViewHolder): View? {
|
||||||
return if (viewHolder is CryptoStatusItem.ViewHolder) {
|
return if (viewHolder is CryptoStatusItem.ViewHolder) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.fsck.k9.ui.messagedetails
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.fsck.k9.mail.Address
|
import com.fsck.k9.mail.Address
|
||||||
|
import com.fsck.k9.mailstore.FolderType
|
||||||
import com.fsck.k9.view.MessageCryptoDisplayStatus
|
import com.fsck.k9.view.MessageCryptoDisplayStatus
|
||||||
|
|
||||||
data class MessageDetailsUi(
|
data class MessageDetailsUi(
|
||||||
|
@ -12,7 +13,8 @@ data class MessageDetailsUi(
|
||||||
val replyTo: List<Participant>,
|
val replyTo: List<Participant>,
|
||||||
val to: List<Participant>,
|
val to: List<Participant>,
|
||||||
val cc: List<Participant>,
|
val cc: List<Participant>,
|
||||||
val bcc: List<Participant>
|
val bcc: List<Participant>,
|
||||||
|
val folder: FolderInfoUi?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CryptoDetails(
|
data class CryptoDetails(
|
||||||
|
@ -31,3 +33,8 @@ data class Participant(
|
||||||
val address: Address
|
val address: Address
|
||||||
get() = Address(emailAddress, displayName?.toString())
|
get() = Address(emailAddress, displayName?.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class FolderInfoUi(
|
||||||
|
val displayName: String,
|
||||||
|
val type: FolderType
|
||||||
|
)
|
||||||
|
|
|
@ -10,10 +10,13 @@ import com.fsck.k9.helper.ClipboardManager
|
||||||
import com.fsck.k9.helper.Contacts
|
import com.fsck.k9.helper.Contacts
|
||||||
import com.fsck.k9.mail.Address
|
import com.fsck.k9.mail.Address
|
||||||
import com.fsck.k9.mailstore.CryptoResultAnnotation
|
import com.fsck.k9.mailstore.CryptoResultAnnotation
|
||||||
|
import com.fsck.k9.mailstore.Folder
|
||||||
|
import com.fsck.k9.mailstore.FolderRepository
|
||||||
import com.fsck.k9.mailstore.MessageDate
|
import com.fsck.k9.mailstore.MessageDate
|
||||||
import com.fsck.k9.mailstore.MessageRepository
|
import com.fsck.k9.mailstore.MessageRepository
|
||||||
import com.fsck.k9.preferences.AccountManager
|
import com.fsck.k9.preferences.AccountManager
|
||||||
import com.fsck.k9.ui.R
|
import com.fsck.k9.ui.R
|
||||||
|
import com.fsck.k9.ui.folders.FolderNameFormatter
|
||||||
import com.fsck.k9.view.MessageCryptoDisplayStatus
|
import com.fsck.k9.view.MessageCryptoDisplayStatus
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
@ -27,11 +30,13 @@ import kotlinx.coroutines.launch
|
||||||
internal class MessageDetailsViewModel(
|
internal class MessageDetailsViewModel(
|
||||||
private val resources: Resources,
|
private val resources: Resources,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
|
private val folderRepository: FolderRepository,
|
||||||
private val contactSettingsProvider: ContactSettingsProvider,
|
private val contactSettingsProvider: ContactSettingsProvider,
|
||||||
private val contacts: Contacts,
|
private val contacts: Contacts,
|
||||||
private val clipboardManager: ClipboardManager,
|
private val clipboardManager: ClipboardManager,
|
||||||
private val accountManager: AccountManager,
|
private val accountManager: AccountManager,
|
||||||
private val participantFormatter: MessageDetailsParticipantFormatter
|
private val participantFormatter: MessageDetailsParticipantFormatter,
|
||||||
|
private val folderNameFormatter: FolderNameFormatter
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault())
|
private val dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault())
|
||||||
private val uiState = MutableStateFlow<MessageDetailsState>(MessageDetailsState.Loading)
|
private val uiState = MutableStateFlow<MessageDetailsState>(MessageDetailsState.Loading)
|
||||||
|
@ -46,6 +51,8 @@ internal class MessageDetailsViewModel(
|
||||||
val account = accountManager.getAccount(messageReference.accountUuid) ?: error("Account not found")
|
val account = accountManager.getAccount(messageReference.accountUuid) ?: error("Account not found")
|
||||||
val messageDetails = messageRepository.getMessageDetails(messageReference)
|
val messageDetails = messageRepository.getMessageDetails(messageReference)
|
||||||
|
|
||||||
|
val folder = folderRepository.getFolder(account, folderId = messageReference.folderId)
|
||||||
|
|
||||||
val senderList = messageDetails.sender?.let { listOf(it) } ?: emptyList()
|
val senderList = messageDetails.sender?.let { listOf(it) } ?: emptyList()
|
||||||
val messageDetailsUi = MessageDetailsUi(
|
val messageDetailsUi = MessageDetailsUi(
|
||||||
date = buildDisplayDate(messageDetails.date),
|
date = buildDisplayDate(messageDetails.date),
|
||||||
|
@ -55,7 +62,8 @@ internal class MessageDetailsViewModel(
|
||||||
replyTo = messageDetails.replyTo.toParticipants(account),
|
replyTo = messageDetails.replyTo.toParticipants(account),
|
||||||
to = messageDetails.to.toParticipants(account),
|
to = messageDetails.to.toParticipants(account),
|
||||||
cc = messageDetails.cc.toParticipants(account),
|
cc = messageDetails.cc.toParticipants(account),
|
||||||
bcc = messageDetails.bcc.toParticipants(account)
|
bcc = messageDetails.bcc.toParticipants(account),
|
||||||
|
folder = folder?.toFolderInfo()
|
||||||
)
|
)
|
||||||
|
|
||||||
MessageDetailsState.DataLoaded(
|
MessageDetailsState.DataLoaded(
|
||||||
|
@ -100,6 +108,13 @@ internal class MessageDetailsViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Folder.toFolderInfo(): FolderInfoUi {
|
||||||
|
return FolderInfoUi(
|
||||||
|
displayName = folderNameFormatter.displayName(this),
|
||||||
|
type = this.type
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun onCryptoStatusClicked() {
|
fun onCryptoStatusClicked() {
|
||||||
val cryptoResult = cryptoResult ?: return
|
val cryptoResult = cryptoResult ?: return
|
||||||
val cryptoStatus = MessageCryptoDisplayStatus.fromResultAnnotation(cryptoResult)
|
val cryptoStatus = MessageCryptoDisplayStatus.fromResultAnnotation(cryptoResult)
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="8dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/keyline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintGuide_begin="72dp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/folder_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/keyline"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.0"
|
||||||
|
tools:srcCompat="@drawable/ic_folder" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/folder_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:textAppearance="?attr/textAppearanceBody2"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/keyline"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Regular folder" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -4,5 +4,6 @@
|
||||||
<item type="id" name="message_details_crypto_status"/>
|
<item type="id" name="message_details_crypto_status"/>
|
||||||
<item type="id" name="message_details_section_header"/>
|
<item type="id" name="message_details_section_header"/>
|
||||||
<item type="id" name="message_details_participant"/>
|
<item type="id" name="message_details_participant"/>
|
||||||
|
<item type="id" name="message_details_folder_name"/>
|
||||||
<item type="id" name="message_details_divider"/>
|
<item type="id" name="message_details_divider"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue