Jitsi call: don't show expanded add matrix icon if only widget is jitsi (also fix join state)

This commit is contained in:
ganfra 2021-07-27 19:16:38 +02:00
parent e259b44449
commit d2785b69df
5 changed files with 75 additions and 19 deletions

View File

@ -31,6 +31,7 @@ import im.vector.app.core.network.WifiDetector
import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.utils.AssetReader import im.vector.app.core.utils.AssetReader
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
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.crypto.keysrequest.KeyRequestHandler import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
@ -65,6 +66,7 @@ import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.HomeServerHistoryService import org.matrix.android.sdk.api.auth.HomeServerHistoryService
import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
import javax.inject.Singleton import javax.inject.Singleton
@Component(modules = [VectorModule::class]) @Component(modules = [VectorModule::class])
@ -167,6 +169,8 @@ interface VectorComponent {
fun roomSummaryHolder(): RoomSummariesHolder fun roomSummaryHolder(): RoomSummariesHolder
fun jitsiActiveConferenceHolder(): JitsiActiveConferenceHolder
@Component.Factory @Component.Factory
interface Factory { interface Factory {
fun create(@BindsInstance context: Context): VectorComponent fun create(@BindsInstance context: Context): VectorComponent

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.call.conference
import android.content.Context
import androidx.lifecycle.ProcessLifecycleOwner
import org.jitsi.meet.sdk.BroadcastEvent
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class JitsiActiveConferenceHolder @Inject constructor(context: Context) {
private var activeConference: String? = null
init {
ProcessLifecycleOwner.get().lifecycle.addObserver(JitsiBroadcastEventObserver(context, this::onBroadcastEvent))
}
fun isJoined(confId: String?): Boolean {
return confId != null && activeConference?.endsWith(confId).orFalse()
}
private fun onBroadcastEvent(broadcastEvent: BroadcastEvent) {
when (broadcastEvent.type) {
BroadcastEvent.Type.CONFERENCE_JOINED -> activeConference = broadcastEvent.extractConferenceUrl()
BroadcastEvent.Type.CONFERENCE_TERMINATED -> activeConference = null
else -> Unit
}
}
}

View File

@ -87,9 +87,8 @@ import im.vector.app.core.intent.getMimeTypeFromUri
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.platform.showOptimizedSnackbar import im.vector.app.core.platform.showOptimizedSnackbar
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.ui.views.CurrentCallsViewPresenter
import im.vector.app.core.ui.views.CurrentCallsView import im.vector.app.core.ui.views.CurrentCallsView
import im.vector.app.core.ui.views.CurrentCallsViewPresenter
import im.vector.app.core.ui.views.FailedMessagesWarningView import im.vector.app.core.ui.views.FailedMessagesWarningView
import im.vector.app.core.ui.views.NotificationAreaView import im.vector.app.core.ui.views.NotificationAreaView
import im.vector.app.core.utils.Debouncer import im.vector.app.core.utils.Debouncer
@ -831,14 +830,8 @@ class RoomDetailFragment @Inject constructor(
val matrixAppsMenuItem = menu.findItem(R.id.open_matrix_apps) val matrixAppsMenuItem = menu.findItem(R.id.open_matrix_apps)
val widgetsCount = state.activeRoomWidgets.invoke()?.size ?: 0 val widgetsCount = state.activeRoomWidgets.invoke()?.size ?: 0
if (widgetsCount > 0) { val hasOnlyJitsiWidget = widgetsCount == 1 && state.hasActiveJitsiWidget()
val actionView = matrixAppsMenuItem.actionView if (widgetsCount == 0 || hasOnlyJitsiWidget) {
actionView
.findViewById<ImageView>(R.id.action_view_icon_image)
.setColorFilter(colorProvider.getColorFromAttribute(R.attr.colorPrimary))
actionView.findViewById<TextView>(R.id.cart_badge).setTextOrHide("$widgetsCount")
matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
} else {
// icon should be default color no badge // icon should be default color no badge
val actionView = matrixAppsMenuItem.actionView val actionView = matrixAppsMenuItem.actionView
actionView actionView
@ -846,6 +839,13 @@ class RoomDetailFragment @Inject constructor(
.setColorFilter(ThemeUtils.getColor(requireContext(), R.attr.vctr_content_secondary)) .setColorFilter(ThemeUtils.getColor(requireContext(), R.attr.vctr_content_secondary))
actionView.findViewById<TextView>(R.id.cart_badge).isVisible = false actionView.findViewById<TextView>(R.id.cart_badge).isVisible = false
matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
} else {
val actionView = matrixAppsMenuItem.actionView
actionView
.findViewById<ImageView>(R.id.action_view_icon_image)
.setColorFilter(colorProvider.getColorFromAttribute(R.attr.colorPrimary))
actionView.findViewById<TextView>(R.id.cart_badge).setTextOrHide("$widgetsCount")
matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
} }
} }
} }

View File

@ -38,8 +38,8 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.mvrx.runCatchingToAsync
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
import im.vector.app.features.call.conference.JitsiService import im.vector.app.features.call.conference.JitsiService
import im.vector.app.features.call.conference.extractConferenceUrl
import im.vector.app.features.call.lookup.CallProtocolsChecker 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.command.CommandParser import im.vector.app.features.command.CommandParser
@ -67,7 +67,6 @@ import org.commonmark.renderer.html.HtmlRenderer
import org.jitsi.meet.sdk.BroadcastEvent import org.jitsi.meet.sdk.BroadcastEvent
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -121,6 +120,7 @@ class RoomDetailViewModel @AssistedInject constructor(
private val chatEffectManager: ChatEffectManager, private val chatEffectManager: ChatEffectManager,
private val directRoomHelper: DirectRoomHelper, private val directRoomHelper: DirectRoomHelper,
private val jitsiService: JitsiService, private val jitsiService: JitsiService,
private val activeConferenceHolder: JitsiActiveConferenceHolder,
timelineFactory: TimelineFactory timelineFactory: TimelineFactory
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), ) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState),
Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener { Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener {
@ -254,7 +254,8 @@ class RoomDetailViewModel @AssistedInject constructor(
copy( copy(
jitsiState = jitsiState.copy( jitsiState = jitsiState.copy(
confId = jitsiConfId, confId = jitsiConfId,
widgetId = jitsiWidget?.widgetId widgetId = jitsiWidget?.widgetId,
hasJoined = activeConferenceHolder.isJoined(jitsiConfId)
) )
) )
} }
@ -363,9 +364,7 @@ class RoomDetailViewModel @AssistedInject constructor(
when (action.broadcastEvent.type) { when (action.broadcastEvent.type) {
BroadcastEvent.Type.CONFERENCE_JOINED, BroadcastEvent.Type.CONFERENCE_JOINED,
BroadcastEvent.Type.CONFERENCE_TERMINATED -> { BroadcastEvent.Type.CONFERENCE_TERMINATED -> {
if (action.broadcastEvent.extractConferenceUrl()?.endsWith(state.jitsiState.confId).orFalse()) { setState { copy(jitsiState = jitsiState.copy(hasJoined = activeConferenceHolder.isJoined(jitsiState.confId))) }
setState { copy(jitsiState = jitsiState.copy(hasJoined = action.broadcastEvent.type == BroadcastEvent.Type.CONFERENCE_JOINED)) }
}
} }
else -> Unit else -> Unit
} }
@ -683,8 +682,9 @@ class RoomDetailViewModel @AssistedInject constructor(
R.id.invite -> state.canInvite R.id.invite -> state.canInvite
R.id.open_matrix_apps -> true R.id.open_matrix_apps -> true
R.id.voice_call -> state.isWebRTCCallOptionAvailable() R.id.voice_call -> state.isWebRTCCallOptionAvailable()
R.id.video_call -> state.isWebRTCCallOptionAvailable() || state.jitsiState.widgetId == null || state.jitsiState.hasJoined R.id.video_call -> state.isWebRTCCallOptionAvailable() || state.jitsiState.confId == null || state.jitsiState.hasJoined
R.id.join_conference -> state.jitsiState.widgetId != null && !state.jitsiState.hasJoined // Show Join conference button only if there is an active conf id not joined. Otherwise fallback to default video disabled. ^
R.id.join_conference -> state.jitsiState.confId != null && !state.jitsiState.hasJoined
R.id.search -> true R.id.search -> true
R.id.dev_tools -> vectorPreferences.developerMode() R.id.dev_tools -> vectorPreferences.developerMode()
else -> false else -> false

View File

@ -18,7 +18,10 @@ package im.vector.app.features.home.room.detail
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import im.vector.app.core.platform.ButtonStateView
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
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.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
@ -26,6 +29,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.Widget
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
/** /**
* Describes the current send mode: * Describes the current send mode:
@ -96,7 +100,9 @@ data class RoomDetailViewState(
fun isWebRTCCallOptionAvailable() = (asyncRoomSummary.invoke()?.joinedMembersCount ?: 0) <= 2 fun isWebRTCCallOptionAvailable() = (asyncRoomSummary.invoke()?.joinedMembersCount ?: 0) <= 2
fun hasActiveJitsiWidget() = jitsiState.confId != null // This checks directly on the active room widgets.
// It can differs for a short period of time on the JitsiState as its computed async.
fun hasActiveJitsiWidget() = activeRoomWidgets()?.any { it.type == WidgetType.Jitsi && it.isActive }.orFalse()
fun isDm() = asyncRoomSummary()?.isDirect == true fun isDm() = asyncRoomSummary()?.isDirect == true
} }