Settings Sessions / Now live + support devices with no keys

This commit is contained in:
Valere 2020-01-31 10:33:53 +01:00
parent 7b385c3b36
commit 8e5c7239cf
5 changed files with 90 additions and 32 deletions

View file

@ -53,7 +53,7 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
var detailedMode = false
@EpoxyAttribute
var trusted : Boolean? = false
var trusted : Boolean? = null
override fun bind(holder: Holder) {
holder.root.setOnClickListener { itemClickAction?.invoke() }

View file

@ -16,7 +16,9 @@
package im.vector.riotx.features.settings.devices
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
@ -24,24 +26,56 @@ import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.rx.rx
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
data class DeviceVerificationInfoBottomSheetViewState(
val cryptoDeviceInfo: Async<CryptoDeviceInfo> = Uninitialized
val cryptoDeviceInfo: Async<CryptoDeviceInfo?> = Uninitialized,
val deviceInfo: Async<DeviceInfo> = Uninitialized
) : MvRxState
class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: DeviceVerificationInfoBottomSheetViewState,
@Assisted val deviceId: String,
val session: Session
) : VectorViewModel<DeviceVerificationInfoBottomSheetViewState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
fun create(initialState: DeviceVerificationInfoBottomSheetViewState): DeviceVerificationInfoBottomSheetViewModel
fun create(initialState: DeviceVerificationInfoBottomSheetViewState, deviceId: String): DeviceVerificationInfoBottomSheetViewModel
}
init {
session.rx().liveUserCryptoDevices(session.myUserId)
.map { list ->
list.firstOrNull { it.deviceId == deviceId }
}
.execute {
copy(
cryptoDeviceInfo = it
)
}
setState {
copy(deviceInfo = Loading())
}
session.getDeviceInfo(deviceId, object : MatrixCallback<DeviceInfo> {
override fun onSuccess(data: DeviceInfo) {
setState {
copy(deviceInfo = Success(data))
}
}
override fun onFailure(failure: Throwable) {
setState {
copy(deviceInfo = Fail(failure))
}
}
})
}
companion object : MvRxViewModelFactory<DeviceVerificationInfoBottomSheetViewModel, DeviceVerificationInfoBottomSheetViewState> {
@ -50,16 +84,8 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
override fun create(viewModelContext: ViewModelContext, state: DeviceVerificationInfoBottomSheetViewState)
: DeviceVerificationInfoBottomSheetViewModel? {
val fragment: DeviceVerificationInfoBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
return fragment.deviceVerificationInfoViewModelFactory.create(state)
}
override fun initialState(viewModelContext: ViewModelContext): DeviceVerificationInfoBottomSheetViewState? {
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
val args = viewModelContext.args<DeviceVerificationInfoArgs>()
session.getDeviceInfo(args.userId, args.deviceId)?.let {
return DeviceVerificationInfoBottomSheetViewState(cryptoDeviceInfo = Success(it))
}
return super.initialState(viewModelContext)
return fragment.deviceVerificationInfoViewModelFactory.create(state, args.deviceId)
}
}

View file

@ -16,6 +16,7 @@
package im.vector.riotx.features.settings.devices
import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Fail
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.dividerItem
@ -23,6 +24,7 @@ import im.vector.riotx.core.epoxy.loadingItem
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.ui.list.GenericItem
import im.vector.riotx.core.ui.list.genericFooterItem
import im.vector.riotx.core.ui.list.genericItem
import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
import javax.inject.Inject
@ -35,15 +37,11 @@ class DeviceVerificationInfoEpoxyController @Inject constructor(private val stri
var callback: Callback? = null
override fun buildModels(data: DeviceVerificationInfoBottomSheetViewState?) {
val device = data?.cryptoDeviceInfo?.invoke()
if (device == null) {
loadingItem {
id("loading")
}
} else {
if (device.isVerified) {
val cryptoDeviceInfo = data?.cryptoDeviceInfo?.invoke()
if (cryptoDeviceInfo != null) {
if (cryptoDeviceInfo.isVerified) {
genericItem {
id("trust${device.deviceId}")
id("trust${cryptoDeviceInfo.deviceId}")
style(GenericItem.STYLE.BIG_TEXT)
titleIconResourceId(R.drawable.ic_shield_trusted)
title(stringProvider.getString(R.string.encryption_information_verified))
@ -51,7 +49,7 @@ class DeviceVerificationInfoEpoxyController @Inject constructor(private val stri
}
} else {
genericItem {
id("trust${device.deviceId}")
id("trust${cryptoDeviceInfo.deviceId}")
titleIconResourceId(R.drawable.ic_shield_warning)
style(GenericItem.STYLE.BIG_TEXT)
title(stringProvider.getString(R.string.encryption_information_not_verified))
@ -60,12 +58,12 @@ class DeviceVerificationInfoEpoxyController @Inject constructor(private val stri
}
genericItem {
id("info${device.deviceId}")
title(device.displayName() ?: "")
description("(${device.deviceId})")
id("info${cryptoDeviceInfo.deviceId}")
title(cryptoDeviceInfo.displayName() ?: "")
description("(${cryptoDeviceInfo.deviceId})")
}
if (!device.isVerified) {
if (!cryptoDeviceInfo.isVerified) {
dividerItem {
id("d1")
}
@ -76,12 +74,12 @@ class DeviceVerificationInfoEpoxyController @Inject constructor(private val stri
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_accent))
listener {
callback?.onAction(DevicesAction.VerifyMyDevice(device.deviceId))
callback?.onAction(DevicesAction.VerifyMyDevice(cryptoDeviceInfo.deviceId))
}
}
}
if (device.deviceId != session.sessionParams.credentials.deviceId) {
if (cryptoDeviceInfo.deviceId != session.sessionParams.credentials.deviceId) {
// Add the delete option
dividerItem {
id("d2")
@ -93,7 +91,7 @@ class DeviceVerificationInfoEpoxyController @Inject constructor(private val stri
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
callback?.onAction(DevicesAction.Delete(device.deviceId))
callback?.onAction(DevicesAction.Delete(cryptoDeviceInfo.deviceId))
}
}
}
@ -108,9 +106,42 @@ class DeviceVerificationInfoEpoxyController @Inject constructor(private val stri
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
listener {
callback?.onAction(DevicesAction.PromptRename(device.deviceId))
callback?.onAction(DevicesAction.PromptRename(cryptoDeviceInfo.deviceId))
}
}
} else if (data?.deviceInfo?.invoke() != null) {
val info = data.deviceInfo.invoke()
genericItem {
id("info${info?.deviceId}")
title(info?.displayName ?: "")
description("(${info?.deviceId})")
}
genericFooterItem {
id("infoCrypto${info?.deviceId}")
text(stringProvider.getString(R.string.settings_failed_to_get_crypto_device_info))
}
if (info?.deviceId != session.sessionParams.credentials.deviceId) {
// Add the delete option
dividerItem {
id("d2")
}
bottomSheetVerificationActionItem {
id("delete")
title(stringProvider.getString(R.string.settings_active_sessions_signout_device))
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
iconRes(R.drawable.ic_arrow_right)
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
listener {
callback?.onAction(DevicesAction.Delete(info?.deviceId ?: ""))
}
}
}
} else {
loadingItem {
id("loading")
}
}
}

View file

@ -115,7 +115,7 @@ class DevicesController @Inject constructor(private val errorFormatter: ErrorFor
deviceInfo(deviceInfo)
currentDevice(isCurrentDevice)
itemClickAction { callback?.onDeviceClicked(deviceInfo) }
trusted(cryptoDevices?.firstOrNull { it.deviceId == deviceInfo.deviceId }?.isVerified ?: false)
trusted(cryptoDevices?.firstOrNull { it.deviceId == deviceInfo.deviceId }?.isVerified)
}
}
}

View file

@ -110,7 +110,8 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic
if (session.isCryptoEnabled() && !session.sessionParams.credentials.deviceId.isNullOrEmpty()) {
setState {
copy(
devices = Loading()
// Keep known list if we have it, and let refresh go in backgroung
devices = this.devices.takeIf { it is Success } ?: Loading()
)
}