Added view binding to MessageDetailsActionSheet and some basic actions handling.
MAILAND-1401
This commit is contained in:
parent
7b93efad7c
commit
6dbe8ac2c3
|
@ -23,7 +23,7 @@ package ch.protonmail.android.activities.messageDetails
|
|||
* Contains types of actions executed from message details screen.
|
||||
*/
|
||||
enum class MessageDetailsAction {
|
||||
CLOSE,
|
||||
DELETE_MESSAGE,
|
||||
FORWARD,
|
||||
LABEL_AS,
|
||||
MARK_UNREAD,
|
||||
|
|
|
@ -24,11 +24,12 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import ch.protonmail.android.R
|
||||
import ch.protonmail.android.activities.messageDetails.viewmodel.MessageDetailsViewModel
|
||||
import ch.protonmail.android.databinding.FragmentMessageDetailsActionSheetBinding
|
||||
import ch.protonmail.android.databinding.LayoutMessageDetailsActionsSheetButtonsBinding
|
||||
import ch.protonmail.android.databinding.LayoutMessageDetailsActionsSheetHeaderBinding
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
|
@ -44,24 +45,17 @@ class MessageDetailsActionSheet : BottomSheetDialogFragment() {
|
|||
|
||||
private val viewModel: MessageDetailsViewModel by activityViewModels()
|
||||
|
||||
private lateinit var closeViewIcon: View
|
||||
private var _binding: FragmentMessageDetailsActionSheetBinding? = null
|
||||
private val binding get() = requireNotNull(_binding)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val rootView = inflater.inflate(R.layout.fragment_message_details_action_sheet, container, false)
|
||||
val title = arguments?.getString(EXTRA_ARG_TITLE)
|
||||
if (!title.isNullOrEmpty()) {
|
||||
rootView.findViewById<TextView>(R.id.detailsActionsTitleTextView).text = title
|
||||
}
|
||||
val subtitle = arguments?.getString(EXTRA_ARG_SUBTITLE)
|
||||
if (!subtitle.isNullOrEmpty()) {
|
||||
rootView.findViewById<TextView>(R.id.detailsActionsSubTitleTextView).text = subtitle
|
||||
}
|
||||
closeViewIcon = rootView.findViewById<TextView>(R.id.detailsActionsCloseView)
|
||||
closeViewIcon.setOnClickListener {
|
||||
viewModel.handleAction(MessageDetailsAction.CLOSE)
|
||||
dismiss()
|
||||
}
|
||||
return rootView
|
||||
_binding = FragmentMessageDetailsActionSheetBinding.inflate(inflater)
|
||||
|
||||
setupHeaderBindings(binding.includeLayoutActionSheetHeader, arguments)
|
||||
setupMainButtonsBindings(binding.includeLayoutActionSheetButtons, viewModel)
|
||||
setupOtherButtonsBindings(binding, viewModel)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
@ -76,9 +70,9 @@ class MessageDetailsActionSheet : BottomSheetDialogFragment() {
|
|||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
Timber.v("State changed to $newState")
|
||||
if (newState == STATE_EXPANDED) {
|
||||
showCloseIcon()
|
||||
setCloseIconVisibility(true)
|
||||
} else {
|
||||
hideCloseIcon()
|
||||
setCloseIconVisibility(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,19 +80,96 @@ class MessageDetailsActionSheet : BottomSheetDialogFragment() {
|
|||
Timber.v("onSlide to offset $slideOffset")
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
return bottomSheetDialog
|
||||
}
|
||||
|
||||
private fun hideCloseIcon() {
|
||||
closeViewIcon.isVisible = false
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun showCloseIcon() {
|
||||
closeViewIcon.isVisible = true
|
||||
private fun setupHeaderBindings(
|
||||
binding: LayoutMessageDetailsActionsSheetHeaderBinding,
|
||||
arguments: Bundle?
|
||||
) = with(binding) {
|
||||
val title = arguments?.getString(EXTRA_ARG_TITLE)
|
||||
if (!title.isNullOrEmpty()) {
|
||||
detailsActionsTitleTextView.text = title
|
||||
}
|
||||
val subtitle = arguments?.getString(EXTRA_ARG_SUBTITLE)
|
||||
if (!subtitle.isNullOrEmpty()) {
|
||||
detailsActionsSubTitleTextView.text = subtitle
|
||||
}
|
||||
detailsActionsCloseView.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMainButtonsBindings(
|
||||
binding: LayoutMessageDetailsActionsSheetButtonsBinding,
|
||||
detailsViewModel: MessageDetailsViewModel
|
||||
) = with(binding) {
|
||||
detailsActionsReplyTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.REPLY)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsReplyAllTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.REPLY_ALL)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsForwardTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.FORWARD)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsMarkAsUnreadTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.MARK_UNREAD)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupOtherButtonsBindings(
|
||||
binding: FragmentMessageDetailsActionSheetBinding,
|
||||
detailsViewModel: MessageDetailsViewModel
|
||||
) = with(binding) {
|
||||
detailsActionsStarUnstarTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.STAR_UNSTAR)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsTrashTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.MOVE_TO_TRASH)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsMoveToArchiveTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.MOVE_TO_ARCHIVE)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsMoveToSpamTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.MOVE_TO_SPAM)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsLabelAsTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.LABEL_AS)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsMoveToTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.MOVE_TO)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsReportPhishingTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.REPORT_PHISHING)
|
||||
dismiss()
|
||||
}
|
||||
detailsActionsPrintTextView.setOnClickListener {
|
||||
detailsViewModel.handleAction(MessageDetailsAction.PRINT, activity)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCloseIconVisibility(shouldBeVisible: Boolean) {
|
||||
binding.includeLayoutActionSheetHeader.detailsActionsCloseView.isVisible = shouldBeVisible
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
package ch.protonmail.android.activities.messageDetails
|
||||
|
||||
import android.content.Context
|
||||
import android.app.Activity
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.print.PrintAttributes
|
||||
|
@ -36,7 +36,7 @@ import ch.protonmail.android.utils.extensions.showToast
|
|||
import timber.log.Timber
|
||||
|
||||
internal class MessagePrinter(
|
||||
private val context: Context,
|
||||
private val activity: Activity,
|
||||
private val resources: Resources,
|
||||
private val printManager: PrintManager,
|
||||
private val loadRemoteImages: Boolean
|
||||
|
@ -56,7 +56,7 @@ internal class MessagePrinter(
|
|||
|
||||
@RequiresApi(Build.VERSION_CODES.KITKAT)
|
||||
fun printMessage(message: Message, bodyString: String) {
|
||||
val webView = WebView(context)
|
||||
val webView = WebView(activity)
|
||||
webView.webViewClient = PrinterWebViewClient(message)
|
||||
webView.settings.blockNetworkImage = !loadRemoteImages
|
||||
val messageString = StringBuilder("<p>")
|
||||
|
@ -70,12 +70,16 @@ internal class MessagePrinter(
|
|||
messageString.appendRecipientsList(message.toList, R.string.print_to_template)
|
||||
messageString.appendRecipientsList(message.ccList, R.string.print_cc_template)
|
||||
messageString.appendRecipientsList(message.bccList, R.string.print_bcc_template)
|
||||
messageString.append(String.format(resources.getString(R.string.print_date_template), DateUtil.formatDetailedDateTime(context, message.timeMs)))
|
||||
messageString.append(String.format(resources.getString(R.string.print_date_template), DateUtil.formatDetailedDateTime(activity, message.timeMs)))
|
||||
messageString.append("<br/>")
|
||||
val attachmentList = message.Attachments
|
||||
val attachmentsCount = attachmentList.size
|
||||
messageString.append(resources.getQuantityString(R.plurals.attachments_non_descriptive,
|
||||
attachmentsCount, attachmentsCount))
|
||||
messageString.append(
|
||||
resources.getQuantityString(
|
||||
R.plurals.attachments_non_descriptive,
|
||||
attachmentsCount, attachmentsCount
|
||||
)
|
||||
)
|
||||
messageString.append("<br/>")
|
||||
attachmentList.forEach { attachment ->
|
||||
messageString.append(String.format(resources.getString(R.string.print_attachment_template), attachment.fileName))
|
||||
|
@ -103,7 +107,7 @@ internal class MessagePrinter(
|
|||
printManager.print(jobName, printAdapter, PrintAttributes.Builder().build())
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
context.showToast(R.string.print_error)
|
||||
activity.showToast(R.string.print_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package ch.protonmail.android.activities.messageDetails.viewmodel
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
|
@ -53,6 +54,7 @@ import ch.protonmail.android.data.local.AttachmentMetadataDao
|
|||
import ch.protonmail.android.data.local.model.*
|
||||
import ch.protonmail.android.events.DownloadEmbeddedImagesEvent
|
||||
import ch.protonmail.android.events.Status
|
||||
import ch.protonmail.android.jobs.PostTrashJobV2
|
||||
import ch.protonmail.android.jobs.helper.EmbeddedImage
|
||||
import ch.protonmail.android.usecase.VerifyConnection
|
||||
import ch.protonmail.android.usecase.delete.DeleteMessage
|
||||
|
@ -67,6 +69,7 @@ import ch.protonmail.android.utils.crypto.KeyInformation
|
|||
import ch.protonmail.android.viewmodel.ConnectivityBaseViewModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import com.birbit.android.jobqueue.JobManager
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -99,6 +102,7 @@ internal class MessageDetailsViewModel @Inject constructor(
|
|||
private val dispatchers: DispatcherProvider,
|
||||
private val attachmentsHelper: AttachmentsHelper,
|
||||
private val downloadUtils: DownloadUtils,
|
||||
private val jobManager: JobManager,
|
||||
messageRendererFactory: MessageRenderer.Factory,
|
||||
verifyConnection: VerifyConnection,
|
||||
networkConfigurator: NetworkConfigurator
|
||||
|
@ -643,13 +647,16 @@ internal class MessageDetailsViewModel @Inject constructor(
|
|||
|
||||
fun deleteMessage(messageId: String) {
|
||||
viewModelScope.launch {
|
||||
deleteMessageUseCase(listOf(messageId), Constants.MessageLocationType.TRASH.messageLocationTypeValue.toString())
|
||||
deleteMessageUseCase(
|
||||
listOf(messageId), Constants.MessageLocationType.TRASH.messageLocationTypeValue.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun printMessage(activityContext: Context) {
|
||||
private fun printMessage(activityContext: Activity?) {
|
||||
val message = message.value
|
||||
message?.let {
|
||||
requireNotNull(activityContext)
|
||||
MessagePrinter(
|
||||
activityContext,
|
||||
activityContext.resources,
|
||||
|
@ -678,7 +685,30 @@ internal class MessageDetailsViewModel @Inject constructor(
|
|||
return bodyString
|
||||
}
|
||||
|
||||
fun handleAction(action: MessageDetailsAction) {
|
||||
fun handleAction(
|
||||
action: MessageDetailsAction,
|
||||
activity: Activity? = null
|
||||
) {
|
||||
Timber.v("Handle action: $action")
|
||||
when (action) {
|
||||
MessageDetailsAction.DELETE_MESSAGE -> deleteMessage(messageId)
|
||||
MessageDetailsAction.FORWARD -> TODO()
|
||||
MessageDetailsAction.LABEL_AS -> TODO()
|
||||
MessageDetailsAction.MARK_UNREAD -> TODO()
|
||||
MessageDetailsAction.MOVE_TO -> TODO()
|
||||
MessageDetailsAction.MOVE_TO_ARCHIVE -> TODO()
|
||||
MessageDetailsAction.MOVE_TO_SPAM -> TODO()
|
||||
MessageDetailsAction.MOVE_TO_TRASH -> moveToTrash(messageId)
|
||||
MessageDetailsAction.PRINT -> printMessage(activity)
|
||||
MessageDetailsAction.REPLY -> TODO()
|
||||
MessageDetailsAction.REPLY_ALL -> TODO()
|
||||
MessageDetailsAction.REPORT_PHISHING -> TODO()
|
||||
MessageDetailsAction.STAR_UNSTAR -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveToTrash(messageId: String) {
|
||||
val job = PostTrashJobV2(listOf(messageId), null)
|
||||
jobManager.addJobInBackground(job)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,6 @@ import ch.protonmail.android.events.PostPhishingReportEvent
|
|||
import ch.protonmail.android.events.Status
|
||||
import ch.protonmail.android.jobs.PostArchiveJob
|
||||
import ch.protonmail.android.jobs.PostSpamJob
|
||||
import ch.protonmail.android.jobs.PostTrashJobV2
|
||||
import ch.protonmail.android.jobs.PostUnreadJob
|
||||
import ch.protonmail.android.jobs.ReportPhishingJob
|
||||
import ch.protonmail.android.utils.AppUtil
|
||||
|
@ -808,8 +807,7 @@ internal class MessageDetailsActivity :
|
|||
)
|
||||
messageDetailsActionsView.bind(actionsUiModel)
|
||||
messageDetailsActionsView.setOnThirdActionClickListener {
|
||||
val job = PostTrashJobV2(listOf(message.messageId), null)
|
||||
mJobManager.addJobInBackground(job)
|
||||
viewModel.handleAction(MessageDetailsAction.MOVE_TO_TRASH)
|
||||
onBackPressed()
|
||||
}
|
||||
messageDetailsActionsView.setOnSecondActionClickListener {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:animateLayoutChanges="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
@ -30,9 +29,13 @@
|
|||
android:paddingTop="@dimen/space_m"
|
||||
android:paddingBottom="@dimen/space_l">
|
||||
|
||||
<include layout="@layout/layout_message_details_actions_sheet_header" />
|
||||
<include
|
||||
android:id="@+id/includeLayoutActionSheetHeader"
|
||||
layout="@layout/layout_message_details_actions_sheet_header" />
|
||||
|
||||
<include layout="@layout/layout_message_details_actions_sheet_buttons" />
|
||||
<include
|
||||
android:id="@+id/includeLayoutActionSheetButtons"
|
||||
layout="@layout/layout_message_details_actions_sheet_buttons" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detailsActionsStarUnstarTextView"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:paddingStart="@dimen/space_l"
|
||||
android:paddingEnd="@dimen/space_l"
|
||||
tools:showIn="@layout/fragment_message_details_action_sheet">
|
||||
|
|
|
@ -33,6 +33,7 @@ import ch.protonmail.android.usecase.VerifyConnection
|
|||
import ch.protonmail.android.usecase.delete.DeleteMessage
|
||||
import ch.protonmail.android.usecase.fetch.FetchVerificationKeys
|
||||
import ch.protonmail.android.utils.DownloadUtils
|
||||
import com.birbit.android.jobqueue.JobManager
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
|
@ -54,6 +55,8 @@ class MessageDetailsViewModelTest : ArchTest, CoroutinesTest {
|
|||
|
||||
private val userManager: UserManager = mockk(relaxed = true)
|
||||
|
||||
private val jobManager: JobManager = mockk(relaxed = true)
|
||||
|
||||
private val contactsRepository: ContactsRepository = mockk(relaxed = true)
|
||||
|
||||
private val attachmentsHelper: AttachmentsHelper = mockk(relaxed = true)
|
||||
|
@ -88,6 +91,7 @@ class MessageDetailsViewModelTest : ArchTest, CoroutinesTest {
|
|||
dispatchers,
|
||||
attachmentsHelper,
|
||||
downloadUtils,
|
||||
jobManager,
|
||||
messageRendererFactory,
|
||||
verifyConnection,
|
||||
networkConfigurator
|
||||
|
@ -100,7 +104,8 @@ class MessageDetailsViewModelTest : ArchTest, CoroutinesTest {
|
|||
val windowWidth = 500
|
||||
val defaultErrorMessage = "errorHappened"
|
||||
val cssContent = "css"
|
||||
val expected = "<html>\n <head>\n <style>$cssContent</style>\n <meta name=\"viewport\" content=\"width=$windowWidth, maximum-scale=2\"> \n </head>\n <body>\n <div id=\"pm-body\" class=\"inbox-body\"> $decryptedMessage \n </div>\n </body>\n</html>"
|
||||
val expected =
|
||||
"<html>\n <head>\n <style>$cssContent</style>\n <meta name=\"viewport\" content=\"width=$windowWidth, maximum-scale=2\"> \n </head>\n <body>\n <div id=\"pm-body\" class=\"inbox-body\"> $decryptedMessage \n </div>\n </body>\n</html>"
|
||||
|
||||
// when
|
||||
val parsedMessage = viewModel.getParsedMessage(decryptedMessage, windowWidth, cssContent, defaultErrorMessage)
|
||||
|
|
|
@ -47,4 +47,4 @@ compileKotlin.kotlinOptions {
|
|||
val compileTestKotlin: KotlinCompile by tasks
|
||||
compileTestKotlin.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,6 +111,8 @@ fun org.gradle.api.Project.android(
|
|||
execution = "ANDROIDX_TEST_ORCHESTRATOR"
|
||||
}
|
||||
|
||||
buildFeatures.viewBinding = true
|
||||
|
||||
packagingOptions {
|
||||
exclude("META-INF/*.kotlin_module")
|
||||
exclude("META-INF/AL2.0")
|
||||
|
|
Loading…
Reference in New Issue