Adds expiration icon to the collapsed message view

Adds the expiration view to the collapsed messages, which shows the icon and the
time using the largest available time unit, e.g. 7days 6hours will be shown as 7D.
In addition, updates the mockk to the most recent version.

MAILAND-2236
This commit is contained in:
Maciej Surmacz 2021-09-08 11:59:05 +02:00 committed by Maciej Surmacz
parent f4ffd7ceb3
commit dee0fa17d8
19 changed files with 514 additions and 38 deletions

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.details.presentation.view
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import ch.protonmail.android.R
import ch.protonmail.android.data.local.model.Message
import ch.protonmail.android.domain.entity.LabelId
import ch.protonmail.android.domain.entity.Name
import ch.protonmail.android.testAndroidInstrumented.assertion.isGone
import ch.protonmail.android.testAndroidInstrumented.assertion.isVisible
import ch.protonmail.android.ui.model.LabelChipUiModel
import ch.protonmail.android.util.HiltViewTest
import ch.protonmail.android.utils.ServerTimeProvider
import dagger.hilt.android.testing.HiltAndroidTest
import io.mockk.every
import io.mockk.mockk
import org.junit.Before
import org.junit.Test
@HiltAndroidTest
class CollapsedMessageViewsTest : HiltViewTest<CollapsedMessageViews>(::CollapsedMessageViews) {
private val serverTimeProviderMock = mockk<ServerTimeProvider>()
@Before
fun setUp() {
testView.serverTimeProvider = serverTimeProviderMock
}
@Test
fun shouldHideExpirationViewWhenMessageDoesNotHaveExpiration() {
every { serverTimeProviderMock.currentTimeMillis() } returns 0
val labels = emptyList<LabelChipUiModel>()
val message = Message(expirationTime = 0)
runOnActivityThread {
testView.bind(message, labels)
}
onExpirationTextView().check(isGone())
}
@Test
fun shouldShowCorrectExpirationTimeWhenMessageDoesHaveExpiration() {
every { serverTimeProviderMock.currentTimeMillis() } returns 60000
val labels = emptyList<LabelChipUiModel>()
val message = Message(expirationTime = 420)
val expectedExpirationString = "6M"
runOnActivityThread {
testView.bind(message, labels)
}
onExpirationTextView()
.check(isVisible())
.check(matches(withText(expectedExpirationString)))
}
@Test
fun shouldHideLabelsViewWhenNoLabelsProvided() {
val labels = emptyList<LabelChipUiModel>()
val message = Message()
runOnActivityThread {
testView.bind(message, labels)
}
onLabelsView().check(isGone())
}
@Test
fun shouldShowLabelsViewWhenLabelsProvided() {
val labels = listOf(
LabelChipUiModel(
id = LabelId("1"),
name = Name("label 1"),
color = null
)
)
val message = Message()
runOnActivityThread {
testView.bind(message, labels)
}
onLabelsView().check(isVisible())
}
private fun onExpirationTextView(): ViewInteraction = onView(withId(R.id.messageExpirationTextView))
private fun onLabelsView(): ViewInteraction = onView(withId(R.id.collapsedLabelsView))
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.util
import android.content.Context
import android.view.View
import android.widget.FrameLayout
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.rules.activityScenarioRule
import dagger.hilt.android.testing.HiltAndroidRule
import org.junit.Rule
import kotlin.test.BeforeTest
open class HiltViewTest<V : View>(
private val buildView: (Context) -> V,
private val width: Int = FrameLayout.LayoutParams.WRAP_CONTENT,
private val height: Int = FrameLayout.LayoutParams.WRAP_CONTENT
) {
@get:Rule(order = 0)
var hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1)
val activityScenarioRule: ActivityScenarioRule<HiltViewTestActivity> = activityScenarioRule(null, null)
protected lateinit var testView: V
protected val context: Context get() = testView.context
@BeforeTest
open fun setupView() {
activityScenarioRule.scenario.onActivity { activity ->
val params = FrameLayout.LayoutParams(width, height)
testView = activity.setView(buildView, params)
testView.id = TEST_VIEW_ID
}
}
fun onTestView(): ViewInteraction =
onView(withId(TEST_VIEW_ID))
fun runOnActivityThread(block: () -> Unit) {
activityScenarioRule.scenario.onActivity {
block()
}
}
private companion object {
const val TEST_VIEW_ID = 7_435_838
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.util
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class HiltViewTestActivity : AppCompatActivity() {
private val frameLayout by lazy { FrameLayout(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(frameLayout)
}
fun <V : View> setView(buildView: (Context) -> V, params: FrameLayout.LayoutParams): V {
val view = buildView(this)
frameLayout.addView(view, params)
return view
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.utils
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Test
import kotlin.test.assertEquals
class DateUtilTest {
private val context = InstrumentationRegistry.getInstrumentation().targetContext
@Test
fun shouldFormatTheLargestAvailableUnitOnly() {
val fiveDaysSixHoursAndSevenMinutes = 454_020L
val sixHoursAndSevenMinutes = 22_020L
val sevenMinutes = 420L
val expectedDaysString = "5D"
val expectedHoursString = "6H"
val expectedMinutesString = "7M"
val actualDaysString = DateUtil.formatTheLargestAvailableUnitOnly(context, fiveDaysSixHoursAndSevenMinutes)
val actualHoursString = DateUtil.formatTheLargestAvailableUnitOnly(context, sixHoursAndSevenMinutes)
val actualMinutesString = DateUtil.formatTheLargestAvailableUnitOnly(context, sevenMinutes)
assertEquals(expectedDaysString, actualDaysString)
assertEquals(expectedHoursString, actualHoursString)
assertEquals(expectedMinutesString, actualMinutesString)
}
}

View File

@ -34,24 +34,24 @@ import org.junit.runner.RunWith
class MessageDetailsHeaderViewTest : ViewTest<MessageDetailsHeaderView>(::MessageDetailsHeaderView) {
@Test
fun shouldHideCollapsedLabels() {
fun shouldHideCollapsedMessageViews() {
runOnActivityThread {
testView.showCollapsedLabelsView()
testView.hideCollapsedLabelsView()
testView.showCollapsedMessageViews()
testView.hideCollapsedMessageViews()
}
onCollapsedLabelsView().check(isGone())
onCollapsedMessageView().check(isGone())
}
@Test
fun shouldShowCollapsedLabels() {
fun shouldShowCollapsedMessageViews() {
runOnActivityThread {
testView.hideCollapsedLabelsView()
testView.showCollapsedLabelsView()
testView.hideCollapsedMessageViews()
testView.showCollapsedMessageViews()
}
onCollapsedLabelsView().check(isVisible())
onCollapsedMessageView().check(isVisible())
}
private fun onCollapsedLabelsView(): ViewInteraction = onView(withId(R.id.collapsedLabelsView))
private fun onCollapsedMessageView(): ViewInteraction = onView(withId(R.id.collapsedMessageViews))
}

View File

@ -132,6 +132,7 @@
<activity android:name=".ViewTestActivity"/>
<activity android:name=".util.HiltViewTestActivity"/>
<!-- Begin - Root Activities -->
<activity

View File

@ -211,10 +211,10 @@ internal class MessageDetailsAdapter(
if (isMessageBodyExpanded()) {
messageDetailsHeaderView.allowExpandingHeaderView()
messageDetailsHeaderView.showRecipientsCollapsedView()
messageDetailsHeaderView.hideCollapsedLabelsView()
messageDetailsHeaderView.hideCollapsedMessageViews()
} else {
messageDetailsHeaderView.hideRecipientsCollapsedView()
messageDetailsHeaderView.showCollapsedLabelsView()
messageDetailsHeaderView.showCollapsedMessageViews()
}
if (message.isRead) {

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.details.presentation.view
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import ch.protonmail.android.data.local.model.Message
import ch.protonmail.android.databinding.LayoutCollapsedMessageViewsBinding
import ch.protonmail.android.ui.model.LabelChipUiModel
import ch.protonmail.android.ui.view.SingleLineCollapsedLabelGroupView
import ch.protonmail.android.utils.DateUtil
import ch.protonmail.android.utils.ServerTimeProvider
import dagger.hilt.android.AndroidEntryPoint
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@AndroidEntryPoint
class CollapsedMessageViews @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
private val messageExpirationTextView: TextView
private val collapsedLabelsView: SingleLineCollapsedLabelGroupView
@Inject lateinit var serverTimeProvider: ServerTimeProvider
init {
val binding = LayoutCollapsedMessageViewsBinding.inflate(LayoutInflater.from(context), this)
messageExpirationTextView = binding.messageExpirationTextView
collapsedLabelsView = binding.collapsedLabelsView
}
fun bind(message: Message, labels: List<LabelChipUiModel>) {
collapsedLabelsView.showLabelsOrHide(labels)
messageExpirationTextView.showExpirationTimeOrHide(message.expirationTime)
}
private fun SingleLineCollapsedLabelGroupView.showLabelsOrHide(labels: List<LabelChipUiModel>) {
if (labels.isNotEmpty()) {
setLabels(labels)
visibility = View.VISIBLE
} else {
visibility = View.GONE
}
}
private fun TextView.showExpirationTimeOrHide(expirationTime: Long) {
if (expirationTime > 0) {
val remainingSeconds = expirationTime -
TimeUnit.MILLISECONDS.toSeconds(serverTimeProvider.currentTimeMillis())
text = DateUtil.formatTheLargestAvailableUnitOnly(context, remainingSeconds)
visibility = View.VISIBLE
} else {
visibility = View.GONE
}
}
}

View File

@ -72,6 +72,7 @@ open class MoreItemsLinearLayout @JvmOverloads constructor (
gravity = Gravity.CENTER_VERTICAL
}
setTextAppearance(R.style.Proton_Text_Caption)
includeFontPadding = false
}
init {

View File

@ -63,6 +63,21 @@ public class DateUtil {
return formatDaysAndHours(context, days, hours, minutes);
}
public static String formatTheLargestAvailableUnitOnly(Context context, long seconds) {
int days = (int) (seconds / (24 * 60 * 60));
if (days > 0) {
return context.getResources().getString(R.string.expiration_days, days);
}
seconds = (int) (seconds - days * (24 * 60 * 60));
int hours = (int)(seconds / (60 * 60));
if (hours > 0) {
return context.getResources().getString(R.string.expiration_hours, hours);
}
seconds = (int) (seconds - hours * (60 * 60));
int minutes = (int) (seconds / 60);
return context.getResources().getString(R.string.expiration_minutes, minutes);
}
public static String formatDaysAndHours(Context context, int days, int hours, int minutes) {
if (days == 0 && hours == 0 & minutes == 0) {
return "";

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.utils
import javax.inject.Inject
import javax.inject.Singleton
/**
* An injectable time provider.
*/
@Singleton
class ServerTimeProvider @Inject constructor() {
fun currentTimeMillis() = ServerTime.currentTimeMillis()
}

View File

@ -44,10 +44,10 @@ import ch.protonmail.android.data.local.model.Label
import ch.protonmail.android.data.local.model.Message
import ch.protonmail.android.databinding.LayoutMessageDetailsHeaderBinding
import ch.protonmail.android.details.presentation.MessageDetailsActivity
import ch.protonmail.android.details.presentation.view.CollapsedMessageViews
import ch.protonmail.android.details.presentation.view.MessageDetailsHeaderIcons
import ch.protonmail.android.ui.model.LabelChipUiModel
import ch.protonmail.android.ui.view.MultiLineLabelChipGroupView
import ch.protonmail.android.ui.view.SingleLineCollapsedLabelGroupView
import ch.protonmail.android.ui.view.SingleLineLabelChipGroupView
import ch.protonmail.android.utils.DateUtil
import ch.protonmail.android.utils.UiUtil
@ -87,7 +87,6 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
private val labelsImageView: ImageView
private val labelsCollapsedGroupView: SingleLineLabelChipGroupView
private val labelsExpandedGroupView: MultiLineLabelChipGroupView
private val collapsedLabelsView: SingleLineCollapsedLabelGroupView
private val timeDateTextView: TextView
private val timeDateExtendedTextView: TextView
@ -108,6 +107,7 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
private val forwardedImageView: ImageView
private val messageDetailsIcons: MessageDetailsHeaderIcons
private val collapsedMessageViews: CollapsedMessageViews
// endregion
init {
@ -136,7 +136,6 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
labelsImageView = binding.labelsImageView
labelsCollapsedGroupView = binding.labelsCollapsedGroupView
labelsExpandedGroupView = binding.labelsExpandedGroupView
collapsedLabelsView = binding.collapsedLabelsView
timeDateTextView = binding.timeDateTextView
timeDateExtendedTextView = binding.timeDateExtendedTextView
@ -157,6 +156,7 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
forwardedImageView = binding.forwardedImageView
messageDetailsIcons = binding.messageDetailsIcons
collapsedMessageViews = binding.collapsedMessageViews
// endregion
// animated layout changes looks buggy on Android 27, so we enable only on 28 +
@ -197,7 +197,6 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
labelsExpandedGroupView.setLabels(nonExclusiveLabels)
collapsedHeaderGroup.addView(labelsCollapsedGroupView)
expandedHeaderGroup.addView(labelsExpandedGroupView)
collapsedLabelsView.setLabels(nonExclusiveLabels)
// Can't control the visibility of individual views within the group as the group visibility trumps the
// visibility of the individual views within the group; thus we want to add the icon to the group only
@ -265,6 +264,7 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
forwardedImageView.isVisible = message.isForwarded ?: false
messageDetailsIcons.bind(message)
collapsedMessageViews.bind(message, nonExclusiveLabels)
}
fun allowExpandingHeaderView() {
@ -283,12 +283,12 @@ class MessageDetailsHeaderView @JvmOverloads constructor(
collapsedHeaderGroup.isVisible = true
}
fun showCollapsedLabelsView() {
collapsedLabelsView.isVisible = true
fun showCollapsedMessageViews() {
collapsedMessageViews.isVisible = true
}
fun hideCollapsedLabelsView() {
collapsedLabelsView.isVisible = false
fun hideCollapsedMessageViews() {
collapsedMessageViews.isVisible = false
}
fun collapseHeader() {

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2020 Proton Technologies AG
~
~ This file is part of ProtonMail.
~
~ ProtonMail 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.
~
~ ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="@dimen/message_details_header_hourglass_icon_size"
android:height="@dimen/message_details_header_hourglass_icon_size"
android:drawable="@drawable/ic_hourglass" />
</layer-list>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2020 Proton Technologies AG
~
~ This file is part of ProtonMail.
~
~ ProtonMail 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.
~
~ ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
-->
<merge 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="wrap_content"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<TextView
android:id="@+id/messageExpirationTextView"
style="@style/Proton.Text.Caption"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/shape_stretchable_circle"
android:gravity="center_vertical"
android:includeFontPadding="false"
android:padding="@dimen/padding_s"
app:drawableStartCompat="@drawable/ic_hourglass_message_header"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12h" />
<ch.protonmail.android.ui.view.SingleLineCollapsedLabelGroupView
android:id="@+id/collapsedLabelsView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_header_margin_small"
android:layout_marginEnd="@dimen/message_details_header_margin_small"
app:layout_constraintBottom_toBottomOf="@id/messageExpirationTextView"
app:layout_constraintStart_toEndOf="@id/messageExpirationTextView"
app:layout_constraintTop_toTopOf="@id/messageExpirationTextView" />
</merge>

View File

@ -109,11 +109,11 @@
app:layout_constraintTop_toTopOf="@id/senderNameTextView"
tools:text="@string/lock_default" />
<ch.protonmail.android.ui.view.SingleLineCollapsedLabelGroupView
android:id="@+id/collapsedLabelsView"
<ch.protonmail.android.details.presentation.view.CollapsedMessageViews
android:id="@+id/collapsedMessageViews"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_header_margin_small"
android:layout_marginStart="@dimen/message_details_header_margin_extra_small"
android:layout_marginEnd="@dimen/message_details_header_margin_small"
app:layout_constraintBottom_toBottomOf="@id/senderNameTextView"
app:layout_constraintEnd_toStartOf="@id/messageDetailsIcons"

View File

@ -25,15 +25,6 @@
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<TextView
android:id="@+id/messageExpirationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12h" />
<ImageView
android:id="@+id/attachmentsImageView"
android:layout_width="@dimen/message_details_header_small_icon_size"

View File

@ -97,9 +97,11 @@
<dimen name="message_details_header_margin_big">16dp</dimen>
<dimen name="message_details_header_margin_normal">8dp</dimen>
<dimen name="message_details_header_margin_small">4dp</dimen>
<dimen name="message_details_header_margin_extra_small">2dp</dimen>
<dimen name="message_details_header_small_icon_size">16dp</dimen>
<dimen name="message_details_header_chevron_icon_size">40dp</dimen>
<dimen name="message_details_header_chevron_icon_padding">12dp</dimen>
<dimen name="message_details_header_hourglass_icon_size">12dp</dimen>
<dimen name="message_details_banner_height">48dp</dimen>
<dimen name="message_details_banner_margin_horizontal">16dp</dimen>

View File

@ -598,11 +598,11 @@ class UploadAttachmentsTest : CoroutinesTest {
uploadAttachments.doWork()
val actualMessage = slot<Message>()
val actualMessages = mutableListOf<Message>()
val expectedAttachments = listOf(uploadedAttachmentMock1, uploadedAttachmentMock2)
verify { messageDetailsRepository.findAttachmentById(uploadedAttachmentMock2Id) }
coVerify { messageDetailsRepository.saveMessage(capture(actualMessage)) }
assertEquals(expectedAttachments, actualMessage.captured.attachments)
coVerify(exactly = 2) { messageDetailsRepository.saveMessage(capture(actualMessages)) }
assertEquals(expectedAttachments, actualMessages.last().attachments)
}
}
@ -676,10 +676,10 @@ class UploadAttachmentsTest : CoroutinesTest {
uploadAttachments.doWork()
val actualMessage = slot<Message>()
val actualMessages = mutableListOf<Message>()
val expectedAttachments = listOf(attachmentMock1)
coVerify(exactly = 2) { messageDetailsRepository.saveMessage(capture(actualMessage)) }
assertEquals(expectedAttachments, actualMessage.captured.attachments)
coVerify(exactly = 2) { messageDetailsRepository.saveMessage(capture(actualMessages)) }
assertEquals(expectedAttachments, actualMessages.last().attachments)
}
}

View File

@ -53,7 +53,7 @@ fun initVersions() {
`assistedInject version` = "0.6.0" // Released: Sep 14, 2020
`dagger version` = "2.35.1" // Released: Apr 28, 2021
`mockK version` = "1.10.0" // Released: Apr 19, 2020
`mockK version` = "1.12.0" // Released: Jul 01, 2021
`retrofit version` = "2.6.1" // Released: Jul 31, 2019
`retrofit-kotlin-serialization version` = ""
`robolectric version` = "4.3.1" // Released: Oct 11, 2019