From 8941e6396c555b0fa17230ad4629356875d04837 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Tue, 22 Aug 2023 12:04:38 +0200
Subject: [PATCH] Hide multi signout if we have an external account manager
 (#8616)

---
 .../settings/devices/v2/DevicesViewModel.kt    | 14 +++++++++++++-
 .../settings/devices/v2/DevicesViewState.kt    |  1 +
 .../v2/VectorSettingsDevicesFragment.kt        | 18 +++++++++++-------
 .../v2/othersessions/OtherSessionsFragment.kt  | 11 ++++++++---
 .../v2/othersessions/OtherSessionsViewModel.kt | 14 +++++++++++++-
 .../v2/othersessions/OtherSessionsViewState.kt |  1 +
 6 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt
index f2e6b25f32..369150d45e 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt
@@ -40,7 +40,7 @@ import timber.log.Timber
 
 class DevicesViewModel @AssistedInject constructor(
         @Assisted initialState: DevicesViewState,
-        activeSessionHolder: ActiveSessionHolder,
+        private val activeSessionHolder: ActiveSessionHolder,
         private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
         private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
         private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase,
@@ -69,6 +69,18 @@ class DevicesViewModel @AssistedInject constructor(
         refreshDeviceList()
         refreshIpAddressVisibility()
         observePreferences()
+        initExternalAccountManagementUrl()
+    }
+
+    private fun initExternalAccountManagementUrl() {
+        setState {
+            copy(
+                    externalAccountManagementUrl = activeSessionHolder.getSafeActiveSession()
+                            ?.homeServerCapabilitiesService()
+                            ?.getHomeServerCapabilities()
+                            ?.externalAccountManagementUrl
+            )
+        }
     }
 
     override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt
index 75d0f132bb..863ecd17a3 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt
@@ -26,6 +26,7 @@ data class DevicesViewState(
         val devices: Async<DeviceFullInfoList> = Uninitialized,
         val isLoading: Boolean = false,
         val isShowingIpAddress: Boolean = false,
+        val externalAccountManagementUrl: String? = null,
 ) : MavericksState
 
 data class DeviceFullInfoList(
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt
index ec21970f94..2850064609 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt
@@ -290,8 +290,8 @@ class VectorSettingsDevicesFragment :
             val unverifiedSessionsCount = deviceFullInfoList?.unverifiedSessionsCount ?: 0
 
             renderSecurityRecommendations(inactiveSessionsCount, unverifiedSessionsCount)
-            renderCurrentSessionView(currentDeviceInfo, hasOtherDevices = otherDevices?.isNotEmpty().orFalse())
-            renderOtherSessionsView(otherDevices, state.isShowingIpAddress)
+            renderCurrentSessionView(currentDeviceInfo, hasOtherDevices = otherDevices?.isNotEmpty().orFalse(), state)
+            renderOtherSessionsView(otherDevices, state)
         } else {
             hideSecurityRecommendations()
             hideCurrentSessionView()
@@ -347,13 +347,16 @@ class VectorSettingsDevicesFragment :
         hideInactiveSessionsRecommendation()
     }
 
-    private fun renderOtherSessionsView(otherDevices: List<DeviceFullInfo>?, isShowingIpAddress: Boolean) {
+    private fun renderOtherSessionsView(otherDevices: List<DeviceFullInfo>?, state: DevicesViewState) {
+        val isShowingIpAddress = state.isShowingIpAddress
         if (otherDevices.isNullOrEmpty()) {
             hideOtherSessionsView()
         } else {
             views.deviceListHeaderOtherSessions.isVisible = true
             val colorDestructive = colorProvider.getColorFromAttribute(R.attr.colorError)
             val multiSignoutItem = views.deviceListHeaderOtherSessions.menu.findItem(R.id.otherSessionsHeaderMultiSignout)
+            // Hide multi signout if we have an external account manager
+            multiSignoutItem.isVisible = state.externalAccountManagementUrl == null
             val nbDevices = otherDevices.size
             multiSignoutItem.title = stringProvider.getQuantityString(R.plurals.device_manager_other_sessions_multi_signout_all, nbDevices, nbDevices)
             multiSignoutItem.setTextColor(colorDestructive)
@@ -377,23 +380,24 @@ class VectorSettingsDevicesFragment :
         views.deviceListOtherSessions.isVisible = false
     }
 
-    private fun renderCurrentSessionView(currentDeviceInfo: DeviceFullInfo?, hasOtherDevices: Boolean) {
+    private fun renderCurrentSessionView(currentDeviceInfo: DeviceFullInfo?, hasOtherDevices: Boolean, state: DevicesViewState) {
         currentDeviceInfo?.let {
-            renderCurrentSessionHeaderView(hasOtherDevices)
+            renderCurrentSessionHeaderView(hasOtherDevices, state)
             renderCurrentSessionListView(it)
         } ?: run {
             hideCurrentSessionView()
         }
     }
 
-    private fun renderCurrentSessionHeaderView(hasOtherDevices: Boolean) {
+    private fun renderCurrentSessionHeaderView(hasOtherDevices: Boolean, state: DevicesViewState) {
         views.deviceListHeaderCurrentSession.isVisible = true
         val colorDestructive = colorProvider.getColorFromAttribute(R.attr.colorError)
         val signoutSessionItem = views.deviceListHeaderCurrentSession.menu.findItem(R.id.currentSessionHeaderSignout)
         signoutSessionItem.setTextColor(colorDestructive)
         val signoutOtherSessionsItem = views.deviceListHeaderCurrentSession.menu.findItem(R.id.currentSessionHeaderSignoutOtherSessions)
         signoutOtherSessionsItem.setTextColor(colorDestructive)
-        signoutOtherSessionsItem.isVisible = hasOtherDevices
+        // Hide signout other sessions if we have an external account manager
+        signoutOtherSessionsItem.isVisible = hasOtherDevices && state.externalAccountManagementUrl == null
     }
 
     private fun renderCurrentSessionListView(currentDeviceInfo: DeviceFullInfo) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt
index 78075ca185..f935cb83ab 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt
@@ -103,10 +103,15 @@ class OtherSessionsFragment :
             val nbDevices = viewState.devices()?.size ?: 0
             stringProvider.getQuantityString(R.plurals.device_manager_other_sessions_multi_signout_all, nbDevices, nbDevices)
         }
-        multiSignoutItem.isVisible = if (viewState.isSelectModeEnabled) {
-            viewState.devices.invoke()?.any { it.isSelected }.orFalse()
+        multiSignoutItem.isVisible = if (viewState.externalAccountManagementUrl != null) {
+            // Hide multi signout if we have an external account manager
+            false
         } else {
-            viewState.devices.invoke()?.isNotEmpty().orFalse()
+            if (viewState.isSelectModeEnabled) {
+                viewState.devices.invoke()?.any { it.isSelected }.orFalse()
+            } else {
+                viewState.devices.invoke()?.isNotEmpty().orFalse()
+            }
         }
         val showAsActionFlag = if (viewState.isSelectModeEnabled) MenuItem.SHOW_AS_ACTION_IF_ROOM else MenuItem.SHOW_AS_ACTION_NEVER
         multiSignoutItem.setShowAsAction(showAsActionFlag or MenuItem.SHOW_AS_ACTION_WITH_TEXT)
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt
index a5282e7ba2..3d41850027 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt
@@ -41,7 +41,7 @@ import timber.log.Timber
 
 class OtherSessionsViewModel @AssistedInject constructor(
         @Assisted private val initialState: OtherSessionsViewState,
-        activeSessionHolder: ActiveSessionHolder,
+        private val activeSessionHolder: ActiveSessionHolder,
         private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
         private val signoutSessionsUseCase: SignoutSessionsUseCase,
         private val pendingAuthHandler: PendingAuthHandler,
@@ -65,6 +65,18 @@ class OtherSessionsViewModel @AssistedInject constructor(
         observeDevices(initialState.currentFilter)
         refreshIpAddressVisibility()
         observePreferences()
+        initExternalAccountManagementUrl()
+    }
+
+    private fun initExternalAccountManagementUrl() {
+        setState {
+            copy(
+                    externalAccountManagementUrl = activeSessionHolder.getSafeActiveSession()
+                            ?.homeServerCapabilitiesService()
+                            ?.getHomeServerCapabilities()
+                            ?.externalAccountManagementUrl
+            )
+        }
     }
 
     override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt
index f4dd3640ee..ccb3e57f41 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt
@@ -29,6 +29,7 @@ data class OtherSessionsViewState(
         val isSelectModeEnabled: Boolean = false,
         val isLoading: Boolean = false,
         val isShowingIpAddress: Boolean = false,
+        val externalAccountManagementUrl: String? = null,
 ) : MavericksState {
 
     constructor(args: OtherSessionsArgs) : this(excludeCurrentDevice = args.excludeCurrentDevice)