Clean after benoits review

This commit is contained in:
ganfra 2021-06-21 17:57:47 +02:00
parent 4b6484d317
commit 48fa9e1a5e
7 changed files with 89 additions and 22 deletions

View File

@ -22,7 +22,6 @@ import androidx.lifecycle.OnLifecycleEvent
import arrow.core.Option import arrow.core.Option
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.utils.BehaviorDataSource import im.vector.app.core.utils.BehaviorDataSource
import im.vector.app.features.invite.InvitesAcceptor
import im.vector.app.features.session.coroutineScope import im.vector.app.features.session.coroutineScope
import im.vector.app.features.ui.UiStateRepository import im.vector.app.features.ui.UiStateRepository
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -52,8 +51,7 @@ fun RoomGroupingMethod.group() = (this as? RoomGroupingMethod.ByLegacyGroup)?.gr
class AppStateHandler @Inject constructor( class AppStateHandler @Inject constructor(
private val sessionDataSource: ActiveSessionDataSource, private val sessionDataSource: ActiveSessionDataSource,
private val uiStateRepository: UiStateRepository, private val uiStateRepository: UiStateRepository,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder
private val invitesAcceptor: InvitesAcceptor
) : LifecycleObserver { ) : LifecycleObserver {
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
@ -63,10 +61,6 @@ class AppStateHandler @Inject constructor(
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? = selectedSpaceDataSource.currentValue?.orNull() fun getCurrentRoomGroupingMethod(): RoomGroupingMethod? = selectedSpaceDataSource.currentValue?.orNull()
init {
observeActiveSession()
}
fun setCurrentSpace(spaceId: String?, session: Session? = null) { fun setCurrentSpace(spaceId: String?, session: Session? = null) {
val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return val uSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.BySpace if (selectedSpaceDataSource.currentValue?.orNull() is RoomGroupingMethod.BySpace
@ -103,7 +97,6 @@ class AppStateHandler @Inject constructor(
.subscribe { .subscribe {
// sessionDataSource could already return a session while activeSession holder still returns null // sessionDataSource could already return a session while activeSession holder still returns null
it.orNull()?.let { session -> it.orNull()?.let { session ->
invitesAcceptor.onSessionActive(session)
if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) { if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) {
setCurrentSpace(uiStateRepository.getSelectedSpace(session.sessionId), session) setCurrentSpace(uiStateRepository.getSelectedSpace(session.sessionId), session)
} else { } else {
@ -123,8 +116,14 @@ class AppStateHandler @Inject constructor(
return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
} }
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun entersForeground() {
observeActiveSession()
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun entersBackground() { fun entersBackground() {
compositeDisposable.clear()
val session = activeSessionHolder.getSafeActiveSession() ?: return val session = activeSessionHolder.getSafeActiveSession() ?: return
when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) { when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) {
is RoomGroupingMethod.BySpace -> { is RoomGroupingMethod.BySpace -> {

View File

@ -47,6 +47,7 @@ import im.vector.app.core.rx.RxConfig
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.configuration.VectorConfiguration
import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog
import im.vector.app.features.invite.InvitesAcceptor
import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks
import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.notifications.NotificationDrawerManager
import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.notifications.NotificationUtils
@ -95,6 +96,7 @@ class VectorApplication :
@Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var popupAlertManager: PopupAlertManager
@Inject lateinit var pinLocker: PinLocker @Inject lateinit var pinLocker: PinLocker
@Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var callManager: WebRtcCallManager
@Inject lateinit var invitesAcceptor: InvitesAcceptor
lateinit var vectorComponent: VectorComponent lateinit var vectorComponent: VectorComponent
@ -116,6 +118,7 @@ class VectorApplication :
appContext = this appContext = this
vectorComponent = DaggerVectorComponent.factory().create(this) vectorComponent = DaggerVectorComponent.factory().create(this)
vectorComponent.inject(this) vectorComponent.inject(this)
invitesAcceptor.initialize()
vectorUncaughtExceptionHandler.activate(this) vectorUncaughtExceptionHandler.activate(this)
rxConfig.setupRxPlugin() rxConfig.setupRxPlugin()

View File

@ -32,6 +32,7 @@ import im.vector.app.features.call.lookup.CallProtocolsChecker
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.createdirect.DirectRoomHelper import im.vector.app.features.createdirect.DirectRoomHelper
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.invite.showInvites
import im.vector.app.features.ui.UiStateRepository import im.vector.app.features.ui.UiStateRepository
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -208,7 +209,7 @@ private val autoAcceptInvites: AutoAcceptInvites)
val activeSpaceRoomId = groupingMethod.spaceSummary?.roomId val activeSpaceRoomId = groupingMethod.spaceSummary?.roomId
var dmInvites = 0 var dmInvites = 0
var roomsInvite = 0 var roomsInvite = 0
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
dmInvites = session.getRoomSummaries( dmInvites = session.getRoomSummaries(
roomSummaryQueryParams { roomSummaryQueryParams {
memberships = listOf(Membership.INVITE) memberships = listOf(Membership.INVITE)

View File

@ -23,6 +23,7 @@ import im.vector.app.RoomGroupingMethod
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.invite.showInvites
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -75,7 +76,7 @@ class GroupRoomListSectionBuilder(
) )
} }
RoomListDisplayMode.NOTIFICATIONS -> { RoomListDisplayMode.NOTIFICATIONS -> {
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
sections, sections,
activeGroupAwareQueries, activeGroupAwareQueries,
@ -118,7 +119,7 @@ class GroupRoomListSectionBuilder(
private fun buildRoomsSections(sections: MutableList<RoomsSection>, private fun buildRoomsSections(sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>, activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>,
actualGroupId: String?) { actualGroupId: String?) {
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
sections, sections,
activeSpaceAwareQueries, activeSpaceAwareQueries,
@ -185,7 +186,7 @@ class GroupRoomListSectionBuilder(
activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>, activeSpaceAwareQueries: MutableList<UpdatableLivePageResult>,
actualGroupId: String? actualGroupId: String?
) { ) {
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
addSection(sections, addSection(sections,
activeSpaceAwareQueries, activeSpaceAwareQueries,
R.string.invitations_header, R.string.invitations_header,

View File

@ -27,6 +27,7 @@ import im.vector.app.R
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.invite.showInvites
import im.vector.app.space import im.vector.app.space
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
@ -90,7 +91,7 @@ class SpaceRoomListSectionBuilder(
) )
} }
RoomListDisplayMode.NOTIFICATIONS -> { RoomListDisplayMode.NOTIFICATIONS -> {
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
sections = sections, sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
@ -140,7 +141,7 @@ class SpaceRoomListSectionBuilder(
} }
private fun buildRoomsSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) { private fun buildRoomsSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
sections = sections, sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
@ -259,7 +260,7 @@ class SpaceRoomListSectionBuilder(
} }
private fun buildDmSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) { private fun buildDmSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>) {
if (!autoAcceptInvites.hideInvites) { if (autoAcceptInvites.showInvites()) {
addSection(sections = sections, addSection(sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,

View File

@ -18,12 +18,28 @@ package im.vector.app.features.invite
import javax.inject.Inject import javax.inject.Inject
/**
* This interface defines 2 flags so you can handle auto accept invites.
* At the moment we only have [CompileTimeAutoAcceptInvites] implementation.
*/
interface AutoAcceptInvites { interface AutoAcceptInvites {
/**
* Enable auto-accept invites. It means, as soon as you got an invite from the sync, it will try to join it.
*/
val isEnabled: Boolean val isEnabled: Boolean
/**
* Hide invites from the UI (from notifications, notification count and room list). By default invites are hidden when [isEnabled] is true
*/
val hideInvites: Boolean val hideInvites: Boolean
get() = isEnabled
} }
fun AutoAcceptInvites.showInvites() = !hideInvites
/**
* Simple compile time implementation of AutoAcceptInvites flags.
*/
class CompileTimeAutoAcceptInvites @Inject constructor() : AutoAcceptInvites { class CompileTimeAutoAcceptInvites @Inject constructor() : AutoAcceptInvites {
override val isEnabled = false override val isEnabled = false
override val hideInvites = isEnabled
} }

View File

@ -16,6 +16,7 @@
package im.vector.app.features.invite package im.vector.app.features.invite
import im.vector.app.ActiveSessionDataSource
import im.vector.app.features.session.coroutineScope import im.vector.app.features.session.coroutineScope
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
@ -23,7 +24,10 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.sync.withPermit
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
@ -39,16 +43,35 @@ import javax.inject.Singleton
* This mechanism will be on only if AutoAcceptInvites.isEnabled is true. * This mechanism will be on only if AutoAcceptInvites.isEnabled is true.
*/ */
@Singleton @Singleton
class InvitesAcceptor @Inject constructor(private val autoAcceptInvites: AutoAcceptInvites) : Session.Listener { class InvitesAcceptor @Inject constructor(
private val sessionDataSource: ActiveSessionDataSource,
private val autoAcceptInvites: AutoAcceptInvites
) : Session.Listener {
private val disposables = HashMap<String, Disposable>() private lateinit var activeSessionDisposable: Disposable
private val shouldRejectRoomIds = mutableSetOf<String>()
private val invitedRoomDisposables = HashMap<String, Disposable>()
private val semaphore = Semaphore(1) private val semaphore = Semaphore(1)
fun onSessionActive(session: Session) { fun initialize() {
observeActiveSession()
}
private fun observeActiveSession() {
activeSessionDisposable = sessionDataSource.observe()
.distinctUntilChanged()
.subscribe {
it.orNull()?.let { session ->
onSessionActive(session)
}
}
}
private fun onSessionActive(session: Session) {
if (!autoAcceptInvites.isEnabled) { if (!autoAcceptInvites.isEnabled) {
return return
} }
if (disposables.containsKey(session.sessionId)) { if (invitedRoomDisposables.containsKey(session.sessionId)) {
return return
} }
session.addListener(this) session.addListener(this)
@ -74,11 +97,15 @@ class InvitesAcceptor @Inject constructor(private val autoAcceptInvites: AutoAcc
} }
} }
.also { .also {
disposables[session.sessionId] = it invitedRoomDisposables[session.sessionId] = it
} }
} }
private suspend fun Session.joinRoomSafely(roomId: String) { private suspend fun Session.joinRoomSafely(roomId: String) {
if (shouldRejectRoomIds.contains(roomId)) {
getRoom(roomId)?.rejectInviteSafely()
return
}
val roomMembershipChanged = getChangeMemberships(roomId) val roomMembershipChanged = getChangeMemberships(roomId)
if (roomMembershipChanged != ChangeMembershipState.Joined && !roomMembershipChanged.isInProgress()) { if (roomMembershipChanged != ChangeMembershipState.Joined && !roomMembershipChanged.isInProgress()) {
try { try {
@ -86,12 +113,31 @@ class InvitesAcceptor @Inject constructor(private val autoAcceptInvites: AutoAcc
joinRoom(roomId) joinRoom(roomId)
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.v("Failed auto join room: $roomId") Timber.v("Failed auto join room: $roomId")
// if we got 404 on invites, the inviting user have left or the hs is off.
if (failure is Failure.ServerError && failure.httpCode == 404) {
val room = getRoom(roomId) ?: return
val inviterId = room.roomSummary()?.inviterId
// if the inviting user is on the same HS, there can only be one cause: they left, so we try to reject the invite.
if (inviterId?.endsWith(sessionParams.credentials.homeServer.orEmpty()).orFalse()) {
shouldRejectRoomIds.add(roomId)
room.rejectInviteSafely()
}
}
} }
} }
} }
private suspend fun Room.rejectInviteSafely() {
try {
leave(null)
shouldRejectRoomIds.remove(roomId)
} catch (failure: Throwable) {
Timber.v("Fail rejecting invite for room: $roomId")
}
}
override fun onSessionStopped(session: Session) { override fun onSessionStopped(session: Session) {
session.removeListener(this) session.removeListener(this)
disposables.remove(session.sessionId)?.dispose() invitedRoomDisposables.remove(session.sessionId)?.dispose()
} }
} }