Add helper method for getting sendView icons (#678)

This commit is contained in:
David Perez 2024-01-18 23:03:52 -06:00 committed by Álison Fernandes
parent cb306a8377
commit 2c749186e1
9 changed files with 151 additions and 70 deletions

View file

@ -1,10 +1,12 @@
package com.x8bit.bitwarden.ui.platform.components.model
import android.os.Parcelable
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import com.x8bit.bitwarden.ui.platform.base.util.Text
import kotlinx.parcelize.Parcelize
/**
* Data class representing the resources required for an icon.
@ -23,11 +25,12 @@ data class IconResource(
* @property iconRes Resource for the icon.
* @property contentDescription The icon's content description.
*/
@Parcelize
data class IconRes(
@DrawableRes
val iconRes: Int,
val contentDescription: Text,
)
) : Parcelable
/**
* A helper method to convert a list of [IconRes] to a list of [IconResource].

View file

@ -15,10 +15,10 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenListItem
import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog
import com.x8bit.bitwarden.ui.platform.components.SelectionItemData
import com.x8bit.bitwarden.ui.platform.components.model.IconData
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
import com.x8bit.bitwarden.ui.platform.components.model.IconResource
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import com.x8bit.bitwarden.ui.platform.util.persistentListOfNotNull
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import kotlinx.collections.immutable.toPersistentList
/**
@ -43,7 +43,7 @@ fun SendListItem(
label: String,
supportingLabel: String,
startIcon: IconData,
trailingLabelIcons: List<SendStatusIcon>,
trailingLabelIcons: List<IconRes>,
onClick: () -> Unit,
onEditClick: () -> Unit,
onCopyClick: () -> Unit,

View file

@ -18,7 +18,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.base.util.concat
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
import com.x8bit.bitwarden.ui.tools.feature.send.util.toViewState
import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemScreen
import dagger.hilt.android.lifecycle.HiltViewModel
@ -350,7 +350,7 @@ data class SendState(
val name: String,
val deletionDate: String,
val type: Type,
val iconList: List<SendStatusIcon>,
val iconList: List<IconRes>,
val shareUrl: String,
val hasPassword: Boolean,
) : Parcelable {

View file

@ -5,8 +5,6 @@ import com.bitwarden.core.SendView
import com.x8bit.bitwarden.data.vault.repository.model.SendData
import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
import com.x8bit.bitwarden.ui.tools.feature.send.SendState
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import java.time.Instant
private const val DELETION_DATE_PATTERN: String = "MMM d, uuuu, hh:mm a"
@ -38,21 +36,7 @@ private fun List<SendView>.toSendContent(
SendType.TEXT -> SendState.ViewState.Content.SendItem.Type.TEXT
SendType.FILE -> SendState.ViewState.Content.SendItem.Type.FILE
},
iconList = listOfNotNull(
SendStatusIcon.DISABLED.takeIf { sendView.disabled },
SendStatusIcon.PASSWORD.takeIf { sendView.hasPassword },
SendStatusIcon.MAX_ACCESS_COUNT_REACHED.takeIf {
sendView.maxAccessCount?.let { maxCount ->
sendView.accessCount >= maxCount
} == true
},
SendStatusIcon.EXPIRED.takeIf {
sendView.expirationDate?.isBefore(Instant.now()) == true
},
SendStatusIcon.PENDING_DELETE.takeIf {
sendView.deletionDate.isBefore(Instant.now())
},
),
iconList = sendView.toLabelIcons(),
shareUrl = sendView.toSendUrl(baseWebSendUrl),
hasPassword = sendView.hasPassword,
)

View file

@ -1,6 +1,24 @@
package com.x8bit.bitwarden.ui.tools.feature.send.util
import com.bitwarden.core.SendView
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import java.time.Clock
/**
* Creates the list of trailing label icons to be displayed for a [SendView].
*/
fun SendView.toLabelIcons(clock: Clock = Clock.systemDefaultZone()): List<IconRes> =
listOfNotNull(
SendStatusIcon.DISABLED.takeIf { disabled },
SendStatusIcon.PASSWORD.takeIf { hasPassword },
SendStatusIcon.MAX_ACCESS_COUNT_REACHED.takeIf {
maxAccessCount?.let { maxCount -> accessCount >= maxCount } == true
},
SendStatusIcon.EXPIRED.takeIf { expirationDate?.isBefore(clock.instant()) == true },
SendStatusIcon.PENDING_DELETE.takeIf { deletionDate.isBefore(clock.instant()) },
)
.map { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) }
/**
* Creates a sharable url from a [SendView].

View file

@ -10,8 +10,7 @@ import com.bitwarden.core.SendView
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.components.model.IconData
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import com.x8bit.bitwarden.ui.tools.feature.send.util.toLabelIcons
import com.x8bit.bitwarden.ui.tools.feature.send.util.toSendUrl
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingsAction
@ -207,23 +206,7 @@ private fun SendView.toDisplayItem(
SendType.FILE -> R.drawable.ic_send_file
},
),
extraIconList = listOfNotNull(
SendStatusIcon.DISABLED
.takeIf { disabled }
?.let { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) },
SendStatusIcon.PASSWORD
.takeIf { hasPassword }
?.let { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) },
SendStatusIcon.MAX_ACCESS_COUNT_REACHED
.takeIf { maxAccessCount?.let { maxCount -> accessCount >= maxCount } == true }
?.let { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) },
SendStatusIcon.EXPIRED
.takeIf { expirationDate?.isBefore(clock.instant()) == true }
?.let { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) },
SendStatusIcon.PENDING_DELETE
.takeIf { deletionDate.isBefore(clock.instant()) }
?.let { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) },
),
extraIconList = toLabelIcons(clock = clock),
overflowOptions = listOfNotNull(
VaultItemListingState.DisplayItem.OverflowItem(
title = R.string.edit.asText(),

View file

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.tools.feature.send.util
import com.bitwarden.core.SendType
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSendView
import com.x8bit.bitwarden.data.vault.repository.model.SendData
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
import com.x8bit.bitwarden.ui.tools.feature.send.SendState
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import io.mockk.every
@ -52,6 +53,8 @@ class SendDataExtensionsTest {
val sendData = SendData(list)
every { textSendView.toSendUrl(DEFAULT_BASE_URL) } returns textSendViewUrl2
every { fileSendView.toSendUrl(DEFAULT_BASE_URL) } returns textSendViewUrl1
every { textSendView.toLabelIcons(any()) } returns DEFAULT_SEND_STATUS_ICONS
every { fileSendView.toLabelIcons(any()) } returns DEFAULT_SEND_STATUS_ICONS
val result = sendData.toViewState(DEFAULT_BASE_URL)
@ -65,12 +68,7 @@ class SendDataExtensionsTest {
name = "mockName-1",
deletionDate = "Oct 27, 2023, 12:00 PM",
type = SendState.ViewState.Content.SendItem.Type.FILE,
iconList = listOf(
SendStatusIcon.PASSWORD,
SendStatusIcon.MAX_ACCESS_COUNT_REACHED,
SendStatusIcon.EXPIRED,
SendStatusIcon.PENDING_DELETE,
),
iconList = DEFAULT_SEND_STATUS_ICONS,
shareUrl = "www.test.com/#/send/mockAccessId-1/mockKey-1",
hasPassword = true,
),
@ -79,12 +77,7 @@ class SendDataExtensionsTest {
name = "mockName-2",
deletionDate = "Oct 27, 2023, 12:00 PM",
type = SendState.ViewState.Content.SendItem.Type.TEXT,
iconList = listOf(
SendStatusIcon.PASSWORD,
SendStatusIcon.MAX_ACCESS_COUNT_REACHED,
SendStatusIcon.EXPIRED,
SendStatusIcon.PENDING_DELETE,
),
iconList = DEFAULT_SEND_STATUS_ICONS,
shareUrl = "www.test.com/#/send/mockAccessId-2/mockKey-2",
hasPassword = true,
),
@ -99,3 +92,26 @@ private const val SEND_VIEW_EXTENSIONS_PATH: String =
"com.x8bit.bitwarden.ui.tools.feature.send.util.SendViewExtensionsKt"
private const val DEFAULT_BASE_URL: String = "www.test.com/"
private val DEFAULT_SEND_STATUS_ICONS: List<IconRes> = listOf(
IconRes(
iconRes = SendStatusIcon.DISABLED.iconRes,
contentDescription = SendStatusIcon.DISABLED.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.PASSWORD.iconRes,
contentDescription = SendStatusIcon.PASSWORD.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.iconRes,
contentDescription = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.EXPIRED.iconRes,
contentDescription = SendStatusIcon.EXPIRED.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.PENDING_DELETE.iconRes,
contentDescription = SendStatusIcon.PENDING_DELETE.contentDescription,
),
)

View file

@ -0,0 +1,94 @@
package com.x8bit.bitwarden.ui.tools.feature.send.util
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSendView
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
import com.x8bit.bitwarden.ui.tools.feature.send.model.SendStatusIcon
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.time.Clock
import java.time.Instant
import java.time.ZoneOffset
class SendViewExtensionsTest {
private val clock: Clock = Clock.fixed(
Instant.parse("2023-10-27T12:00:00Z"),
ZoneOffset.UTC,
)
@Test
fun `toLabelIcons should return all of the icons when all checks have passed`() {
val sendView = createMockSendView(number = 1).copy(
// Show the password icon when true
hasPassword = true,
// Show the disabled icon when true
disabled = true,
// Show the max access count reached icon when accessCount is greater than or equal to
// the maxAccessCount
maxAccessCount = 1u,
accessCount = 1u,
// Show the pending deletion icon when the deletion date is in the past
deletionDate = Instant.parse("2023-10-26T12:00:00Z"),
// Show the expired icon when the expiration date is in the past
expirationDate = Instant.parse("2023-10-26T12:00:00Z"),
)
val result = sendView.toLabelIcons(clock)
assertEquals(ALL_SEND_STATUS_ICONS, result)
}
@Test
fun `toLabelIcons should return none of the icons when none of the checks have passed`() {
val sendView = createMockSendView(number = 1).copy(
// Hide the password icon when false
hasPassword = false,
// Hide the disabled icon when false
disabled = false,
// Hide the max access count reached icon when accessCount is less than the
// maxAccessCount
maxAccessCount = 10u,
accessCount = 1u,
// Hide the pending deletion icon when the deletion date is in the future
deletionDate = Instant.parse("2023-10-28T12:00:00Z"),
// Hide the expired icon when the expiration date is in the future
expirationDate = Instant.parse("2023-10-28T12:00:00Z"),
)
val result = sendView.toLabelIcons(clock)
assertEquals(emptyList<IconRes>(), result)
}
@Test
fun `toSendUrl should create an appropriate url`() {
val sendView = createMockSendView(number = 1)
val result = sendView.toSendUrl(baseWebSendUrl = "www.test.com/")
assertEquals("www.test.com/mockAccessId-1/mockKey-1", result)
}
}
private val ALL_SEND_STATUS_ICONS: List<IconRes> = listOf(
IconRes(
iconRes = SendStatusIcon.DISABLED.iconRes,
contentDescription = SendStatusIcon.DISABLED.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.PASSWORD.iconRes,
contentDescription = SendStatusIcon.PASSWORD.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.iconRes,
contentDescription = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.EXPIRED.iconRes,
contentDescription = SendStatusIcon.EXPIRED.contentDescription,
),
IconRes(
iconRes = SendStatusIcon.PENDING_DELETE.iconRes,
contentDescription = SendStatusIcon.PENDING_DELETE.contentDescription,
),
)

View file

@ -1,17 +0,0 @@
package com.x8bit.bitwarden.ui.tools.feature.send.util
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSendView
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class SendViewTest {
@Test
fun `toSendUrl should create an appropriate url`() {
val sendView = createMockSendView(number = 1)
val result = sendView.toSendUrl(baseWebSendUrl = "www.test.com/")
assertEquals("www.test.com/mockAccessId-1/mockKey-1", result)
}
}