From 9c9dbcb0a04d0a051accd3171e49d740f09d5cfc Mon Sep 17 00:00:00 2001 From: Kevin Boulongne Date: Thu, 4 Jul 2024 10:02:29 +0200 Subject: [PATCH] Move each MenuDrawerAdapter's items binding to its own file --- .../com/infomaniak/mail/data/models/Folder.kt | 1 + .../ui/main/menuDrawer/MenuDrawerAdapter.kt | 330 ++++-------------- .../ui/main/menuDrawer/items/DividerItem.kt | 34 ++ .../main/menuDrawer/items/EmptyFoldersItem.kt | 34 ++ .../ui/main/menuDrawer/items/FolderItem.kt | 179 ++++++++++ .../menuDrawer/items/FoldersHeaderItem.kt | 54 +++ .../ui/main/menuDrawer/items/FooterItem.kt | 120 +++++++ .../menuDrawer/items/InvalidMailboxItem.kt | 69 ++++ .../ui/main/menuDrawer/items/MailboxItem.kt | 64 ++++ .../menuDrawer/items/MailboxesHeaderItem.kt | 90 +++++ .../mail/ui/main/move/MoveAdapter.kt | 6 +- 11 files changed, 720 insertions(+), 261 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/DividerItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/EmptyFoldersItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FolderItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FoldersHeaderItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FooterItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/InvalidMailboxItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxItem.kt create mode 100644 app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxesHeaderItem.kt diff --git a/app/src/main/java/com/infomaniak/mail/data/models/Folder.kt b/app/src/main/java/com/infomaniak/mail/data/models/Folder.kt index 7b0c66e773..87bbbecc09 100644 --- a/app/src/main/java/com/infomaniak/mail/data/models/Folder.kt +++ b/app/src/main/java/com/infomaniak/mail/data/models/Folder.kt @@ -182,6 +182,7 @@ class Folder : RealmObject, Cloneable { const val DEFAULT_IS_HISTORY_COMPLETE = false const val INBOX_FOLDER_ID = "eJzz9HPyjwAABGYBgQ--" + const val MAX_SUB_FOLDERS_INDENT = 2 private const val CUSTOM_FOLDER_ROLE_ORDER = 0 } } diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/MenuDrawerAdapter.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/MenuDrawerAdapter.kt index aa3d73fc71..d32323440e 100644 --- a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/MenuDrawerAdapter.kt +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/MenuDrawerAdapter.kt @@ -17,38 +17,21 @@ */ package com.infomaniak.mail.ui.main.menuDrawer -import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup -import androidx.annotation.DrawableRes -import androidx.appcompat.content.res.AppCompatResources -import androidx.core.view.isGone -import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.viewbinding.ViewBinding -import com.infomaniak.lib.core.utils.context -import com.infomaniak.mail.BuildConfig -import com.infomaniak.mail.MatomoMail -import com.infomaniak.mail.MatomoMail.toFloat -import com.infomaniak.mail.MatomoMail.trackMenuDrawerEvent -import com.infomaniak.mail.R import com.infomaniak.mail.data.models.Folder -import com.infomaniak.mail.data.models.Folder.FolderRole -import com.infomaniak.mail.data.models.Quotas import com.infomaniak.mail.data.models.mailbox.Mailbox -import com.infomaniak.mail.data.models.mailbox.MailboxPermissions -import com.infomaniak.mail.databinding.* import com.infomaniak.mail.ui.main.menuDrawer.MenuDrawerAdapter.MenuDrawerViewHolder import com.infomaniak.mail.ui.main.menuDrawer.MenuDrawerFragment.MediatorContainer -import com.infomaniak.mail.utils.UnreadDisplay +import com.infomaniak.mail.ui.main.menuDrawer.items.* +import com.infomaniak.mail.ui.main.menuDrawer.items.FooterItem.MenuDrawerFooter +import com.infomaniak.mail.ui.main.menuDrawer.items.MailboxesHeaderItem.MailboxesHeader import com.infomaniak.mail.utils.Utils.runCatchingRealm -import com.infomaniak.mail.utils.extensions.toggleChevron -import com.infomaniak.mail.views.itemViews.* -import com.infomaniak.mail.views.itemViews.DecoratedItemView.SelectionStyle import javax.inject.Inject -import kotlin.math.min class MenuDrawerAdapter @Inject constructor() : ListAdapter(FolderDiffCallback()) { @@ -62,8 +45,8 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter Unit private lateinit var onMailboxesHeaderClicked: () -> Unit private lateinit var onValidMailboxClicked: (Int) -> Unit - private lateinit var onInvalidPasswordMailboxClicked: (Mailbox) -> Unit private lateinit var onLockedMailboxClicked: (String) -> Unit + private lateinit var onInvalidPasswordMailboxClicked: (Mailbox) -> Unit private lateinit var onCustomFoldersHeaderClicked: (Boolean) -> Unit private lateinit var onCreateFolderClicked: () -> Unit private lateinit var onFolderClicked: (folderId: String) -> Unit @@ -202,13 +185,13 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter DisplayType.MAILBOXES_HEADER.layout - is Mailbox -> if (item.isValid) DisplayType.MAILBOX.layout else DisplayType.INVALID_MAILBOX.layout - is Folder -> DisplayType.FOLDER.layout - ItemType.CUSTOM_FOLDERS_HEADER -> DisplayType.CUSTOM_FOLDERS_HEADER.layout - ItemType.EMPTY_CUSTOM_FOLDERS -> DisplayType.EMPTY_CUSTOM_FOLDERS.layout - is MenuDrawerFooter -> DisplayType.MENU_DRAWER_FOOTER.layout - ItemType.DIVIDER -> DisplayType.DIVIDER.layout + is MailboxesHeader -> MailboxesHeaderItem.viewType + is Mailbox -> if (item.isValid) MailboxItem.viewType else InvalidMailboxItem.viewType + is Folder -> FolderItem.viewType + ItemType.CUSTOM_FOLDERS_HEADER -> FoldersHeaderItem.viewType + ItemType.EMPTY_CUSTOM_FOLDERS -> EmptyFoldersItem.viewType + is MenuDrawerFooter -> FooterItem.viewType + ItemType.DIVIDER -> DividerItem.viewType else -> throw IllegalStateException("Failed to find a viewType for MenuDrawer item") } }.getOrDefault(super.getItemViewType(position)) @@ -217,13 +200,14 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter ItemMenuDrawerMailboxesHeaderBinding.inflate(inflater, parent, false) - DisplayType.MAILBOX.layout -> ItemMenuDrawerMailboxBinding.inflate(inflater, parent, false) - DisplayType.FOLDER.layout -> ItemMenuDrawerFolderBinding.inflate(inflater, parent, false) - DisplayType.CUSTOM_FOLDERS_HEADER.layout -> ItemMenuDrawerCustomFoldersHeaderBinding.inflate(inflater, parent, false) - DisplayType.EMPTY_CUSTOM_FOLDERS.layout -> ItemMenuDrawerEmptyCustomFoldersBinding.inflate(inflater, parent, false) - DisplayType.MENU_DRAWER_FOOTER.layout -> ItemMenuDrawerFooterBinding.inflate(inflater, parent, false) - DisplayType.DIVIDER.layout -> ItemMenuDrawerDividerBinding.inflate(inflater, parent, false) + MailboxesHeaderItem.viewType -> MailboxesHeaderItem.binding(inflater, parent) + MailboxItem.viewType -> MailboxItem.binding(inflater, parent) + InvalidMailboxItem.viewType -> InvalidMailboxItem.binding(inflater, parent) + FolderItem.viewType -> FolderItem.binding(inflater, parent) + FoldersHeaderItem.viewType -> FoldersHeaderItem.binding(inflater, parent) + EmptyFoldersItem.viewType -> EmptyFoldersItem.binding(inflater, parent) + FooterItem.viewType -> FooterItem.binding(inflater, parent) + DividerItem.viewType -> DividerItem.binding(inflater, parent) else -> throw IllegalStateException("Failed to find a binding for MenuDrawer viewType") } @@ -231,23 +215,21 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter) { - - val payload = payloads.firstOrNull() - if (payload !is NotifyType) { - super.onBindViewHolder(holder, position, payloads) - return - } - - when (payload) { - NotifyType.MAILBOXES_HEADER_CLICKED -> { - Log.d("Bind", "Bind Mailboxes header because of collapse change") - (holder.binding as ItemMenuDrawerMailboxesHeaderBinding).updateCollapseState(items[position] as MailboxesHeader) - } - NotifyType.COLLAPSABLE_FOLDER_EXISTENCE_HAS_CHANGED -> { - val folder = items[position] as Folder - Log.d("Bind", "Bind Custom folders because of collapse change = ${folder.name}") - (holder.binding as ItemMenuDrawerFolderBinding).displayFolder(folder) - } + when (payloads.firstOrNull()) { + NotifyType.MAILBOXES_HEADER_CLICKED -> MailboxesHeaderItem.displayWithPayload( + item = items[position], + binding = holder.binding, + ) + NotifyType.COLLAPSABLE_FOLDER_EXISTENCE_HAS_CHANGED -> FolderItem.displayWithPayload( + item = items[position], + binding = holder.binding, + currentFolderId = currentFolderId, + hasCollapsableDefaultFolder = hasCollapsableDefaultFolder, + hasCollapsableCustomFolder = hasCollapsableCustomFolder, + onFolderClicked = onFolderClicked, + onCollapseChildrenClicked = onCollapseChildrenClicked, + ) + else -> super.onBindViewHolder(holder, position, payloads) } } @@ -255,211 +237,51 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter { - Log.d("Bind", "Bind Mailboxes header") - (this as ItemMenuDrawerMailboxesHeaderBinding).displayMailboxesHeader(item as MailboxesHeader) - } - DisplayType.MAILBOX.layout -> { - Log.d("Bind", "Bind Mailbox (${(item as Mailbox).email})") - (this as ItemMenuDrawerMailboxBinding).displayMailbox(item) - } - DisplayType.INVALID_MAILBOX.layout -> { - Log.d("Bind", "Bind Invalid Mailbox (${(item as Mailbox).email})") - (this as ItemInvalidMailboxBinding).displayInvalidMailbox(item) - } - DisplayType.FOLDER.layout -> { - Log.d("Bind", "Bind Folder : ${(item as Folder).name}") - (this as ItemMenuDrawerFolderBinding).displayFolder(item) - } - DisplayType.CUSTOM_FOLDERS_HEADER.layout -> { - Log.d("Bind", "Bind Folders header") - (this as ItemMenuDrawerCustomFoldersHeaderBinding).displayCustomFoldersHeader() - } - DisplayType.MENU_DRAWER_FOOTER.layout -> { - Log.d("Bind", "Bind Footer") - (this as ItemMenuDrawerFooterBinding).displayFooter(item as MenuDrawerFooter) - } - } - } - - private fun ItemMenuDrawerMailboxesHeaderBinding.displayMailboxesHeader(header: MailboxesHeader) = with(header) { - mailboxSwitcherText.text = mailbox?.email - - mailboxSwitcher.apply { - isClickable = hasMoreThanOneMailbox - isFocusable = hasMoreThanOneMailbox - } - - mailboxExpandButton.isVisible = hasMoreThanOneMailbox - - setMailboxSwitcherTextAppearance(isExpanded) - - root.setOnClickListener { onMailboxesHeaderClicked() } - } - - private fun ItemMenuDrawerMailboxesHeaderBinding.updateCollapseState(header: MailboxesHeader) = with(header) { - mailboxExpandButton.toggleChevron(!isExpanded) - setMailboxSwitcherTextAppearance(isExpanded) - } - - private fun ItemMenuDrawerMailboxesHeaderBinding.setMailboxSwitcherTextAppearance(isOpen: Boolean) { - mailboxSwitcherText.setTextAppearance(if (isOpen) R.style.BodyMedium_Accent else R.style.BodyMedium) - } - - private fun ItemMenuDrawerMailboxBinding.displayMailbox(mailbox: Mailbox) = with(root) { - text = mailbox.email - unreadCount = mailbox.unreadCountDisplay.count - isPastilleDisplayed = mailbox.unreadCountDisplay.shouldDisplayPastille - - setOnClickListener { - context.trackMenuDrawerEvent(MatomoMail.SWITCH_MAILBOX_NAME) - onValidMailboxClicked(mailbox.mailboxId) - } - } - - private fun ItemInvalidMailboxBinding.displayInvalidMailbox(mailbox: Mailbox) = with(root) { - text = mailbox.email - itemStyle = SelectionStyle.MENU_DRAWER - isPasswordOutdated = !mailbox.isPasswordValid - isMailboxLocked = mailbox.isLocked - hasNoValidMailboxes = false - - computeEndIconVisibility() - - initSetOnClickListener( - onLockedMailboxClicked = { onLockedMailboxClicked(mailbox.email) }, - onInvalidPasswordMailboxClicked = { onInvalidPasswordMailboxClicked(mailbox) }, - ) - } - - private fun ItemMenuDrawerFolderBinding.displayFolder(folder: Folder) = with(root) { - - val unread = when (folder.role) { - FolderRole.DRAFT -> UnreadDisplay(folder.threads.count()) - FolderRole.SENT, FolderRole.TRASH -> UnreadDisplay(0) - else -> folder.unreadCountDisplay - } - - folder.role?.let { - setFolderUi(folder, it.folderIconRes, unread, it.matomoValue) - } ?: run { - val indentLevel = folder.path.split(folder.separator).size - 1 - setFolderUi( - folder = folder, - iconId = if (folder.isFavorite) R.drawable.ic_folder_star else R.drawable.ic_folder, - unread = unread, - trackerName = "customFolder", - trackerValue = indentLevel.toFloat(), - folderIndent = min(indentLevel, MAX_SUB_FOLDERS_INDENT), + MailboxesHeaderItem.viewType -> MailboxesHeaderItem.display( + item = item, + binding = this, + onMailboxesHeaderClicked = onMailboxesHeaderClicked, + ) + MailboxItem.viewType -> MailboxItem.display( + item = item, + binding = this, + onValidMailboxClicked = onValidMailboxClicked, + ) + InvalidMailboxItem.viewType -> InvalidMailboxItem.display( + item = item, + binding = this, + onLockedMailboxClicked = onLockedMailboxClicked, + onInvalidPasswordMailboxClicked = onInvalidPasswordMailboxClicked, + ) + FolderItem.viewType -> FolderItem.display( + item = item, + binding = this, + currentFolderId = currentFolderId, + hasCollapsableDefaultFolder = hasCollapsableDefaultFolder, + hasCollapsableCustomFolder = hasCollapsableCustomFolder, + onFolderClicked = onFolderClicked, + onCollapseChildrenClicked = onCollapseChildrenClicked, + ) + FoldersHeaderItem.viewType -> FoldersHeaderItem.display( + binding = this, + onCustomFoldersHeaderClicked = onCustomFoldersHeaderClicked, + onCreateFolderClicked = onCreateFolderClicked, + ) + FooterItem.viewType -> FooterItem.display( + item = item, + binding = this, + onSyncAutoConfigClicked = onSyncAutoConfigClicked, + onImportMailsClicked = onImportMailsClicked, + onRestoreMailsClicked = onRestoreMailsClicked, + onFeedbackClicked = onFeedbackClicked, + onHelpClicked = onHelpClicked, + onAppVersionClicked = onAppVersionClicked, ) - } - } - - private fun SelectableItemView.setFolderUi( - folder: Folder, - @DrawableRes iconId: Int, - unread: UnreadDisplay?, - trackerName: String, - trackerValue: Float? = null, - folderIndent: Int = 0, - ) { - val folderName = folder.getLocalizedName(context) - - text = folderName - icon = AppCompatResources.getDrawable(context, iconId) - setSelectedState(folder.id == currentFolderId) - - when (this) { - is SelectableFolderItemView -> setIndent(folderIndent) - is UnreadFolderItemView -> { - initOnCollapsableClickListener { onCollapseChildrenClicked(folder.id, isCollapsed) } - isPastilleDisplayed = unread?.shouldDisplayPastille ?: false - unreadCount = unread?.count ?: 0 - isCollapsed = folder.isCollapsed - canBeCollapsed = folder.canBeCollapsed - val hasCollapsableFolder = if (folder.role == null) hasCollapsableCustomFolder else hasCollapsableDefaultFolder - setIndent( - indent = folderIndent, - hasCollapsableFolder = hasCollapsableFolder, - canBeCollapsed = canBeCollapsed, - ) - setCollapsingButtonContentDescription(folderName) - } - is SelectableMailboxItemView, is UnreadItemView -> { - error("`${this::class.simpleName}` cannot exists here. Only Folder classes are allowed") - } - } - - setOnClickListener { - context.trackMenuDrawerEvent(trackerName, value = trackerValue) - onFolderClicked.invoke(folder.id) - } - } - - private fun ItemMenuDrawerCustomFoldersHeaderBinding.displayCustomFoldersHeader() = with(root) { - setOnClickListener { onCustomFoldersHeaderClicked(isCollapsed) } - setOnActionClickListener { onCreateFolderClicked() } - } - - private fun ItemMenuDrawerFooterBinding.displayFooter(footer: MenuDrawerFooter) { - - // Actions header - advancedActions.setOnClickListener { - context.trackMenuDrawerEvent("advancedActions", value = (!advancedActions.isCollapsed).toFloat()) - advancedActionsLayout.isGone = advancedActions.isCollapsed - } - - // Calendar & contacts sync - syncAutoConfig.setOnClickListener { onSyncAutoConfigClicked() } - - // Import mails - importMails.setOnClickListener { onImportMailsClicked() } - - // Restore mails - restoreMails.apply { - isVisible = footer.permissions?.canRestoreEmails == true - setOnClickListener { onRestoreMailsClicked() } - } - - // Feedback - feedback.setOnClickListener { onFeedbackClicked() } - - // Help - help.setOnClickListener { onHelpClicked() } - - // Quotas - val isLimited = footer.quotas != null - storageLayout.isVisible = isLimited - storageDivider.isVisible = isLimited - if (isLimited) { - storageText.text = footer.quotas!!.getText(context) - storageIndicator.progress = footer.quotas.getProgress() - } - - // App version - appVersionName.apply { - text = "App version ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" - setOnClickListener { onAppVersionClicked() } } } class MenuDrawerViewHolder(val binding: ViewBinding) : ViewHolder(binding.root) - private enum class DisplayType(val layout: Int) { - MAILBOXES_HEADER(R.layout.item_menu_drawer_mailboxes_header), - MAILBOX(R.layout.item_menu_drawer_mailbox), - INVALID_MAILBOX(R.layout.item_invalid_mailbox), - FOLDER(R.layout.item_menu_drawer_folder), - CUSTOM_FOLDERS_HEADER(R.layout.view_menu_drawer_dropdown), - EMPTY_CUSTOM_FOLDERS(R.layout.item_menu_drawer_empty_custom_folders), - MENU_DRAWER_FOOTER(R.layout.item_menu_drawer_footer), - DIVIDER(R.layout.item_menu_drawer_divider), - } - - private data class MailboxesHeader(val mailbox: Mailbox?, val hasMoreThanOneMailbox: Boolean, val isExpanded: Boolean) - - private data class MenuDrawerFooter(val permissions: MailboxPermissions?, val quotas: Quotas?) - private enum class ItemType { CUSTOM_FOLDERS_HEADER, EMPTY_CUSTOM_FOLDERS, @@ -468,7 +290,7 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter() { @@ -517,8 +339,4 @@ class MenuDrawerAdapter @Inject constructor() : ListAdapter. + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.R +import com.infomaniak.mail.databinding.ItemMenuDrawerDividerBinding + +object DividerItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_menu_drawer_divider + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerDividerBinding.inflate(inflater, parent, false) + } +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/EmptyFoldersItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/EmptyFoldersItem.kt new file mode 100644 index 0000000000..fe7219a283 --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/EmptyFoldersItem.kt @@ -0,0 +1,34 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.R +import com.infomaniak.mail.databinding.ItemMenuDrawerEmptyCustomFoldersBinding + +object EmptyFoldersItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_menu_drawer_empty_custom_folders + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerEmptyCustomFoldersBinding.inflate(inflater, parent, false) + } +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FolderItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FolderItem.kt new file mode 100644 index 0000000000..13a422e0f9 --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FolderItem.kt @@ -0,0 +1,179 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.DrawableRes +import androidx.appcompat.content.res.AppCompatResources +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.MatomoMail.trackMenuDrawerEvent +import com.infomaniak.mail.R +import com.infomaniak.mail.data.models.Folder +import com.infomaniak.mail.databinding.ItemMenuDrawerFolderBinding +import com.infomaniak.mail.utils.UnreadDisplay +import com.infomaniak.mail.views.itemViews.* +import kotlin.math.min + +object FolderItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_menu_drawer_folder + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerFolderBinding.inflate(inflater, parent, false) + } + + fun display( + item: Any, + binding: ViewBinding, + currentFolderId: String?, + hasCollapsableDefaultFolder: Boolean, + hasCollapsableCustomFolder: Boolean, + onFolderClicked: (folderId: String) -> Unit, + onCollapseChildrenClicked: (folderId: String, shouldCollapse: Boolean) -> Unit, + ) { + item as Folder + binding as ItemMenuDrawerFolderBinding + + Log.d("Bind", "Bind Folder : ${item.name}") + binding.displayFolder( + item, + currentFolderId, + hasCollapsableDefaultFolder, + hasCollapsableCustomFolder, + onFolderClicked, + onCollapseChildrenClicked, + ) + } + + fun displayWithPayload( + item: Any, + binding: ViewBinding, + currentFolderId: String?, + hasCollapsableDefaultFolder: Boolean, + hasCollapsableCustomFolder: Boolean, + onFolderClicked: (folderId: String) -> Unit, + onCollapseChildrenClicked: (folderId: String, shouldCollapse: Boolean) -> Unit, + ) { + item as Folder + binding as ItemMenuDrawerFolderBinding + + Log.d("Bind", "Bind Custom folders because of collapse change = ${item.name}") + binding.displayFolder( + item, + currentFolderId, + hasCollapsableDefaultFolder, + hasCollapsableCustomFolder, + onFolderClicked, + onCollapseChildrenClicked, + ) + } + + private fun ItemMenuDrawerFolderBinding.displayFolder( + folder: Folder, + currentFolderId: String?, + hasCollapsableDefaultFolder: Boolean, + hasCollapsableCustomFolder: Boolean, + onFolderClicked: (folderId: String) -> Unit, + onCollapseChildrenClicked: (folderId: String, shouldCollapse: Boolean) -> Unit, + ) = with(root) { + + val unread = when (folder.role) { + Folder.FolderRole.DRAFT -> UnreadDisplay(folder.threads.count()) + Folder.FolderRole.SENT, Folder.FolderRole.TRASH -> UnreadDisplay(0) + else -> folder.unreadCountDisplay + } + + folder.role?.let { + setFolderUi( + folder = folder, + iconId = it.folderIconRes, + unread = unread, + currentFolderId = currentFolderId, + hasCollapsableDefaultFolder = hasCollapsableDefaultFolder, + hasCollapsableCustomFolder = hasCollapsableCustomFolder, + onFolderClicked = onFolderClicked, + onCollapseChildrenClicked = onCollapseChildrenClicked, + trackerName = it.matomoValue, + ) + } ?: run { + val indentLevel = folder.path.split(folder.separator).size - 1 + setFolderUi( + folder = folder, + iconId = if (folder.isFavorite) R.drawable.ic_folder_star else R.drawable.ic_folder, + unread = unread, + currentFolderId = currentFolderId, + hasCollapsableDefaultFolder = hasCollapsableDefaultFolder, + hasCollapsableCustomFolder = hasCollapsableCustomFolder, + onFolderClicked = onFolderClicked, + onCollapseChildrenClicked = onCollapseChildrenClicked, + trackerName = "customFolder", + trackerValue = indentLevel.toFloat(), + folderIndent = min(indentLevel, Folder.MAX_SUB_FOLDERS_INDENT), + ) + } + } + + private fun SelectableItemView.setFolderUi( + folder: Folder, + @DrawableRes iconId: Int, + unread: UnreadDisplay?, + currentFolderId: String?, + hasCollapsableDefaultFolder: Boolean, + hasCollapsableCustomFolder: Boolean, + onFolderClicked: (folderId: String) -> Unit, + onCollapseChildrenClicked: (folderId: String, shouldCollapse: Boolean) -> Unit, + trackerName: String, + trackerValue: Float? = null, + folderIndent: Int = 0, + ) { + val folderName = folder.getLocalizedName(context) + + text = folderName + icon = AppCompatResources.getDrawable(context, iconId) + setSelectedState(folder.id == currentFolderId) + + when (this) { + is SelectableFolderItemView -> setIndent(folderIndent) + is UnreadFolderItemView -> { + initOnCollapsableClickListener { onCollapseChildrenClicked(folder.id, isCollapsed) } + isPastilleDisplayed = unread?.shouldDisplayPastille ?: false + unreadCount = unread?.count ?: 0 + isCollapsed = folder.isCollapsed + canBeCollapsed = folder.canBeCollapsed + val hasCollapsableFolder = if (folder.role == null) hasCollapsableCustomFolder else hasCollapsableDefaultFolder + setIndent( + indent = folderIndent, + hasCollapsableFolder = hasCollapsableFolder, + canBeCollapsed = canBeCollapsed, + ) + setCollapsingButtonContentDescription(folderName) + } + is SelectableMailboxItemView, is UnreadItemView -> { + error("`${this::class.simpleName}` cannot exists here. Only Folder classes are allowed") + } + } + + setOnClickListener { + context.trackMenuDrawerEvent(trackerName, value = trackerValue) + onFolderClicked.invoke(folder.id) + } + } +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FoldersHeaderItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FoldersHeaderItem.kt new file mode 100644 index 0000000000..6e4cef04ac --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FoldersHeaderItem.kt @@ -0,0 +1,54 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.R +import com.infomaniak.mail.databinding.ItemMenuDrawerCustomFoldersHeaderBinding + +object FoldersHeaderItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.view_menu_drawer_dropdown + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerCustomFoldersHeaderBinding.inflate(inflater, parent, false) + } + + fun display( + binding: ViewBinding, + onCustomFoldersHeaderClicked: (Boolean) -> Unit, + onCreateFolderClicked: () -> Unit, + ) { + binding as ItemMenuDrawerCustomFoldersHeaderBinding + + Log.d("Bind", "Bind Custom Folders header") + binding.displayCustomFoldersHeader(onCustomFoldersHeaderClicked, onCreateFolderClicked) + } + + private fun ItemMenuDrawerCustomFoldersHeaderBinding.displayCustomFoldersHeader( + onCustomFoldersHeaderClicked: (Boolean) -> Unit, + onCreateFolderClicked: () -> Unit, + ) = with(root) { + setOnClickListener { onCustomFoldersHeaderClicked(isCollapsed) } + setOnActionClickListener { onCreateFolderClicked() } + } +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FooterItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FooterItem.kt new file mode 100644 index 0000000000..47bb888af8 --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/FooterItem.kt @@ -0,0 +1,120 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.viewbinding.ViewBinding +import com.infomaniak.lib.core.utils.context +import com.infomaniak.mail.BuildConfig +import com.infomaniak.mail.MatomoMail.toFloat +import com.infomaniak.mail.MatomoMail.trackMenuDrawerEvent +import com.infomaniak.mail.R +import com.infomaniak.mail.data.models.Quotas +import com.infomaniak.mail.data.models.mailbox.MailboxPermissions +import com.infomaniak.mail.databinding.ItemMenuDrawerFooterBinding + +object FooterItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_menu_drawer_footer + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerFooterBinding.inflate(inflater, parent, false) + } + + fun display( + item: Any, + binding: ViewBinding, + onSyncAutoConfigClicked: () -> Unit, + onImportMailsClicked: () -> Unit, + onRestoreMailsClicked: () -> Unit, + onFeedbackClicked: () -> Unit, + onHelpClicked: () -> Unit, + onAppVersionClicked: () -> Unit, + ) { + item as MenuDrawerFooter + binding as ItemMenuDrawerFooterBinding + + Log.d("Bind", "Bind Footer") + binding.displayFooter( + item, + onSyncAutoConfigClicked, + onImportMailsClicked, + onRestoreMailsClicked, + onFeedbackClicked, + onHelpClicked, + onAppVersionClicked, + ) + } + + private fun ItemMenuDrawerFooterBinding.displayFooter( + footer: MenuDrawerFooter, + onSyncAutoConfigClicked: () -> Unit, + onImportMailsClicked: () -> Unit, + onRestoreMailsClicked: () -> Unit, + onFeedbackClicked: () -> Unit, + onHelpClicked: () -> Unit, + onAppVersionClicked: () -> Unit, + ) { + + // Actions header + advancedActions.setOnClickListener { + context.trackMenuDrawerEvent("advancedActions", value = (!advancedActions.isCollapsed).toFloat()) + advancedActionsLayout.isGone = advancedActions.isCollapsed + } + + // Calendar & contacts sync + syncAutoConfig.setOnClickListener { onSyncAutoConfigClicked() } + + // Import mails + importMails.setOnClickListener { onImportMailsClicked() } + + // Restore mails + restoreMails.apply { + isVisible = footer.permissions?.canRestoreEmails == true + setOnClickListener { onRestoreMailsClicked() } + } + + // Feedback + feedback.setOnClickListener { onFeedbackClicked() } + + // Help + help.setOnClickListener { onHelpClicked() } + + // Quotas + val isLimited = footer.quotas != null + storageLayout.isVisible = isLimited + storageDivider.isVisible = isLimited + if (isLimited) { + storageText.text = footer.quotas!!.getText(context) + storageIndicator.progress = footer.quotas.getProgress() + } + + // App version + appVersionName.apply { + text = "App version ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" + setOnClickListener { onAppVersionClicked() } + } + } + + data class MenuDrawerFooter(val permissions: MailboxPermissions?, val quotas: Quotas?) +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/InvalidMailboxItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/InvalidMailboxItem.kt new file mode 100644 index 0000000000..aaf0306267 --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/InvalidMailboxItem.kt @@ -0,0 +1,69 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.R +import com.infomaniak.mail.data.models.mailbox.Mailbox +import com.infomaniak.mail.databinding.ItemInvalidMailboxBinding +import com.infomaniak.mail.views.itemViews.DecoratedItemView + +object InvalidMailboxItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_invalid_mailbox + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemInvalidMailboxBinding.inflate(inflater, parent, false) + } + + fun display( + item: Any, + binding: ViewBinding, + onLockedMailboxClicked: (String) -> Unit, + onInvalidPasswordMailboxClicked: (Mailbox) -> Unit, + ) { + item as Mailbox + binding as ItemInvalidMailboxBinding + + Log.d("Bind", "Bind Invalid Mailbox (${item.email})") + binding.displayInvalidMailbox(item,onLockedMailboxClicked, onInvalidPasswordMailboxClicked) + } + + private fun ItemInvalidMailboxBinding.displayInvalidMailbox( + mailbox: Mailbox, + onLockedMailboxClicked: (String) -> Unit, + onInvalidPasswordMailboxClicked: (Mailbox) -> Unit, + ) = with(root) { + text = mailbox.email + itemStyle = DecoratedItemView.SelectionStyle.MENU_DRAWER + isPasswordOutdated = !mailbox.isPasswordValid + isMailboxLocked = mailbox.isLocked + hasNoValidMailboxes = false + + computeEndIconVisibility() + + initSetOnClickListener( + onLockedMailboxClicked = { onLockedMailboxClicked(mailbox.email) }, + onInvalidPasswordMailboxClicked = { onInvalidPasswordMailboxClicked(mailbox) }, + ) + } +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxItem.kt new file mode 100644 index 0000000000..92e4bbf3d5 --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxItem.kt @@ -0,0 +1,64 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.MatomoMail +import com.infomaniak.mail.MatomoMail.trackMenuDrawerEvent +import com.infomaniak.mail.R +import com.infomaniak.mail.data.models.mailbox.Mailbox +import com.infomaniak.mail.databinding.ItemMenuDrawerMailboxBinding + +object MailboxItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_menu_drawer_mailbox + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerMailboxBinding.inflate(inflater, parent, false) + } + + fun display( + item: Any, + binding: ViewBinding, + onValidMailboxClicked: (Int) -> Unit, + ) { + item as Mailbox + binding as ItemMenuDrawerMailboxBinding + + Log.d("Bind", "Bind Mailbox (${item.email})") + binding.displayMailbox(item, onValidMailboxClicked) + } + + private fun ItemMenuDrawerMailboxBinding.displayMailbox( + mailbox: Mailbox, + onValidMailboxClicked: (Int) -> Unit, + ) = with(root) { + text = mailbox.email + unreadCount = mailbox.unreadCountDisplay.count + isPastilleDisplayed = mailbox.unreadCountDisplay.shouldDisplayPastille + + setOnClickListener { + context.trackMenuDrawerEvent(MatomoMail.SWITCH_MAILBOX_NAME) + onValidMailboxClicked(mailbox.mailboxId) + } + } +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxesHeaderItem.kt b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxesHeaderItem.kt new file mode 100644 index 0000000000..396a22d8bf --- /dev/null +++ b/app/src/main/java/com/infomaniak/mail/ui/main/menuDrawer/items/MailboxesHeaderItem.kt @@ -0,0 +1,90 @@ +/* + * Infomaniak Mail - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.mail.ui.main.menuDrawer.items + +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.viewbinding.ViewBinding +import com.infomaniak.mail.R +import com.infomaniak.mail.data.models.mailbox.Mailbox +import com.infomaniak.mail.databinding.ItemMenuDrawerMailboxesHeaderBinding +import com.infomaniak.mail.utils.extensions.toggleChevron + +object MailboxesHeaderItem { + + @Suppress("MayBeConstant") + val viewType = R.layout.item_menu_drawer_mailboxes_header + + fun binding(inflater: LayoutInflater, parent: ViewGroup): ViewBinding { + return ItemMenuDrawerMailboxesHeaderBinding.inflate(inflater, parent, false) + } + + fun display( + item: Any, + binding: ViewBinding, + onMailboxesHeaderClicked: () -> Unit, + ) { + item as MailboxesHeader + binding as ItemMenuDrawerMailboxesHeaderBinding + + Log.d("Bind", "Bind Mailboxes header") + binding.displayMailboxesHeader(item, onMailboxesHeaderClicked) + } + + fun displayWithPayload( + item: Any, + binding: ViewBinding, + ) { + item as MailboxesHeader + binding as ItemMenuDrawerMailboxesHeaderBinding + + Log.d("Bind", "Bind Mailboxes header because of collapse change") + binding.updateCollapseState(item) + } + + private fun ItemMenuDrawerMailboxesHeaderBinding.displayMailboxesHeader( + header: MailboxesHeader, + onMailboxesHeaderClicked: () -> Unit, + ) = with(header) { + mailboxSwitcherText.text = mailbox?.email + + mailboxSwitcher.apply { + isClickable = hasMoreThanOneMailbox + isFocusable = hasMoreThanOneMailbox + } + + mailboxExpandButton.isVisible = hasMoreThanOneMailbox + + setMailboxSwitcherTextAppearance(isExpanded) + + root.setOnClickListener { onMailboxesHeaderClicked() } + } + + private fun ItemMenuDrawerMailboxesHeaderBinding.updateCollapseState(header: MailboxesHeader) = with(header) { + mailboxExpandButton.toggleChevron(!isExpanded) + setMailboxSwitcherTextAppearance(isExpanded) + } + + private fun ItemMenuDrawerMailboxesHeaderBinding.setMailboxSwitcherTextAppearance(isOpen: Boolean) { + mailboxSwitcherText.setTextAppearance(if (isOpen) R.style.BodyMedium_Accent else R.style.BodyMedium) + } + + data class MailboxesHeader(val mailbox: Mailbox?, val hasMoreThanOneMailbox: Boolean, val isExpanded: Boolean) +} diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/move/MoveAdapter.kt b/app/src/main/java/com/infomaniak/mail/ui/main/move/MoveAdapter.kt index ff4da80e36..78c82b039b 100644 --- a/app/src/main/java/com/infomaniak/mail/ui/main/move/MoveAdapter.kt +++ b/app/src/main/java/com/infomaniak/mail/ui/main/move/MoveAdapter.kt @@ -88,7 +88,7 @@ class MoveAdapter @Inject constructor() : ListAdapter( setFolderUi( folder = folder, iconId = if (folder.isFavorite) R.drawable.ic_folder_star else R.drawable.ic_folder, - folderIndent = min(indentLevel, MAX_SUB_FOLDERS_INDENT), + folderIndent = min(indentLevel, Folder.MAX_SUB_FOLDERS_INDENT), ) } } @@ -102,10 +102,6 @@ class MoveAdapter @Inject constructor() : ListAdapter( setOnClickListener { onFolderClicked.invoke(folder.id) } } - companion object { - private const val MAX_SUB_FOLDERS_INDENT = 2 - } - class FolderViewHolder(val binding: ViewBinding) : ViewHolder(binding.root) private class FolderDiffCallback : DiffUtil.ItemCallback() {