diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 714b48e8b4..82e2177581 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -3246,6 +3246,7 @@
Verified · Last activity %1$s
Unverified · Last activity %1$s
+ Unverified · Your current session
- Inactive for %1$d+ day (%2$s)
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt
index f0a91c6183..373df53b1b 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt
@@ -25,4 +25,5 @@ data class DeviceFullInfo(
val cryptoDeviceInfo: CryptoDeviceInfo?,
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
val isInactive: Boolean,
+ val isCurrentDevice: Boolean,
)
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 f4725d5571..da1a9a2fbd 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
@@ -41,6 +41,7 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER
import im.vector.app.features.settings.devices.v2.list.OtherSessionsView
import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS
+import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationView
import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationViewState
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
import javax.inject.Inject
@@ -84,6 +85,7 @@ class VectorSettingsDevicesFragment :
initLearnMoreButtons()
initWaitingView()
initOtherSessionsView()
+ initSecurityRecommendationsView()
observeViewEvents()
}
@@ -126,6 +128,29 @@ class VectorSettingsDevicesFragment :
views.deviceListOtherSessions.callback = this
}
+ private fun initSecurityRecommendationsView() {
+ views.deviceListUnverifiedSessionsRecommendation.callback = object : SecurityRecommendationView.Callback {
+ override fun onViewAllClicked() {
+ viewNavigator.navigateToOtherSessions(
+ requireActivity(),
+ R.string.device_manager_header_section_security_recommendations_title,
+ DeviceManagerFilterType.UNVERIFIED,
+ includeCurrentSession = true
+ )
+ }
+ }
+ views.deviceListInactiveSessionsRecommendation.callback = object : SecurityRecommendationView.Callback {
+ override fun onViewAllClicked() {
+ viewNavigator.navigateToOtherSessions(
+ requireActivity(),
+ R.string.device_manager_header_section_security_recommendations_title,
+ DeviceManagerFilterType.INACTIVE,
+ includeCurrentSession = true
+ )
+ }
+ }
+ }
+
override fun onDestroyView() {
cleanUpLearnMoreButtonsListeners()
super.onDestroyView()
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt
index c73389d775..283e64fffe 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt
@@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.list
import android.graphics.drawable.Drawable
import android.widget.ImageView
import android.widget.TextView
+import androidx.annotation.ColorInt
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
@@ -45,6 +46,10 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la
@EpoxyAttribute
var sessionDescription: String? = null
+ @EpoxyAttribute
+ @ColorInt
+ var sessionDescriptionColor: Int? = null
+
@EpoxyAttribute
var sessionDescriptionDrawable: Drawable? = null
@@ -82,6 +87,9 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la
holder.otherSessionVerificationStatusImageView.render(roomEncryptionTrustLevel)
holder.otherSessionNameTextView.text = sessionName
holder.otherSessionDescriptionTextView.text = sessionDescription
+ sessionDescriptionColor?.let {
+ holder.otherSessionDescriptionTextView.setTextColor(it)
+ }
holder.otherSessionDescriptionTextView.setCompoundDrawablesWithIntrinsicBounds(sessionDescriptionDrawable, null, null, null)
}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt
index 06f3373f61..bcf6e87575 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt
@@ -53,20 +53,14 @@ class OtherSessionsController @Inject constructor(
data.forEach { device ->
val dateFormatKind = if (device.isInactive) DateFormatKind.TIMELINE_DAY_DIVIDER else DateFormatKind.DEFAULT_DATE_AND_TIME
val formattedLastActivityDate = host.dateFormatter.format(device.deviceInfo.lastSeenTs, dateFormatKind)
- val description = if (device.isInactive) {
- stringProvider.getQuantityString(
- R.plurals.device_manager_other_sessions_description_inactive,
- SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
- SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
- formattedLastActivityDate
- )
- } else if (device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) {
- stringProvider.getString(R.string.device_manager_other_sessions_description_verified, formattedLastActivityDate)
+ val description = calculateDescription(device, formattedLastActivityDate)
+ val descriptionColor = if (device.isCurrentDevice) {
+ host.colorProvider.getColorFromAttribute(R.attr.colorError)
} else {
- stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate)
+ host.colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
}
- val drawableColor = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
- val descriptionDrawable = if (device.isInactive) drawableProvider.getDrawable(R.drawable.ic_inactive_sessions, drawableColor) else null
+ val drawableColor = host.colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
+ val descriptionDrawable = if (device.isInactive) host.drawableProvider.getDrawable(R.drawable.ic_inactive_sessions, drawableColor) else null
otherSessionItem {
id(device.deviceInfo.deviceId)
@@ -75,10 +69,28 @@ class OtherSessionsController @Inject constructor(
sessionName(device.deviceInfo.displayName)
sessionDescription(description)
sessionDescriptionDrawable(descriptionDrawable)
+ sessionDescriptionColor(descriptionColor)
stringProvider(this@OtherSessionsController.stringProvider)
clickListener { device.deviceInfo.deviceId?.let { host.callback?.onItemClicked(it) } }
}
}
}
}
+
+ private fun calculateDescription(device: DeviceFullInfo, formattedLastActivityDate: String): String {
+ return if (device.isInactive) {
+ stringProvider.getQuantityString(
+ R.plurals.device_manager_other_sessions_description_inactive,
+ SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
+ SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
+ formattedLastActivityDate
+ )
+ } else if (device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) {
+ stringProvider.getString(R.string.device_manager_other_sessions_description_verified, formattedLastActivityDate)
+ } else if (device.isCurrentDevice) {
+ stringProvider.getString(R.string.device_manager_other_sessions_description_unverified_current_session)
+ } else {
+ stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate)
+ }
+ }
}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt
index 93cf3c0501..c4d86af8c3 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt
@@ -31,7 +31,12 @@ class SecurityRecommendationView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
+ interface Callback {
+ fun onViewAllClicked()
+ }
+
private val views: ViewSecurityRecommendationBinding
+ var callback: Callback? = null
init {
inflate(context, R.layout.view_security_recommendation, this)
@@ -47,6 +52,10 @@ class SecurityRecommendationView @JvmOverloads constructor(
setDescription(it)
setImage(it)
}
+
+ views.recommendationViewAllButton.setOnClickListener {
+ callback?.onViewAllClicked()
+ }
}
private fun setTitle(typedArray: TypedArray) {
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 a40d95c6d9..2ca24dd92a 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
@@ -30,7 +30,7 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
import kotlinx.coroutines.Job
class OtherSessionsViewModel @AssistedInject constructor(
- @Assisted initialState: OtherSessionsViewState,
+ @Assisted private val initialState: OtherSessionsViewState,
activeSessionHolder: ActiveSessionHolder,
private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase,
refreshDevicesUseCase: RefreshDevicesUseCase
@@ -55,7 +55,7 @@ class OtherSessionsViewModel @AssistedInject constructor(
observeDevicesJob?.cancel()
observeDevicesJob = getDeviceFullInfoListUseCase.execute(
filterType = currentFilter,
- excludeCurrentDevice = true
+ excludeCurrentDevice = !initialState.includeCurrentSession
)
.execute { async ->
copy(
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 d03cba03f9..cb30490845 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
@@ -25,4 +25,8 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
data class OtherSessionsViewState(
val devices: Async> = Uninitialized,
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
-) : MavericksState
+ val includeCurrentSession: Boolean = false,
+) : MavericksState {
+
+ constructor(args: OtherSessionsArgs) : this(includeCurrentSession = args.includeCurrentSession)
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt
index 5a8106f2fd..72a48238b0 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt
@@ -48,11 +48,13 @@ class GetDeviceFullInfoUseCase @Inject constructor(
val fullInfo = if (info != null && cryptoInfo != null) {
val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoInfo)
val isInactive = checkIfSessionIsInactiveUseCase.execute(info.lastSeenTs ?: 0)
+ val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoInfo.deviceId
DeviceFullInfo(
deviceInfo = info,
cryptoDeviceInfo = cryptoInfo,
roomEncryptionTrustLevel = roomEncryptionTrustLevel,
- isInactive = isInactive
+ isInactive = isInactive,
+ isCurrentDevice = isCurrentDevice,
)
} else {
null