Remember ignored unknown sessions

This commit is contained in:
Valere 2020-04-27 10:07:28 +02:00
parent 7ef1970a0b
commit 42b47c25aa
3 changed files with 67 additions and 12 deletions

View File

@ -1,4 +1,3 @@
/* /*
* Copyright 2019 New Vector Ltd * Copyright 2019 New Vector Ltd
* *
@ -61,7 +60,7 @@ class HomeDetailFragment @Inject constructor(
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>() private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
private val viewModel: HomeDetailViewModel by fragmentViewModel() private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel : UnknownDeviceDetectorSharedViewModel by activityViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
private lateinit var sharedActionViewModel: HomeSharedActionViewModel private lateinit var sharedActionViewModel: HomeSharedActionViewModel
@ -112,7 +111,11 @@ class HomeDetailFragment @Inject constructor(
?.navigator ?.navigator
?.requestSessionVerification(requireContext(), newest.deviceId ?: "") ?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
} }
dismissedAction = Runnable {} dismissedAction = Runnable {
unknownDeviceDetectorSharedViewModel.handle(
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(newest.deviceId ?: "")
)
}
} }
) )
} }

View File

@ -19,6 +19,7 @@ package im.vector.riotx.features.home
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
@ -30,9 +31,11 @@ import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.matrix.rx.singleBuilder import im.vector.matrix.rx.singleBuilder
import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.platform.VectorViewModelAction
import im.vector.riotx.features.settings.VectorPreferences
import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
data class UnknownDevicesState( data class UnknownDevicesState(
@ -40,16 +43,31 @@ data class UnknownDevicesState(
val canCrossSign: Boolean = false val canCrossSign: Boolean = false
) : MvRxState ) : MvRxState
class UnknownDeviceDetectorSharedViewModel(session: Session, initialState: UnknownDevicesState) class UnknownDeviceDetectorSharedViewModel(
: VectorViewModel<UnknownDevicesState, EmptyAction, EmptyViewEvents>(initialState) { session: Session,
private val vectorPreferences: VectorPreferences,
initialState: UnknownDevicesState)
: VectorViewModel<UnknownDevicesState, UnknownDeviceDetectorSharedViewModel.Action, EmptyViewEvents>(initialState) {
sealed class Action : VectorViewModelAction {
data class IgnoreDevice(val deviceId: String) : Action()
}
val ignoredDeviceList = ArrayList<String>()
init { init {
ignoredDeviceList.addAll(
vectorPreferences.getUnknownDeviceDismissedList().also {
Timber.v("## Detector - Remembered ignored list $it")
}
)
session.rx().liveUserCryptoDevices(session.myUserId) session.rx().liveUserCryptoDevices(session.myUserId)
.debounce(600, TimeUnit.MILLISECONDS) .debounce(600, TimeUnit.MILLISECONDS)
.distinct() .distinct()
.switchMap { deviceList -> .switchMap { deviceList ->
// Timber.v("## Detector - ============================") Timber.v("## Detector - ============================")
// Timber.v("## Detector - Crypto device update ${deviceList.map { "${it.deviceId} : ${it.isVerified}" }}") Timber.v("## Detector - Crypto device update ${deviceList.map { "${it.deviceId} : ${it.isVerified}" }}")
singleBuilder<DevicesListResponse> { singleBuilder<DevicesListResponse> {
session.cryptoService().getDevicesList(it) session.cryptoService().getDevicesList(it)
NoOpCancellable NoOpCancellable
@ -59,10 +77,13 @@ class UnknownDeviceDetectorSharedViewModel(session: Session, initialState: Unkno
deviceList.firstOrNull { info.deviceId == it.deviceId }?.let { deviceList.firstOrNull { info.deviceId == it.deviceId }?.let {
!it.isVerified !it.isVerified
} ?: false } ?: false
}?.sortedByDescending { it.lastSeenTs } }
?.sortedByDescending { it.lastSeenTs }
?.map { ?.map {
session.getUser(it.user_id ?: "")?.toMatrixItem() to it session.getUser(it.user_id ?: "")?.toMatrixItem() to it
} ?: emptyList() }
?.filter { !ignoredDeviceList.contains(it.second.deviceId) }
?: emptyList()
} }
.toObservable() .toObservable()
} }
@ -76,12 +97,28 @@ class UnknownDeviceDetectorSharedViewModel(session: Session, initialState: Unkno
} }
} }
override fun handle(action: EmptyAction) {} override fun handle(action: Action) {
when (action) {
is Action.IgnoreDevice -> {
// local echo
withState { state ->
state.unknownSessions.invoke()?.let {
val updated = it.filter { it.second.deviceId != action.deviceId }
setState {
copy(unknownSessions = Success(updated))
}
}
}
ignoredDeviceList.add(action.deviceId)
vectorPreferences.storeUnknownDeviceDismissedList(ignoredDeviceList)
}
}
}
companion object : MvRxViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> { companion object : MvRxViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> {
override fun create(viewModelContext: ViewModelContext, state: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel? { override fun create(viewModelContext: ViewModelContext, state: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel? {
val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession() val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
return UnknownDeviceDetectorSharedViewModel(session, state) return UnknownDeviceDetectorSharedViewModel(session, VectorPreferences(viewModelContext.activity()), state)
} }
} }
} }

View File

@ -24,6 +24,7 @@ import android.provider.MediaStore
import androidx.core.content.edit import androidx.core.content.edit
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.squareup.seismic.ShakeDetector import com.squareup.seismic.ShakeDetector
import im.vector.matrix.android.api.extensions.tryThis
import im.vector.riotx.BuildConfig import im.vector.riotx.BuildConfig
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.features.homeserver.ServerUrlsRepository import im.vector.riotx.features.homeserver.ServerUrlsRepository
@ -166,6 +167,8 @@ class VectorPreferences @Inject constructor(private val context: Context) {
private const val MEDIA_SAVING_1_MONTH = 2 private const val MEDIA_SAVING_1_MONTH = 2
private const val MEDIA_SAVING_FOREVER = 3 private const val MEDIA_SAVING_FOREVER = 3
private const val SETTINGS_UNKNOWN_DEVICE_DISMISSED_LIST = "SETTINGS_UNKNWON_DEVICE_DISMISSED_LIST"
// some preferences keys must be kept after a logout // some preferences keys must be kept after a logout
private val mKeysToKeepAfterLogout = listOf( private val mKeysToKeepAfterLogout = listOf(
SETTINGS_DEFAULT_MEDIA_COMPRESSION_KEY, SETTINGS_DEFAULT_MEDIA_COMPRESSION_KEY,
@ -364,6 +367,18 @@ class VectorPreferences @Inject constructor(private val context: Context) {
return defaultPrefs.getBoolean(SETTINGS_PLAY_SHUTTER_SOUND_KEY, true) return defaultPrefs.getBoolean(SETTINGS_PLAY_SHUTTER_SOUND_KEY, true)
} }
fun storeUnknownDeviceDismissedList(deviceIds: List<String>) {
defaultPrefs.edit(true) {
putStringSet(SETTINGS_UNKNOWN_DEVICE_DISMISSED_LIST, deviceIds.toSet())
}
}
fun getUnknownDeviceDismissedList(): List<String> {
return tryThis {
defaultPrefs.getStringSet(SETTINGS_UNKNOWN_DEVICE_DISMISSED_LIST, null)?.toList()
} ?: emptyList()
}
/** /**
* Update the notification ringtone * Update the notification ringtone
* *