Skip to content

Commit

Permalink
fix: connection button not shown when partial metadata (WPB-10342) (#…
Browse files Browse the repository at this point in the history
…3280)

Co-authored-by: Mojtaba Chenani <[email protected]>
  • Loading branch information
yamilmedina and mchenani authored Aug 5, 2024
1 parent 65bdbb4 commit d746711
Show file tree
Hide file tree
Showing 13 changed files with 293 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* 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 http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.other

import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import com.wire.android.ui.WireTestTheme
import com.wire.android.ui.home.conversationslist.model.Membership
import com.wire.android.ui.userprofile.other.OtherUserStubs.provideState
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
import org.junit.Rule
import org.junit.Test

class OtherUserProfileGroupTest {
@get:Rule
val composeTestRule by lazy { createComposeRule() }

@Test
fun givenARoleSelectionComponentIsShow_ShouldNotAllowModificationForTempUsers() = runTest {
composeTestRule.setContent {
WireTestTheme {
OtherUserProfileGroup(
provideState(withExpireAt = Instant.DISTANT_FUTURE.toEpochMilliseconds()),
onRemoveFromConversation = {},
openChangeRoleBottomSheet = {},
)
}
}

composeTestRule.onNodeWithContentDescription("Edit").assertDoesNotExist()
}

@Test
fun givenARoleSelectionComponentIsShow_ShouldNotAllowModificationForUsersWithoutMetadata() = runTest {
composeTestRule.setContent {
WireTestTheme {
OtherUserProfileGroup(
provideState(withUserName = "", withFullName = ""),
onRemoveFromConversation = {},
openChangeRoleBottomSheet = {},
)
}
}

composeTestRule.onNodeWithContentDescription("Edit").assertDoesNotExist()
}

@Test
fun givenARoleSelectionComponentIsShow_ShouldNotAllowModificationForFederatedUsers() = runTest {
composeTestRule.setContent {
WireTestTheme {
OtherUserProfileGroup(
provideState(withMembership = Membership.Federated),
onRemoveFromConversation = {},
openChangeRoleBottomSheet = {},
)
}
}

composeTestRule.onNodeWithContentDescription("Edit").assertDoesNotExist()
}

@Test
fun givenARoleSelectionComponentIsShow_ShouldNotAllowModificationForServices() = runTest {
composeTestRule.setContent {
WireTestTheme {
OtherUserProfileGroup(
provideState(withMembership = Membership.Service),
onRemoveFromConversation = {},
openChangeRoleBottomSheet = {},
)
}
}

composeTestRule.onNodeWithContentDescription("Edit").assertDoesNotExist()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* 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 http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.other

import androidx.compose.material3.MaterialTheme
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import com.wire.android.ui.WireTestTheme
import com.wire.android.ui.connection.CONNECTION_ACTION_BUTTONS_TEST_TAG
import com.wire.android.ui.home.conversationslist.model.Membership
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.userprofile.other.OtherUserStubs.provideState
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
import org.junit.Rule
import org.junit.Test

class OtherUserProfileScreenTest {
@get:Rule
val composeTestRule by lazy { createComposeRule() }

@Test
fun givenOtherUserProfileFooter_ShouldNotShowConnectButtonForTempUsers() = runTest {
composeTestRule.setContent {
WireTestTheme {
ContentFooter(
state = provideState(withExpireAt = Instant.DISTANT_FUTURE.toEpochMilliseconds()),
maxBarElevation = MaterialTheme.wireDimensions.topBarShadowElevation
)
}
}

composeTestRule.onNodeWithTag(CONNECTION_ACTION_BUTTONS_TEST_TAG).assertDoesNotExist()
}

@Test
fun givenOtherUserProfileFooter_ShouldNotShowConnectButtonForUsersWithoutMetadata() = runTest {
composeTestRule.setContent {
WireTestTheme {
ContentFooter(
state = provideState(withUserName = "", withFullName = ""),
maxBarElevation = MaterialTheme.wireDimensions.topBarShadowElevation
)
}
}

composeTestRule.onNodeWithTag(CONNECTION_ACTION_BUTTONS_TEST_TAG).assertDoesNotExist()
}

@Test
fun givenOtherUserProfileFooter_ShouldNotShowConnectButtonForServices() = runTest {
composeTestRule.setContent {
WireTestTheme {
ContentFooter(
state = provideState(withMembership = Membership.Service),
maxBarElevation = MaterialTheme.wireDimensions.topBarShadowElevation
)
}
}

composeTestRule.onNodeWithTag(CONNECTION_ACTION_BUTTONS_TEST_TAG).assertDoesNotExist()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* 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 http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.other

import com.wire.android.ui.home.conversationslist.model.Membership
import com.wire.kalium.logic.data.conversation.Conversation.Member
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.user.UserId
import kotlinx.datetime.Instant

object OtherUserStubs {
private val baseState = OtherUserProfileState(
userId = UserId("some_user", "domain.com"),
fullName = "name",
userName = "username",
teamName = "team",
email = "email",
groupState = OtherUserProfileGroupState(
groupName = "group name",
role = Member.Role.Member,
isSelfAdmin = true,
conversationId = ConversationId("some_user", "domain.com")
)
)

fun provideState(
withFullName: String = "name",
withUserName: String = "username",
withExpireAt: Long? = null,
withMembership: Membership = Membership.Standard
): OtherUserProfileState {
return baseState.copy(
fullName = withFullName,
userName = withUserName,
expiresAt = withExpireAt?.let { Instant.fromEpochMilliseconds(it) },
membership = withMembership
)
}
}
4 changes: 2 additions & 2 deletions app/src/main/kotlin/com/wire/android/mapper/ContactMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import com.wire.android.model.ImageAsset
import com.wire.android.model.UserAvatarData
import com.wire.android.ui.home.conversationslist.model.Membership
import com.wire.android.ui.home.newconversation.model.Contact
import com.wire.android.ui.userprofile.common.UsernameMapper.mapUserLabel
import com.wire.android.ui.userprofile.common.UsernameMapper
import com.wire.android.util.EMPTY
import com.wire.android.util.ui.WireSessionImageLoader
import com.wire.kalium.logic.data.publicuser.model.UserSearchDetails
Expand All @@ -44,7 +44,7 @@ class ContactMapper
id = id.value,
domain = id.domain,
name = name.orEmpty(),
label = mapUserLabel(otherUser),
label = UsernameMapper.fromOtherUser(otherUser),
avatarData = UserAvatarData(
asset = previewPicture?.let { ImageAsset.UserAvatarAsset(wireSessionImageLoader, it) },
connectionState = connectionStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class UIParticipantMapper @Inject constructor(
isMLSVerified = isMLSVerified,
supportedProtocolList = supportedProtocols.orEmpty().toList(),
isUnderLegalHold = isUnderLegalHold,
expiresAt = user.expiresAt
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.wire.android.R
Expand Down Expand Up @@ -56,6 +57,8 @@ import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.user.ConnectionState
import com.wire.kalium.logic.data.user.UserId

const val CONNECTION_ACTION_BUTTONS_TEST_TAG = "connection_buttons"

@Composable
fun ConnectionActionButton(
userId: UserId,
Expand Down Expand Up @@ -98,6 +101,7 @@ fun ConnectionActionButton(
loading = viewModel.actionableState().isPerformingAction,
onClick = viewModel::onCancelConnectionRequest,
clickBlockParams = ClickBlockParams(blockWhenSyncing = true, blockWhenConnecting = true),
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)

ConnectionState.ACCEPTED -> WirePrimaryButton(
Expand All @@ -108,6 +112,7 @@ fun ConnectionActionButton(
unableStartConversationDialogState.show(UnableStartConversationDialogState(fullName))
}
},
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)

ConnectionState.IGNORED -> WirePrimaryButton(
Expand All @@ -121,7 +126,8 @@ fun ConnectionActionButton(
contentDescription = stringResource(R.string.content_description_right_arrow),
modifier = Modifier.padding(dimensions().spacing8x)
)
}
},
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)

ConnectionState.PENDING -> Column {
Expand All @@ -136,7 +142,8 @@ fun ConnectionActionButton(
contentDescription = stringResource(R.string.content_description_right_arrow),
modifier = Modifier.padding(dimensions().spacing8x)
)
}
},
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)
Spacer(modifier = Modifier.height(dimensions().spacing8x))
WirePrimaryButton(
Expand All @@ -155,7 +162,8 @@ fun ConnectionActionButton(
contentDescription = stringResource(R.string.content_description_right_arrow),
modifier = Modifier.padding(dimensions().spacing8x)
)
}
},
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)
}

Expand All @@ -172,6 +180,7 @@ fun ConnectionActionButton(
)
},
clickBlockParams = ClickBlockParams(blockWhenSyncing = true, blockWhenConnecting = true),
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)
}

Expand All @@ -188,7 +197,8 @@ fun ConnectionActionButton(
contentDescription = stringResource(R.string.content_description_right_arrow),
modifier = Modifier.padding(dimensions().spacing8x)
)
}
},
modifier = Modifier.testTag(CONNECTION_ACTION_BUTTONS_TEST_TAG),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ data class UIParticipant(
val isMLSVerified: Boolean = false,
val supportedProtocolList: List<SupportedProtocol> = listOf(),
val isUnderLegalHold: Boolean = false,
val expiresAt: Instant? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,4 @@ data class Contact(
val label: String = "",
val connectionState: ConnectionState,
val membership: Membership
) {
fun isMetadataEmpty(): Boolean {
return name.isEmpty()
}
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@

package com.wire.android.ui.userprofile.common

import com.wire.android.util.ifNotEmpty
import com.wire.kalium.logic.data.user.OtherUser
import com.wire.kalium.logic.data.user.type.UserType

object UsernameMapper {

fun mapUserLabel(otherUser: OtherUser): String = with(otherUser) {
/**
* Returns the username for the given [OtherUser].
* The username is the handle if it exists, otherwise it is the handle@domain for federated users.
*/
fun fromOtherUser(otherUser: OtherUser): String = with(otherUser) {
val userId = otherUser.id
return when (otherUser.userType) {
UserType.FEDERATED -> if (handle != null) "$handle@${userId.domain}" else ""
UserType.FEDERATED -> handle?.ifNotEmpty { "$handle@${userId.domain}" }.orEmpty()
else -> handle.orEmpty()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ fun OtherUserProfileGroup(
value = AnnotatedString(state.groupState!!.role.name.asString()),
isSelfAdmin = state.groupState.isSelfAdmin,
openChangeRoleBottomSheet = openChangeRoleBottomSheet,
isRoleEditable = state.membership.allowsRoleEdition() && !state.isMetadataEmpty()
isRoleEditable = state.membership.allowsRoleEdition() && !state.isMetadataEmpty() && !state.isTemporaryUser()
)
}
}
Expand Down
Loading

0 comments on commit d746711

Please sign in to comment.