From 22a0b22c4e4dc4c1086df242ccc013389750679c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Zag=C3=B3rski?= <mateusz.zagorski.ext@wire.com>
Date: Wed, 18 Dec 2024 19:17:50 +0100
Subject: [PATCH] feat: Add option to manage team [#WPB-14873] (#3753)

---
 .../android/di/accountScoped/UserModule.kt    |  6 +++++
 .../userprofile/self/SelfUserProfileScreen.kt | 22 ++++++++++++++++++-
 .../userprofile/self/SelfUserProfileState.kt  |  1 +
 .../self/SelfUserProfileViewModel.kt          |  6 ++++-
 app/src/main/res/values/strings.xml           |  2 ++
 .../SelfUserProfileViewModelArrangement.kt    |  8 ++++++-
 kalium                                        |  2 +-
 7 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt b/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt
index e4ed7d01bfa..2c8c7ac115c 100644
--- a/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt
+++ b/app/src/main/kotlin/com/wire/android/di/accountScoped/UserModule.kt
@@ -37,6 +37,7 @@ import com.wire.kalium.logic.feature.personaltoteamaccount.CanMigrateFromPersona
 import com.wire.kalium.logic.feature.publicuser.GetAllContactsUseCase
 import com.wire.kalium.logic.feature.publicuser.GetKnownUserUseCase
 import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase
+import com.wire.kalium.logic.feature.server.GetTeamUrlUseCase
 import com.wire.kalium.logic.feature.user.DeleteAccountUseCase
 import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
 import com.wire.kalium.logic.feature.user.GetUserInfoUseCase
@@ -191,6 +192,11 @@ class UserModule {
     fun provideGetSelfUseCase(userScope: UserScope): GetSelfUserUseCase =
         userScope.getSelfUser
 
+    @ViewModelScoped
+    @Provides
+    fun provideGetTeamUrlUseCase(userScope: UserScope): GetTeamUrlUseCase =
+        userScope.getTeamUrl
+
     @ViewModelScoped
     @Provides
     fun provideGetAvatarAssetUseCase(userScope: UserScope): GetAvatarAssetUseCase =
diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileScreen.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileScreen.kt
index e09da4b1532..60d081bf260 100644
--- a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileScreen.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileScreen.kt
@@ -25,6 +25,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.scrollable
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.defaultMinSize
@@ -43,6 +44,7 @@ import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalUriHandler
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
@@ -208,6 +210,7 @@ private fun SelfUserProfileContent(
     isUserInCall: () -> Boolean
 ) {
     val snackbarHostState = LocalSnackbarHostState.current
+    val uriHandler = LocalUriHandler.current
 
     state.errorMessageCode?.let { errorCode ->
         val errorMessage = mapErrorCodeToString(errorCode)
@@ -345,7 +348,13 @@ private fun SelfUserProfileContent(
 
                 Divider(color = MaterialTheme.wireColorScheme.outline)
 
-                Box(modifier = Modifier.padding(dimensions().spacing16x)) {
+                Column(
+                    modifier = Modifier.padding(dimensions().spacing16x),
+                    verticalArrangement = Arrangement.spacedBy(dimensions().spacing8x)
+                ) {
+                    if (teamUrl != null) {
+                        ManageTeamButton { uriHandler.openUri(teamUrl) }
+                    }
                     NewTeamButton(onAddAccountClick, isUserInCall, context)
                 }
             }
@@ -440,6 +449,17 @@ private fun CurrentSelfUserStatus(
     }
 }
 
+@Composable
+private fun ManageTeamButton(
+    onManageTeamClick: () -> Unit
+) {
+    WireSecondaryButton(
+        text = stringResource(R.string.user_profile_account_management),
+        onClickDescription = stringResource(R.string.content_description_self_profile_manage_team_btn),
+        onClick = onManageTeamClick
+    )
+}
+
 @Composable
 private fun NewTeamButton(
     onAddAccountClick: () -> Unit,
diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileState.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileState.kt
index c5ffb5c647a..5c2a742f02d 100644
--- a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileState.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileState.kt
@@ -34,6 +34,7 @@ data class SelfUserProfileState(
     val fullName: String = "",
     val userName: String = "",
     val teamName: String? = "", // maybe teamId is better here
+    val teamUrl: String? = null,
     val otherAccounts: List<OtherAccount> = emptyList(),
     val statusDialogData: StatusDialogData? = null, // null means no dialog to display
     val isAvatarLoading: Boolean = false,
diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModel.kt
index 7ea1e925b6b..2820cc43ae5 100644
--- a/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModel.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModel.kt
@@ -48,12 +48,14 @@ import com.wire.kalium.logic.data.user.SelfUser
 import com.wire.kalium.logic.data.user.UserAssetId
 import com.wire.kalium.logic.data.user.UserAvailabilityStatus
 import com.wire.kalium.logic.data.user.UserId
+import com.wire.kalium.logic.data.user.type.UserType
 import com.wire.kalium.logic.feature.auth.LogoutUseCase
 import com.wire.kalium.logic.feature.call.usecase.EndCallUseCase
 import com.wire.kalium.logic.feature.call.usecase.ObserveEstablishedCallsUseCase
 import com.wire.kalium.logic.feature.legalhold.LegalHoldStateForSelfUser
 import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForSelfUserUseCase
 import com.wire.kalium.logic.feature.personaltoteamaccount.CanMigrateFromPersonalToTeamUseCase
+import com.wire.kalium.logic.feature.server.GetTeamUrlUseCase
 import com.wire.kalium.logic.feature.team.GetUpdatedSelfTeamUseCase
 import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
 import com.wire.kalium.logic.feature.user.IsReadOnlyAccountUseCase
@@ -98,7 +100,8 @@ class SelfUserProfileViewModel @Inject constructor(
     private val notificationManager: WireNotificationManager,
     private val globalDataStore: GlobalDataStore,
     private val qualifiedIdMapper: QualifiedIdMapper,
-    private val anonymousAnalyticsManager: AnonymousAnalyticsManager
+    private val anonymousAnalyticsManager: AnonymousAnalyticsManager,
+    private val getTeamUrl: GetTeamUrlUseCase
 ) : ViewModel() {
 
     var userProfileState by mutableStateOf(SelfUserProfileState(userId = selfUserId, isAvatarLoading = true))
@@ -176,6 +179,7 @@ class SelfUserProfileViewModel @Inject constructor(
                             fullName = name.orEmpty(),
                             userName = handle.orEmpty(),
                             teamName = selfTeam?.name,
+                            teamUrl = getTeamUrl().takeIf { userType == UserType.OWNER || userType == UserType.ADMIN },
                             otherAccounts = otherAccounts,
                             avatarAsset = userProfileState.avatarAsset,
                             isAvatarLoading = false,
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4811da7ef86..f12f3cbc10a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -242,6 +242,7 @@
     <string name="content_description_self_profile_team">Team name, %s</string>
     <string name="content_description_self_profile_change_status">change availability status</string>
     <string name="content_description_self_profile_new_account_btn">Create a new team or personal account or log in</string>
+    <string name="content_description_self_profile_manage_team_btn">Manage team</string>
     <string name="content_description_change_picture_back_btn">Go back to your profile overview</string>
     <string name="content_description_welcome_screen_close_btn">Close new team creation and login view</string>
     <string name="content_description_login_back_btn">Go back to new team creation and login view</string>
@@ -612,6 +613,7 @@
     <string name="user_profile_status_away">Away</string>
     <string name="user_profile_status_none">None</string>
     <string name="user_profile_new_account_text">New Team or Add Account</string>
+    <string name="user_profile_account_management">Manage Team</string>
     <string name="user_profile_details_tab">Details</string>
     <string name="user_profile_devices_tab">Devices</string>
     <string name="user_profile_group_tab">Group</string>
diff --git a/app/src/test/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModelArrangement.kt
index 47b10e19c10..b278b335428 100644
--- a/app/src/test/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModelArrangement.kt
+++ b/app/src/test/kotlin/com/wire/android/ui/userprofile/self/SelfUserProfileViewModelArrangement.kt
@@ -35,6 +35,7 @@ import com.wire.kalium.logic.feature.call.usecase.ObserveEstablishedCallsUseCase
 import com.wire.kalium.logic.feature.legalhold.LegalHoldStateForSelfUser
 import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForSelfUserUseCase
 import com.wire.kalium.logic.feature.personaltoteamaccount.CanMigrateFromPersonalToTeamUseCase
+import com.wire.kalium.logic.feature.server.GetTeamUrlUseCase
 import com.wire.kalium.logic.feature.team.GetUpdatedSelfTeamUseCase
 import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
 import com.wire.kalium.logic.feature.user.IsReadOnlyAccountUseCase
@@ -101,6 +102,9 @@ class SelfUserProfileViewModelArrangement {
     @MockK
     lateinit var canMigrateFromPersonalToTeam: CanMigrateFromPersonalToTeamUseCase
 
+    @MockK
+    lateinit var getTeamUrl: GetTeamUrlUseCase
+
     private val viewModel by lazy {
         SelfUserProfileViewModel(
             selfUserId = TestUser.SELF_USER.id,
@@ -121,7 +125,8 @@ class SelfUserProfileViewModelArrangement {
             globalDataStore = globalDataStore,
             qualifiedIdMapper = qualifiedIdMapper,
             anonymousAnalyticsManager = anonymousAnalyticsManager,
-            canMigrateFromPersonalToTeam = canMigrateFromPersonalToTeam
+            canMigrateFromPersonalToTeam = canMigrateFromPersonalToTeam,
+            getTeamUrl = getTeamUrl
         )
     }
 
@@ -136,6 +141,7 @@ class SelfUserProfileViewModelArrangement {
         coEvery { observeEstablishedCalls.invoke() } returns flowOf(emptyList())
         coEvery { observeEstablishedCalls.invoke() } returns flowOf(emptyList())
         coEvery { canMigrateFromPersonalToTeam.invoke() } returns true
+        coEvery { getTeamUrl.invoke() } returns ""
     }
 
     fun withLegalHoldStatus(result: LegalHoldStateForSelfUser) = apply {
diff --git a/kalium b/kalium
index 1ca6dfc988e..91b8319e99d 160000
--- a/kalium
+++ b/kalium
@@ -1 +1 @@
-Subproject commit 1ca6dfc988eeccf550858620ae1dadf8e49555da
+Subproject commit 91b8319e99d83e486751967c8adf4f027d57a82e