From d0db96d48693fc6da0d39d4966a0693ebf1ceaa2 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Wed, 6 Sep 2023 14:17:13 +0200 Subject: [PATCH 1/2] Move editor and external bottom bars from NewMessageActivity to NewMessageFragment --- .../ui/main/newMessage/NewMessageActivity.kt | 154 +------------ .../ui/main/newMessage/NewMessageFragment.kt | 156 ++++++++++++- .../ui/main/newMessage/NewMessageViewModel.kt | 4 +- .../main/res/layout/activity_new_message.xml | 204 ----------------- .../main/res/layout/fragment_new_message.xml | 209 +++++++++++++++++- 5 files changed, 365 insertions(+), 362 deletions(-) diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageActivity.kt b/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageActivity.kt index 5541be34b7..98e3422092 100644 --- a/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageActivity.kt +++ b/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageActivity.kt @@ -18,28 +18,18 @@ package com.infomaniak.mail.ui.main.newMessage import android.content.Intent -import android.content.res.ColorStateList import android.os.Bundle import android.webkit.WebView import androidx.activity.viewModels -import androidx.core.view.isGone -import androidx.core.view.isVisible -import com.google.android.material.button.MaterialButton import com.infomaniak.mail.BuildConfig -import com.infomaniak.mail.MatomoMail.ACTION_POSTPONE_NAME -import com.infomaniak.mail.MatomoMail.trackEvent -import com.infomaniak.mail.MatomoMail.trackExternalEvent -import com.infomaniak.mail.MatomoMail.trackNewMessageEvent import com.infomaniak.mail.R import com.infomaniak.mail.data.models.AppSettings -import com.infomaniak.mail.data.models.draft.Draft.DraftAction import com.infomaniak.mail.databinding.ActivityNewMessageBinding import com.infomaniak.mail.ui.BaseActivity import com.infomaniak.mail.ui.LaunchActivity -import com.infomaniak.mail.ui.MainActivity -import com.infomaniak.mail.utils.* +import com.infomaniak.mail.utils.AccountUtils +import com.infomaniak.mail.utils.updateNavigationBarColor import dagger.hilt.android.AndroidEntryPoint -import com.google.android.material.R as RMaterial @AndroidEntryPoint class NewMessageActivity : BaseActivity() { @@ -59,47 +49,7 @@ class NewMessageActivity : BaseActivity() { } setupSnackBar() - setupSendButton() setupSystemBars() - setupExternalBanner() - - observeInitSuccess() - } - - private fun setupExternalBanner() = with(binding) { - var manuallyClosed = false - - var externalRecipientEmail: String? = null - var externalRecipientQuantity = 0 - - closeButton.setOnClickListener { - trackExternalEvent("bannerManuallyClosed") - manuallyClosed = true - externalBanner.isGone = true - } - - informationButton.setOnClickListener { - trackExternalEvent("bannerInfo") - - val description = resources.getQuantityString( - R.plurals.externalDialogDescriptionRecipient, - externalRecipientQuantity, - externalRecipientEmail, - ) - - // TODO: Reuse instance - createInformationDialog( - title = getString(R.string.externalDialogTitleRecipient), - description = description, - confirmButtonText = R.string.externalDialogConfirmButton, - ).show() - } - - newMessageViewModel.externalRecipientCount.observe(this@NewMessageActivity) { (email, externalQuantity) -> - externalBanner.isGone = manuallyClosed || externalQuantity == 0 - externalRecipientEmail = email - externalRecipientQuantity = externalQuantity - } } private fun isAuth(): Boolean { @@ -110,52 +60,10 @@ class NewMessageActivity : BaseActivity() { return true } - fun finishAppAndRemoveTaskIfNeeded() { - if (isTaskRoot) finishAndRemoveTask() else finish() - } - private fun setupSnackBar() { newMessageViewModel.snackBarManager.setup(view = binding.root, activity = this) } - private fun setupSendButton() = with(binding) { - newMessageViewModel.isSendingAllowed.observe(this@NewMessageActivity) { - sendButton.isEnabled = it - } - - sendButton.setOnClickListener { tryToSendEmail() } - } - - private fun tryToSendEmail() { - - fun setSnackBarActivityResult() { - val resultIntent = Intent() - resultIntent.putExtra(MainActivity.DRAFT_ACTION_KEY, DraftAction.SEND.name) - setResult(RESULT_OK, resultIntent) - } - - fun sendEmail() { - newMessageViewModel.shouldSendInsteadOfSave = true - setSnackBarActivityResult() - finishAppAndRemoveTaskIfNeeded() - } - - if (newMessageViewModel.draft.subject.isNullOrBlank()) { - trackNewMessageEvent("sendWithoutSubject") - createDescriptionDialog( - title = getString(R.string.emailWithoutSubjectTitle), - description = getString(R.string.emailWithoutSubjectDescription), - confirmButtonText = R.string.buttonContinue, - onPositiveButtonClicked = { - trackNewMessageEvent("sendWithoutSubjectConfirm") - sendEmail() - }, - ).show() - } else { - sendEmail() - } - } - private fun setupSystemBars() { val backgroundColor = getColor(R.color.newMessageBackgroundColor) window.apply { @@ -163,62 +71,4 @@ class NewMessageActivity : BaseActivity() { updateNavigationBarColor(backgroundColor) } } - - private fun observeInitSuccess() { - newMessageViewModel.isInitSuccess.observe(this) { isSuccess -> - if (isSuccess) { - setupEditorActions() - setupEditorFormatActionsToggle() - } - } - } - - private fun setupEditorActions() = with(binding) { - - fun linkEditor(view: MaterialButton, action: EditorAction) { - view.setOnClickListener { - // TODO: Don't forget to add in this `if` all actions that make the app go to background. - if (action == EditorAction.ATTACHMENT) newMessageViewModel.shouldExecuteDraftActionWhenStopping = false - trackEvent("editorActions", action.matomoValue) - newMessageViewModel.editorAction.value = action to null - } - } - - linkEditor(editorAttachment, EditorAction.ATTACHMENT) - linkEditor(editorCamera, EditorAction.CAMERA) - linkEditor(editorLink, EditorAction.LINK) - linkEditor(editorClock, EditorAction.CLOCK) - } - - private fun setupEditorFormatActionsToggle() = with(binding) { - editorTextOptions.setOnClickListener { - newMessageViewModel.isEditorExpanded = !newMessageViewModel.isEditorExpanded - updateEditorVisibility(newMessageViewModel.isEditorExpanded) - } - } - - private fun updateEditorVisibility(isEditorExpanded: Boolean) = with(binding) { - val color = if (isEditorExpanded) getAttributeColor(RMaterial.attr.colorPrimary) else getColor(R.color.iconColor) - val resId = if (isEditorExpanded) R.string.buttonTextOptionsClose else R.string.buttonTextOptionsOpen - - editorTextOptions.apply { - iconTint = ColorStateList.valueOf(color) - contentDescription = getString(resId) - } - - editorActions.isGone = isEditorExpanded - textEditing.isVisible = isEditorExpanded - } - - enum class EditorAction(val matomoValue: String) { - ATTACHMENT("importFile"), - CAMERA("importFromCamera"), - LINK("addLink"), - CLOCK(ACTION_POSTPONE_NAME), - // BOLD("bold"), - // ITALIC("italic"), - // UNDERLINE("underline"), - // STRIKE_THROUGH("strikeThrough"), - // UNORDERED_LIST("unorderedList"), - } } diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageFragment.kt b/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageFragment.kt index 3aee24d4d8..2dd04be189 100644 --- a/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageFragment.kt +++ b/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageFragment.kt @@ -18,8 +18,10 @@ package com.infomaniak.mail.ui.main.newMessage import android.annotation.SuppressLint +import android.app.Activity import android.content.ClipDescription import android.content.Intent +import android.content.res.ColorStateList import android.content.res.Configuration import android.net.Uri import android.os.Bundle @@ -36,6 +38,7 @@ import android.webkit.WebView import android.widget.ListPopupWindow import android.widget.PopupWindow import androidx.activity.addCallback +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.content.res.AppCompatResources import androidx.constraintlayout.widget.Group import androidx.core.net.MailTo @@ -47,8 +50,12 @@ import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature +import com.google.android.material.button.MaterialButton import com.infomaniak.lib.core.utils.* import com.infomaniak.lib.core.utils.SnackbarUtils.showSnackbar +import com.infomaniak.mail.MatomoMail +import com.infomaniak.mail.MatomoMail.trackEvent +import com.infomaniak.mail.MatomoMail.trackExternalEvent import com.infomaniak.mail.MatomoMail.trackNewMessageEvent import com.infomaniak.mail.R import com.infomaniak.mail.data.LocalSettings @@ -59,7 +66,7 @@ import com.infomaniak.mail.data.models.correspondent.Recipient import com.infomaniak.mail.data.models.draft.Draft.* import com.infomaniak.mail.data.models.signature.Signature import com.infomaniak.mail.databinding.FragmentNewMessageBinding -import com.infomaniak.mail.ui.main.newMessage.NewMessageActivity.EditorAction +import com.infomaniak.mail.ui.MainActivity import com.infomaniak.mail.ui.main.newMessage.NewMessageFragment.FieldType.* import com.infomaniak.mail.ui.main.newMessage.NewMessageViewModel.ImportationResult import com.infomaniak.mail.ui.main.thread.AttachmentAdapter @@ -72,6 +79,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.* import java.util.UUID import javax.inject.Inject +import com.google.android.material.R as RMaterial @AndroidEntryPoint class NewMessageFragment : Fragment() { @@ -136,6 +144,7 @@ class NewMessageFragment : Fragment() { observeNewAttachments() observeCcAndBccVisibility() observeDraftWorkerResults() + observeInitSuccess() } override fun onStart() { @@ -191,6 +200,9 @@ class NewMessageFragment : Fragment() { } }) } + + setupSendButton() + setupExternalBanner() } private fun initDraftAndViewModel() { @@ -576,7 +588,7 @@ class NewMessageFragment : Fragment() { } private fun observeEditorActions() { - newMessageViewModel.editorAction.observe(requireActivity()) { (editorAction, /*isToggled*/ _) -> + newMessageViewModel.editorAction.observe(viewLifecycleOwner) { (editorAction, /*isToggled*/ _) -> when (editorAction) { EditorAction.ATTACHMENT -> { filePicker.open { uris -> @@ -665,6 +677,146 @@ class NewMessageFragment : Fragment() { draft.attachments.removeAt(position) } + private fun setupExternalBanner() = with(binding) { + var manuallyClosed = false + + var externalRecipientEmail: String? = null + var externalRecipientQuantity = 0 + + closeButton.setOnClickListener { + trackExternalEvent("bannerManuallyClosed") + manuallyClosed = true + externalBanner.isGone = true + } + + informationButton.setOnClickListener { + trackExternalEvent("bannerInfo") + + val description = resources.getQuantityString( + R.plurals.externalDialogDescriptionRecipient, + externalRecipientQuantity, + externalRecipientEmail, + ) + + // TODO: Reuse instance + createInformationDialog( + title = getString(R.string.externalDialogTitleRecipient), + description = description, + confirmButtonText = R.string.externalDialogConfirmButton, + ).show() + } + + newMessageViewModel.externalRecipientCount.observe(viewLifecycleOwner) { (email, externalQuantity) -> + externalBanner.isGone = manuallyClosed || externalQuantity == 0 + externalRecipientEmail = email + externalRecipientQuantity = externalQuantity + } + } + + private fun setupSendButton() = with(binding) { + newMessageViewModel.isSendingAllowed.observe(viewLifecycleOwner) { + sendButton.isEnabled = it + } + + sendButton.setOnClickListener { tryToSendEmail() } + } + + private fun tryToSendEmail() { + + fun setSnackBarActivityResult() { + val resultIntent = Intent() + resultIntent.putExtra(MainActivity.DRAFT_ACTION_KEY, DraftAction.SEND.name) + requireActivity().setResult(AppCompatActivity.RESULT_OK, resultIntent) + } + + fun sendEmail() { + newMessageViewModel.shouldSendInsteadOfSave = true + setSnackBarActivityResult() + requireActivity().finishAppAndRemoveTaskIfNeeded() + } + + if (newMessageViewModel.draft.subject.isNullOrBlank()) { + trackNewMessageEvent("sendWithoutSubject") + createDescriptionDialog( + title = getString(R.string.emailWithoutSubjectTitle), + description = getString(R.string.emailWithoutSubjectDescription), + confirmButtonText = R.string.buttonContinue, + onPositiveButtonClicked = { + trackNewMessageEvent("sendWithoutSubjectConfirm") + sendEmail() + }, + ).show() + } else { + sendEmail() + } + } + + private fun Activity.finishAppAndRemoveTaskIfNeeded() { + if (isTaskRoot) finishAndRemoveTask() else finish() + } + + private fun observeInitSuccess() { + newMessageViewModel.isInitSuccess.observe(viewLifecycleOwner) { isSuccess -> + if (isSuccess) { + setupEditorActions() + setupEditorFormatActionsToggle() + } + } + } + + private fun setupEditorActions() = with(binding) { + + fun linkEditor(view: MaterialButton, action: EditorAction) { + view.setOnClickListener { + // TODO: Don't forget to add in this `if` all actions that make the app go to background. + if (action == EditorAction.ATTACHMENT) newMessageViewModel.shouldExecuteDraftActionWhenStopping = false + trackEvent("editorActions", action.matomoValue) + newMessageViewModel.editorAction.value = action to null + } + } + + linkEditor(editorAttachment, EditorAction.ATTACHMENT) + linkEditor(editorCamera, EditorAction.CAMERA) + linkEditor(editorLink, EditorAction.LINK) + linkEditor(editorClock, EditorAction.CLOCK) + } + + private fun setupEditorFormatActionsToggle() = with(binding) { + editorTextOptions.setOnClickListener { + newMessageViewModel.isEditorExpanded = !newMessageViewModel.isEditorExpanded + updateEditorVisibility(newMessageViewModel.isEditorExpanded) + } + } + + private fun updateEditorVisibility(isEditorExpanded: Boolean) = with(binding) { + val color = if (isEditorExpanded) { + context.getAttributeColor(RMaterial.attr.colorPrimary) + } else { + context.getColor(R.color.iconColor) + } + val resId = if (isEditorExpanded) R.string.buttonTextOptionsClose else R.string.buttonTextOptionsOpen + + editorTextOptions.apply { + iconTint = ColorStateList.valueOf(color) + contentDescription = getString(resId) + } + + editorActions.isGone = isEditorExpanded + textEditing.isVisible = isEditorExpanded + } + + enum class EditorAction(val matomoValue: String) { + ATTACHMENT("importFile"), + CAMERA("importFromCamera"), + LINK("addLink"), + CLOCK(MatomoMail.ACTION_POSTPONE_NAME), + // BOLD("bold"), + // ITALIC("italic"), + // UNDERLINE("underline"), + // STRIKE_THROUGH("strikeThrough"), + // UNORDERED_LIST("unorderedList"), + } + enum class FieldType { TO, CC, diff --git a/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageViewModel.kt b/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageViewModel.kt index f92470663e..ef21d019a3 100644 --- a/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageViewModel.kt +++ b/app/src/main/java/com/infomaniak/mail/ui/main/newMessage/NewMessageViewModel.kt @@ -46,9 +46,7 @@ import com.infomaniak.mail.data.models.signature.Signature import com.infomaniak.mail.di.IoDispatcher import com.infomaniak.mail.di.MainDispatcher import com.infomaniak.mail.ui.main.SnackBarManager -import com.infomaniak.mail.ui.main.newMessage.NewMessageActivity.EditorAction -import com.infomaniak.mail.ui.main.newMessage.NewMessageFragment.CreationStatus -import com.infomaniak.mail.ui.main.newMessage.NewMessageFragment.FieldType +import com.infomaniak.mail.ui.main.newMessage.NewMessageFragment.* import com.infomaniak.mail.ui.main.newMessage.NewMessageViewModel.SignatureScore.* import com.infomaniak.mail.utils.* import com.infomaniak.mail.utils.ContactUtils.arrangeMergedContacts diff --git a/app/src/main/res/layout/activity_new_message.xml b/app/src/main/res/layout/activity_new_message.xml index 07d3ce6ae8..bde779052e 100644 --- a/app/src/main/res/layout/activity_new_message.xml +++ b/app/src/main/res/layout/activity_new_message.xml @@ -37,209 +37,5 @@ app:defaultNavHost="true" app:navGraph="@navigation/new_message_navigation" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_new_message.xml b/app/src/main/res/layout/fragment_new_message.xml index fb40c75b0c..9bba5c8fd2 100644 --- a/app/src/main/res/layout/fragment_new_message.xml +++ b/app/src/main/res/layout/fragment_new_message.xml @@ -38,7 +38,8 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 67bd019cae64289fcbe248353f9b98f0689ee8d9 Mon Sep 17 00:00:00 2001 From: Kevin Boulongne Date: Wed, 6 Sep 2023 15:50:40 +0200 Subject: [PATCH 2/2] Update ExternalRecipient text color --- app/src/main/res/layout/fragment_new_message.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/fragment_new_message.xml b/app/src/main/res/layout/fragment_new_message.xml index 9bba5c8fd2..538f581ed0 100644 --- a/app/src/main/res/layout/fragment_new_message.xml +++ b/app/src/main/res/layout/fragment_new_message.xml @@ -485,7 +485,8 @@ android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/marginStandardMedium" android:layout_weight="1" - android:text="@string/externalDialogTitleRecipient" /> + android:text="@string/externalDialogTitleRecipient" + android:textColor="@color/externalTagOnBackground" />