mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Render security recommendation sessions.
This commit is contained in:
parent
740b69d48c
commit
7db222af0c
9 changed files with 78 additions and 16 deletions
|
@ -3246,6 +3246,7 @@
|
|||
<string name="device_manager_other_sessions_description_verified">Verified · Last activity %1$s</string>
|
||||
<!-- Examples: Unverified · Last activity Yesterday at 6PM, Unverified · Last activity Aug 31 at 5:47PM -->
|
||||
<string name="device_manager_other_sessions_description_unverified">Unverified · Last activity %1$s</string>
|
||||
<string name="device_manager_other_sessions_description_unverified_current_session">Unverified · Your current session</string>
|
||||
<!-- Example: Inactive for 90+ days (Dec 25, 2021) -->
|
||||
<plurals name="device_manager_other_sessions_description_inactive">
|
||||
<item quantity="one">Inactive for %1$d+ day (%2$s)</item>
|
||||
|
|
|
@ -25,4 +25,5 @@ data class DeviceFullInfo(
|
|||
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
||||
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
|
||||
val isInactive: Boolean,
|
||||
val isCurrentDevice: Boolean,
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<OtherSessionItem.Holder>(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<OtherSessionItem.Holder>(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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -25,4 +25,8 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
|||
data class OtherSessionsViewState(
|
||||
val devices: Async<List<DeviceFullInfo>> = Uninitialized,
|
||||
val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS,
|
||||
) : MavericksState
|
||||
val includeCurrentSession: Boolean = false,
|
||||
) : MavericksState {
|
||||
|
||||
constructor(args: OtherSessionsArgs) : this(includeCurrentSession = args.includeCurrentSession)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue