Merge pull request #7707 from vector-im/feature/mna/rename-and-signout-action-current-session

[Session manager] Add actions to rename and signout current session (PSG-885)
This commit is contained in:
Maxime NATUREL 2022-12-07 16:16:44 +01:00 committed by GitHub
commit c580090f20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 40 deletions

1
changelog.d/7697.feature Normal file
View File

@ -0,0 +1 @@
[Session manager] Add actions to rename and signout current session

View File

@ -52,6 +52,7 @@ import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationVie
import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationViewState import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationViewState
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
import im.vector.app.features.settings.devices.v2.signout.BuildConfirmSignoutDialogUseCase import im.vector.app.features.settings.devices.v2.signout.BuildConfirmSignoutDialogUseCase
import im.vector.app.features.workers.signout.SignOutUiWorker
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
@ -101,6 +102,7 @@ class VectorSettingsDevicesFragment :
initWaitingView() initWaitingView()
initCurrentSessionHeaderView() initCurrentSessionHeaderView()
initCurrentSessionView()
initOtherSessionsHeaderView() initOtherSessionsHeaderView()
initOtherSessionsView() initOtherSessionsView()
initSecurityRecommendationsView() initSecurityRecommendationsView()
@ -144,6 +146,14 @@ class VectorSettingsDevicesFragment :
private fun initCurrentSessionHeaderView() { private fun initCurrentSessionHeaderView() {
views.deviceListHeaderCurrentSession.setOnMenuItemClickListener { menuItem -> views.deviceListHeaderCurrentSession.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) { when (menuItem.itemId) {
R.id.currentSessionHeaderRename -> {
navigateToRenameCurrentSession()
true
}
R.id.currentSessionHeaderSignout -> {
confirmSignoutCurrentSession()
true
}
R.id.currentSessionHeaderSignoutOtherSessions -> { R.id.currentSessionHeaderSignoutOtherSessions -> {
confirmMultiSignoutOtherSessions() confirmMultiSignoutOtherSessions()
true true
@ -153,6 +163,26 @@ class VectorSettingsDevicesFragment :
} }
} }
private fun navigateToRenameCurrentSession() = withState(viewModel) { state ->
val currentDeviceId = state.currentSessionCrossSigningInfo.deviceId
if (currentDeviceId.isNotEmpty()) {
viewNavigator.navigateToRenameSession(
context = requireActivity(),
deviceId = currentDeviceId,
)
}
}
private fun confirmSignoutCurrentSession() {
activity?.let { SignOutUiWorker(it).perform() }
}
private fun initCurrentSessionView() {
views.deviceListCurrentSession.viewVerifyButton.debouncedClicks {
viewModel.handle(DevicesAction.VerifyCurrentSession)
}
}
private fun initOtherSessionsHeaderView() { private fun initOtherSessionsHeaderView() {
views.deviceListHeaderOtherSessions.setOnMenuItemClickListener { menuItem -> views.deviceListHeaderOtherSessions.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) { when (menuItem.itemId) {
@ -351,15 +381,28 @@ class VectorSettingsDevicesFragment :
private fun renderCurrentSessionView(currentDeviceInfo: DeviceFullInfo?, hasOtherDevices: Boolean) { private fun renderCurrentSessionView(currentDeviceInfo: DeviceFullInfo?, hasOtherDevices: Boolean) {
currentDeviceInfo?.let { currentDeviceInfo?.let {
renderCurrentSessionHeaderView(hasOtherDevices)
renderCurrentSessionListView(it)
} ?: run {
hideCurrentSessionView()
}
}
private fun renderCurrentSessionHeaderView(hasOtherDevices: Boolean) {
views.deviceListHeaderCurrentSession.isVisible = true views.deviceListHeaderCurrentSession.isVisible = true
val colorDestructive = colorProvider.getColorFromAttribute(R.attr.colorError) 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) val signoutOtherSessionsItem = views.deviceListHeaderCurrentSession.menu.findItem(R.id.currentSessionHeaderSignoutOtherSessions)
signoutOtherSessionsItem.setTextColor(colorDestructive) signoutOtherSessionsItem.setTextColor(colorDestructive)
signoutOtherSessionsItem.isVisible = hasOtherDevices signoutOtherSessionsItem.isVisible = hasOtherDevices
}
private fun renderCurrentSessionListView(currentDeviceInfo: DeviceFullInfo) {
views.deviceListCurrentSession.isVisible = true views.deviceListCurrentSession.isVisible = true
val viewState = SessionInfoViewState( val viewState = SessionInfoViewState(
isCurrentSession = true, isCurrentSession = true,
deviceFullInfo = it deviceFullInfo = currentDeviceInfo
) )
views.deviceListCurrentSession.render(viewState, dateFormatter, drawableProvider, colorProvider, stringProvider) views.deviceListCurrentSession.render(viewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
views.deviceListCurrentSession.debouncedClicks { views.deviceListCurrentSession.debouncedClicks {
@ -368,12 +411,6 @@ class VectorSettingsDevicesFragment :
views.deviceListCurrentSession.viewDetailsButton.debouncedClicks { views.deviceListCurrentSession.viewDetailsButton.debouncedClicks {
currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) }
} }
views.deviceListCurrentSession.viewVerifyButton.debouncedClicks {
viewModel.handle(DevicesAction.VerifyCurrentSession)
}
} ?: run {
hideCurrentSessionView()
}
} }
private fun navigateToSessionOverview(deviceId: String) { private fun navigateToSessionOverview(deviceId: String) {

View File

@ -20,6 +20,7 @@ import android.content.Context
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsActivity import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsActivity
import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity
import im.vector.app.features.settings.devices.v2.rename.RenameSessionActivity
import javax.inject.Inject import javax.inject.Inject
class VectorSettingsDevicesViewNavigator @Inject constructor() { class VectorSettingsDevicesViewNavigator @Inject constructor() {
@ -38,4 +39,8 @@ class VectorSettingsDevicesViewNavigator @Inject constructor() {
OtherSessionsActivity.newIntent(context, titleResourceId, defaultFilter, excludeCurrentDevice) OtherSessionsActivity.newIntent(context, titleResourceId, defaultFilter, excludeCurrentDevice)
) )
} }
fun navigateToRenameSession(context: Context, deviceId: String) {
context.startActivity(RenameSessionActivity.newIntent(context, deviceId))
}
} }

View File

@ -4,6 +4,16 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AlwaysShowAction"> tools:ignore="AlwaysShowAction">
<item
android:id="@+id/currentSessionHeaderRename"
android:title="@string/device_manager_session_rename"
app:showAsAction="withText|never" />
<item
android:id="@+id/currentSessionHeaderSignout"
android:title="@string/logout"
app:showAsAction="withText|never" />
<item <item
android:id="@+id/currentSessionHeaderSignoutOtherSessions" android:id="@+id/currentSessionHeaderSignoutOtherSessions"
android:title="@string/device_manager_signout_all_other_sessions" android:title="@string/device_manager_signout_all_other_sessions"

View File

@ -20,12 +20,12 @@ import android.content.Intent
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsActivity import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsActivity
import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity
import im.vector.app.features.settings.devices.v2.rename.RenameSessionActivity
import im.vector.app.test.fakes.FakeContext import im.vector.app.test.fakes.FakeContext
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkObject import io.mockk.mockkObject
import io.mockk.unmockkAll import io.mockk.unmockkAll
import io.mockk.verify
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -43,6 +43,7 @@ class VectorSettingsDevicesViewNavigatorTest {
fun setUp() { fun setUp() {
mockkObject(SessionOverviewActivity.Companion) mockkObject(SessionOverviewActivity.Companion)
mockkObject(OtherSessionsActivity.Companion) mockkObject(OtherSessionsActivity.Companion)
mockkObject(RenameSessionActivity.Companion)
} }
@After @After
@ -52,26 +53,41 @@ class VectorSettingsDevicesViewNavigatorTest {
@Test @Test
fun `given a session id when navigating to overview then it starts the correct activity`() { fun `given a session id when navigating to overview then it starts the correct activity`() {
// Given
val intent = givenIntentForSessionOverview(A_SESSION_ID) val intent = givenIntentForSessionOverview(A_SESSION_ID)
context.givenStartActivity(intent) context.givenStartActivity(intent)
// When
vectorSettingsDevicesViewNavigator.navigateToSessionOverview(context.instance, A_SESSION_ID) vectorSettingsDevicesViewNavigator.navigateToSessionOverview(context.instance, A_SESSION_ID)
verify { // Then
context.instance.startActivity(intent) context.verifyStartActivity(intent)
}
} }
@Test @Test
fun `given an intent when navigating to other sessions list then it starts the correct activity`() { fun `given an intent when navigating to other sessions list then it starts the correct activity`() {
// Given
val intent = givenIntentForOtherSessions(A_TITLE_RESOURCE_ID, A_DEFAULT_FILTER, true) val intent = givenIntentForOtherSessions(A_TITLE_RESOURCE_ID, A_DEFAULT_FILTER, true)
context.givenStartActivity(intent) context.givenStartActivity(intent)
// When
vectorSettingsDevicesViewNavigator.navigateToOtherSessions(context.instance, A_TITLE_RESOURCE_ID, A_DEFAULT_FILTER, true) vectorSettingsDevicesViewNavigator.navigateToOtherSessions(context.instance, A_TITLE_RESOURCE_ID, A_DEFAULT_FILTER, true)
verify { // Then
context.instance.startActivity(intent) context.verifyStartActivity(intent)
} }
@Test
fun `given an intent when navigating to rename session screen then it starts the correct activity`() {
// Given
val intent = givenIntentForRenameSession(A_SESSION_ID)
context.givenStartActivity(intent)
// When
vectorSettingsDevicesViewNavigator.navigateToRenameSession(context.instance, A_SESSION_ID)
// Then
context.verifyStartActivity(intent)
} }
private fun givenIntentForSessionOverview(sessionId: String): Intent { private fun givenIntentForSessionOverview(sessionId: String): Intent {
@ -85,4 +101,10 @@ class VectorSettingsDevicesViewNavigatorTest {
every { OtherSessionsActivity.newIntent(context.instance, titleResourceId, defaultFilter, excludeCurrentDevice) } returns intent every { OtherSessionsActivity.newIntent(context.instance, titleResourceId, defaultFilter, excludeCurrentDevice) } returns intent
return intent return intent
} }
private fun givenIntentForRenameSession(sessionId: String): Intent {
val intent = mockk<Intent>()
every { RenameSessionActivity.newIntent(context.instance, sessionId) } returns intent
return intent
}
} }

View File

@ -23,7 +23,6 @@ import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkObject import io.mockk.mockkObject
import io.mockk.unmockkAll import io.mockk.unmockkAll
import io.mockk.verify
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -47,14 +46,15 @@ class OtherSessionsViewNavigatorTest {
@Test @Test
fun `given a device id when navigating to overview then it starts the correct activity`() { fun `given a device id when navigating to overview then it starts the correct activity`() {
// Given
val intent = givenIntentForDeviceOverview(A_DEVICE_ID) val intent = givenIntentForDeviceOverview(A_DEVICE_ID)
context.givenStartActivity(intent) context.givenStartActivity(intent)
// When
otherSessionsViewNavigator.navigateToSessionOverview(context.instance, A_DEVICE_ID) otherSessionsViewNavigator.navigateToSessionOverview(context.instance, A_DEVICE_ID)
verify { // Then
context.instance.startActivity(intent) context.verifyStartActivity(intent)
}
} }
private fun givenIntentForDeviceOverview(deviceId: String): Intent { private fun givenIntentForDeviceOverview(deviceId: String): Intent {

View File

@ -60,9 +60,7 @@ class SessionOverviewViewNavigatorTest {
sessionOverviewViewNavigator.goToSessionDetails(context.instance, A_SESSION_ID) sessionOverviewViewNavigator.goToSessionDetails(context.instance, A_SESSION_ID)
// Then // Then
verify { context.verifyStartActivity(intent)
context.instance.startActivity(intent)
}
} }
@Test @Test
@ -75,9 +73,7 @@ class SessionOverviewViewNavigatorTest {
sessionOverviewViewNavigator.goToRenameSession(context.instance, A_SESSION_ID) sessionOverviewViewNavigator.goToRenameSession(context.instance, A_SESSION_ID)
// Then // Then
verify { context.verifyStartActivity(intent)
context.instance.startActivity(intent)
}
} }
@Test @Test

View File

@ -24,9 +24,9 @@ import android.net.ConnectivityManager
import android.net.Uri import android.net.Uri
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.justRun
import io.mockk.mockk import io.mockk.mockk
import io.mockk.runs import io.mockk.verify
import java.io.OutputStream import java.io.OutputStream
class FakeContext( class FakeContext(
@ -73,7 +73,11 @@ class FakeContext(
} }
fun givenStartActivity(intent: Intent) { fun givenStartActivity(intent: Intent) {
every { instance.startActivity(intent) } just runs justRun { instance.startActivity(intent) }
}
fun verifyStartActivity(intent: Intent) {
verify { instance.startActivity(intent) }
} }
fun givenClipboardManager(): FakeClipboardManager { fun givenClipboardManager(): FakeClipboardManager {