mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 10:25:35 +03:00
VoIP: start to show in-app notification
This commit is contained in:
parent
bf6f60c7e5
commit
76ed775f6f
27 changed files with 496 additions and 351 deletions
|
@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.room.model.call.SdpType
|
|||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
||||
interface MxCallDetail {
|
||||
val sessionId: String
|
||||
val callId: String
|
||||
val isOutgoing: Boolean
|
||||
val roomId: String
|
||||
|
|
|
@ -160,7 +160,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa
|
|||
val content = event.getClearContent().toModel<CallInviteContent>() ?: return
|
||||
val incomingCall = mxCallFactory.createIncomingCall(
|
||||
roomId = event.roomId,
|
||||
senderId = event.senderId,
|
||||
opponentUserId = event.senderId,
|
||||
content = content
|
||||
) ?: return
|
||||
activeCallHandler.addCall(incomingCall)
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.matrix.android.sdk.api.session.call.MxCall
|
|||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.di.DeviceId
|
||||
import org.matrix.android.sdk.internal.di.SessionId
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.call.model.MxCallImpl
|
||||
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
|
||||
|
@ -29,21 +30,23 @@ import java.util.UUID
|
|||
import javax.inject.Inject
|
||||
|
||||
internal class MxCallFactory @Inject constructor(
|
||||
@SessionId private val sessionId: String,
|
||||
@DeviceId private val deviceId: String?,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val eventSenderProcessor: EventSenderProcessor,
|
||||
@UserId private val userId: String
|
||||
) {
|
||||
|
||||
fun createIncomingCall(roomId: String, senderId: String, content: CallInviteContent): MxCall? {
|
||||
fun createIncomingCall(roomId: String, opponentUserId: String, content: CallInviteContent): MxCall? {
|
||||
if (content.callId == null) return null
|
||||
return MxCallImpl(
|
||||
sessionId = sessionId,
|
||||
callId = content.callId,
|
||||
isOutgoing = false,
|
||||
roomId = roomId,
|
||||
userId = userId,
|
||||
ourPartyId = deviceId ?: "",
|
||||
opponentUserId = senderId,
|
||||
opponentUserId = opponentUserId,
|
||||
isVideoCall = content.isVideo(),
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor
|
||||
|
@ -53,14 +56,15 @@ internal class MxCallFactory @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall {
|
||||
fun createOutgoingCall(roomId: String, opponentUserId: String, isVideoCall: Boolean): MxCall {
|
||||
return MxCallImpl(
|
||||
sessionId = sessionId,
|
||||
callId = UUID.randomUUID().toString(),
|
||||
isOutgoing = true,
|
||||
roomId = roomId,
|
||||
userId = userId,
|
||||
ourPartyId = deviceId ?: "",
|
||||
opponentUserId = otherUserId,
|
||||
opponentUserId = opponentUserId,
|
||||
isVideoCall = isVideoCall,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
eventSenderProcessor = eventSenderProcessor
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
|
|||
import timber.log.Timber
|
||||
|
||||
internal class MxCallImpl(
|
||||
override val sessionId: String,
|
||||
override val callId: String,
|
||||
override val isOutgoing: Boolean,
|
||||
override val roomId: String,
|
||||
|
|
|
@ -239,7 +239,7 @@ android {
|
|||
productFlavors {
|
||||
gplay {
|
||||
dimension "store"
|
||||
|
||||
isDefault = true
|
||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}${getGplayVersionSuffix()}"
|
||||
|
||||
resValue "bool", "isGplay", "true"
|
||||
|
|
|
@ -25,9 +25,16 @@ import android.view.KeyEvent
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.media.session.MediaButtonReceiver
|
||||
import im.vector.app.core.extensions.vectorComponent
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.telecom.CallConnection
|
||||
import im.vector.app.features.call.webrtc.WebRtcCall
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.popup.IncomingCallAlert
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
|
@ -39,6 +46,8 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
|
||||
private lateinit var notificationUtils: NotificationUtils
|
||||
private lateinit var callManager: WebRtcCallManager
|
||||
private lateinit var avatarRenderer: AvatarRenderer
|
||||
private lateinit var alertManager: PopupAlertManager
|
||||
|
||||
private var callRingPlayerIncoming: CallRingPlayerIncoming? = null
|
||||
private var callRingPlayerOutgoing: CallRingPlayerOutgoing? = null
|
||||
|
@ -64,6 +73,8 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
super.onCreate()
|
||||
notificationUtils = vectorComponent().notificationUtils()
|
||||
callManager = vectorComponent().webRtcCallManager()
|
||||
avatarRenderer = vectorComponent().avatarRenderer()
|
||||
alertManager = vectorComponent().alertManager()
|
||||
callRingPlayerIncoming = CallRingPlayerIncoming(applicationContext)
|
||||
callRingPlayerOutgoing = CallRingPlayerOutgoing(applicationContext)
|
||||
wiredHeadsetStateReceiver = WiredHeadsetStateReceiver.createAndRegister(this, this)
|
||||
|
@ -111,20 +122,20 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
callRingPlayerOutgoing?.start()
|
||||
displayOutgoingRingingCallNotification(intent)
|
||||
}
|
||||
ACTION_ONGOING_CALL -> {
|
||||
ACTION_ONGOING_CALL -> {
|
||||
callRingPlayerIncoming?.stop()
|
||||
callRingPlayerOutgoing?.stop()
|
||||
displayCallInProgressNotification(intent)
|
||||
}
|
||||
ACTION_NO_ACTIVE_CALL -> hideCallNotifications()
|
||||
ACTION_CALL_CONNECTING -> {
|
||||
ACTION_NO_ACTIVE_CALL -> hideCallNotifications()
|
||||
ACTION_CALL_CONNECTING -> {
|
||||
// lower notification priority
|
||||
displayCallInProgressNotification(intent)
|
||||
// stop ringing
|
||||
callRingPlayerIncoming?.stop()
|
||||
callRingPlayerOutgoing?.stop()
|
||||
}
|
||||
ACTION_ONGOING_CALL_BG -> {
|
||||
ACTION_ONGOING_CALL_BG -> {
|
||||
// there is an ongoing call but call activity is in background
|
||||
displayCallOnGoingInBackground(intent)
|
||||
}
|
||||
|
@ -154,56 +165,52 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
*/
|
||||
private fun displayIncomingCallNotification(intent: Intent) {
|
||||
Timber.v("## VOIP displayIncomingCallNotification $intent")
|
||||
|
||||
// the incoming call in progress is already displayed
|
||||
// if (!TextUtils.isEmpty(mIncomingCallId)) {
|
||||
// Timber.v("displayIncomingCallNotification : the incoming call in progress is already displayed")
|
||||
// } else if (!TextUtils.isEmpty(mCallIdInProgress)) {
|
||||
// Timber.v("displayIncomingCallNotification : a 'call in progress' notification is displayed")
|
||||
// } else
|
||||
// // if (null == webRtcPeerConnectionManager.currentCall)
|
||||
// {
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID)
|
||||
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: ""
|
||||
val call = callManager.getCallById(callId) ?: return
|
||||
val isVideoCall = call.mxCall.isVideoCall
|
||||
val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false)
|
||||
val opponentMatrixItem = getOpponentMatrixItem(call)
|
||||
Timber.v("displayIncomingCallNotification : display the dedicated notification")
|
||||
if (!fromBg) {
|
||||
// Show in-app notification if app is in foreground.
|
||||
val incomingCallAlert = IncomingCallAlert(INCOMING_CALL_ALERT_UID).apply {
|
||||
viewBinder = IncomingCallAlert.ViewBinder(
|
||||
matrixItem = opponentMatrixItem,
|
||||
avatarRenderer = avatarRenderer,
|
||||
isVideoCall = isVideoCall,
|
||||
onAccept = { acceptIncomingCall(call) },
|
||||
onReject = { call.endCall() }
|
||||
)
|
||||
dismissedAction = Runnable { call.endCall() }
|
||||
}
|
||||
alertManager.postVectorAlert(incomingCallAlert)
|
||||
}
|
||||
val notification = notificationUtils.buildIncomingCallNotification(
|
||||
intent.getBooleanExtra(EXTRA_IS_VIDEO, false),
|
||||
intent.getStringExtra(EXTRA_ROOM_NAME) ?: "",
|
||||
intent.getStringExtra(EXTRA_ROOM_ID) ?: "",
|
||||
callId ?: "")
|
||||
mxCall = call.mxCall,
|
||||
title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId,
|
||||
fromBg = fromBg
|
||||
)
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
// mIncomingCallId = callId
|
||||
|
||||
// turn the screen on for 3 seconds
|
||||
// if (Matrix.getInstance(VectorApp.getInstance())!!.pushManager.isScreenTurnedOn) {
|
||||
// try {
|
||||
// val pm = getSystemService<PowerManager>()!!
|
||||
// val wl = pm.newWakeLock(
|
||||
// WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or PowerManager.ACQUIRE_CAUSES_WAKEUP,
|
||||
// CallService::class.java.simpleName)
|
||||
// wl.acquire(3000)
|
||||
// wl.release()
|
||||
// } catch (re: RuntimeException) {
|
||||
// Timber.e(re, "displayIncomingCallNotification : failed to turn screen on ")
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// Timber.i("displayIncomingCallNotification : do not display the incoming call notification because there is a pending call")
|
||||
// }
|
||||
private fun acceptIncomingCall(call: WebRtcCall){
|
||||
val intent = VectorCallActivity.newIntent(
|
||||
context = this,
|
||||
mxCall = call.mxCall,
|
||||
mode = VectorCallActivity.INCOMING_ACCEPT
|
||||
)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun displayOutgoingRingingCallNotification(intent: Intent) {
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID)
|
||||
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: return
|
||||
val call = callManager.getCallById(callId) ?: return
|
||||
val opponentMatrixItem = getOpponentMatrixItem(call)
|
||||
Timber.v("displayOutgoingCallNotification : display the dedicated notification")
|
||||
val notification = notificationUtils.buildOutgoingRingingCallNotification(
|
||||
intent.getBooleanExtra(EXTRA_IS_VIDEO, false),
|
||||
intent.getStringExtra(EXTRA_ROOM_NAME) ?: "",
|
||||
intent.getStringExtra(EXTRA_ROOM_ID) ?: "",
|
||||
callId ?: "")
|
||||
mxCall = call.mxCall,
|
||||
title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId
|
||||
)
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
|
@ -213,16 +220,14 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
private fun displayCallInProgressNotification(intent: Intent) {
|
||||
Timber.v("## VOIP displayCallInProgressNotification")
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: ""
|
||||
|
||||
val call = callManager.getCallById(callId) ?: return
|
||||
val opponentMatrixItem = getOpponentMatrixItem(call)
|
||||
alertManager.cancelAlert(INCOMING_CALL_ALERT_UID)
|
||||
val notification = notificationUtils.buildPendingCallNotification(
|
||||
intent.getBooleanExtra(EXTRA_IS_VIDEO, false),
|
||||
intent.getStringExtra(EXTRA_ROOM_NAME) ?: "",
|
||||
intent.getStringExtra(EXTRA_ROOM_ID) ?: "",
|
||||
intent.getStringExtra(EXTRA_MATRIX_ID) ?: "",
|
||||
callId)
|
||||
|
||||
mxCall = call.mxCall,
|
||||
title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId
|
||||
)
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
||||
// mCallIdInProgress = callId
|
||||
}
|
||||
|
||||
|
@ -231,18 +236,15 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
*/
|
||||
private fun displayCallOnGoingInBackground(intent: Intent) {
|
||||
Timber.v("## VOIP displayCallInProgressNotification")
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: ""
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: return
|
||||
val call = callManager.getCallById(callId) ?: return
|
||||
val opponentMatrixItem = getOpponentMatrixItem(call)
|
||||
|
||||
val notification = notificationUtils.buildPendingCallNotification(
|
||||
isVideo = intent.getBooleanExtra(EXTRA_IS_VIDEO, false),
|
||||
roomName = intent.getStringExtra(EXTRA_ROOM_NAME) ?: "",
|
||||
roomId = intent.getStringExtra(EXTRA_ROOM_ID) ?: "",
|
||||
matrixId = intent.getStringExtra(EXTRA_MATRIX_ID) ?: "",
|
||||
callId = callId,
|
||||
mxCall = call.mxCall,
|
||||
title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId,
|
||||
fromBg = true)
|
||||
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
||||
// mCallIdInProgress = callId
|
||||
}
|
||||
|
||||
|
@ -251,7 +253,7 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
*/
|
||||
private fun hideCallNotifications() {
|
||||
val notification = notificationUtils.buildCallEndedNotification()
|
||||
|
||||
alertManager.cancelAlert(INCOMING_CALL_ALERT_UID)
|
||||
mediaSession?.isActive = false
|
||||
// It's mandatory to startForeground to avoid crash
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
@ -263,9 +265,14 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
connections[callConnection.callId] = callConnection
|
||||
}
|
||||
|
||||
private fun getOpponentMatrixItem(call: WebRtcCall): MatrixItem? {
|
||||
return vectorComponent().currentSession().getUser(call.mxCall.opponentUserId)?.toMatrixItem()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NOTIFICATION_ID = 6480
|
||||
|
||||
private const val INCOMING_CALL_ALERT_UID = "INCOMING_CALL_ALERT_UID"
|
||||
private const val ACTION_INCOMING_RINGING_CALL = "im.vector.app.core.services.CallService.ACTION_INCOMING_RINGING_CALL"
|
||||
private const val ACTION_OUTGOING_RINGING_CALL = "im.vector.app.core.services.CallService.ACTION_OUTGOING_RINGING_CALL"
|
||||
private const val ACTION_CALL_CONNECTING = "im.vector.app.core.services.CallService.ACTION_CALL_CONNECTING"
|
||||
|
@ -275,44 +282,26 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
// private const val ACTION_ACTIVITY_VISIBLE = "im.vector.app.core.services.CallService.ACTION_ACTIVITY_VISIBLE"
|
||||
// private const val ACTION_STOP_RINGING = "im.vector.app.core.services.CallService.ACTION_STOP_RINGING"
|
||||
|
||||
private const val EXTRA_IS_VIDEO = "EXTRA_IS_VIDEO"
|
||||
private const val EXTRA_ROOM_NAME = "EXTRA_ROOM_NAME"
|
||||
private const val EXTRA_ROOM_ID = "EXTRA_ROOM_ID"
|
||||
private const val EXTRA_MATRIX_ID = "EXTRA_MATRIX_ID"
|
||||
private const val EXTRA_CALL_ID = "EXTRA_CALL_ID"
|
||||
private const val EXTRA_IS_IN_BG = "EXTRA_IS_IN_BG"
|
||||
|
||||
fun onIncomingCallRinging(context: Context,
|
||||
isVideo: Boolean,
|
||||
roomName: String,
|
||||
roomId: String,
|
||||
matrixId: String,
|
||||
callId: String) {
|
||||
callId: String,
|
||||
isInBackground: Boolean) {
|
||||
val intent = Intent(context, CallService::class.java)
|
||||
.apply {
|
||||
action = ACTION_INCOMING_RINGING_CALL
|
||||
putExtra(EXTRA_IS_VIDEO, isVideo)
|
||||
putExtra(EXTRA_ROOM_NAME, roomName)
|
||||
putExtra(EXTRA_ROOM_ID, roomId)
|
||||
putExtra(EXTRA_MATRIX_ID, matrixId)
|
||||
putExtra(EXTRA_CALL_ID, callId)
|
||||
putExtra(EXTRA_IS_IN_BG, isInBackground)
|
||||
}
|
||||
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
}
|
||||
|
||||
fun onOnGoingCallBackground(context: Context,
|
||||
isVideo: Boolean,
|
||||
roomName: String,
|
||||
roomId: String,
|
||||
matrixId: String,
|
||||
callId: String) {
|
||||
val intent = Intent(context, CallService::class.java)
|
||||
.apply {
|
||||
action = ACTION_ONGOING_CALL_BG
|
||||
putExtra(EXTRA_IS_VIDEO, isVideo)
|
||||
putExtra(EXTRA_ROOM_NAME, roomName)
|
||||
putExtra(EXTRA_ROOM_ID, roomId)
|
||||
putExtra(EXTRA_MATRIX_ID, matrixId)
|
||||
putExtra(EXTRA_CALL_ID, callId)
|
||||
}
|
||||
|
||||
|
@ -320,18 +309,10 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
}
|
||||
|
||||
fun onOutgoingCallRinging(context: Context,
|
||||
isVideo: Boolean,
|
||||
roomName: String,
|
||||
roomId: String,
|
||||
matrixId: String,
|
||||
callId: String) {
|
||||
val intent = Intent(context, CallService::class.java)
|
||||
.apply {
|
||||
action = ACTION_OUTGOING_RINGING_CALL
|
||||
putExtra(EXTRA_IS_VIDEO, isVideo)
|
||||
putExtra(EXTRA_ROOM_NAME, roomName)
|
||||
putExtra(EXTRA_ROOM_ID, roomId)
|
||||
putExtra(EXTRA_MATRIX_ID, matrixId)
|
||||
putExtra(EXTRA_CALL_ID, callId)
|
||||
}
|
||||
|
||||
|
@ -339,18 +320,10 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
}
|
||||
|
||||
fun onPendingCall(context: Context,
|
||||
isVideo: Boolean,
|
||||
roomName: String,
|
||||
roomId: String,
|
||||
matrixId: String,
|
||||
callId: String) {
|
||||
val intent = Intent(context, CallService::class.java)
|
||||
.apply {
|
||||
action = ACTION_ONGOING_CALL
|
||||
putExtra(EXTRA_IS_VIDEO, isVideo)
|
||||
putExtra(EXTRA_ROOM_NAME, roomName)
|
||||
putExtra(EXTRA_ROOM_ID, roomId)
|
||||
putExtra(EXTRA_MATRIX_ID, matrixId)
|
||||
putExtra(EXTRA_CALL_ID, callId)
|
||||
}
|
||||
|
||||
|
@ -362,7 +335,6 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe
|
|||
.apply {
|
||||
action = ACTION_NO_ACTIVE_CALL
|
||||
}
|
||||
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ package im.vector.app.features.call
|
|||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
@ -33,7 +35,7 @@ import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
|
|||
|
||||
class CallControlsView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
|
@ -56,8 +58,7 @@ class CallControlsView @JvmOverloads constructor(
|
|||
lateinit var videoToggleIcon: ImageView
|
||||
|
||||
init {
|
||||
ConstraintLayout.inflate(context, R.layout.view_call_controls, this)
|
||||
// layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
View.inflate(context, R.layout.view_call_controls, this)
|
||||
ButterKnife.bind(this)
|
||||
}
|
||||
|
||||
|
|
|
@ -339,12 +339,12 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
const val INCOMING_RINGING = "INCOMING_RINGING"
|
||||
const val INCOMING_ACCEPT = "INCOMING_ACCEPT"
|
||||
|
||||
fun newIntent(context: Context, mxCall: MxCallDetail): Intent {
|
||||
fun newIntent(context: Context, mxCall: MxCallDetail, mode: String?): Intent {
|
||||
return Intent(context, VectorCallActivity::class.java).apply {
|
||||
// what could be the best flags?
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
putExtra(MvRx.KEY_ARG, CallArgs(mxCall.roomId, mxCall.callId, mxCall.opponentUserId, !mxCall.isOutgoing, mxCall.isVideoCall))
|
||||
putExtra(EXTRA_MODE, OUTGOING_CREATED)
|
||||
putExtra(EXTRA_MODE, mode)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
|
||||
val callId = mxCall.callId
|
||||
val roomId = mxCall.roomId
|
||||
|
||||
private var peerConnection: PeerConnection? = null
|
||||
private var localAudioSource: AudioSource? = null
|
||||
|
@ -237,16 +238,9 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
mxCall
|
||||
.takeIf { it.state is CallState.Connected }
|
||||
?.let { mxCall ->
|
||||
val session = sessionProvider.get()
|
||||
val name = session?.getUser(mxCall.opponentUserId)?.getBestName()
|
||||
?: mxCall.roomId
|
||||
// Start background service with notification
|
||||
CallService.onPendingCall(
|
||||
context = context,
|
||||
isVideo = mxCall.isVideoCall,
|
||||
roomName = name,
|
||||
roomId = mxCall.roomId,
|
||||
matrixId = session?.myUserId ?: "",
|
||||
callId = mxCall.callId)
|
||||
}
|
||||
|
||||
|
@ -307,15 +301,8 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
.takeIf { it.state is CallState.Connected }
|
||||
?.let { mxCall ->
|
||||
// Start background service with notification
|
||||
val session = sessionProvider.get()
|
||||
val name = session?.getUser(mxCall.opponentUserId)?.getBestName()
|
||||
?: mxCall.opponentUserId
|
||||
CallService.onOnGoingCallBackground(
|
||||
context = context,
|
||||
isVideo = mxCall.isVideoCall,
|
||||
roomName = name,
|
||||
roomId = mxCall.roomId,
|
||||
matrixId = session?.myUserId ?: "",
|
||||
callId = mxCall.callId
|
||||
)
|
||||
}
|
||||
|
@ -344,15 +331,8 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
val turnServerResponse = getTurnServer()
|
||||
// Update service state
|
||||
withContext(Dispatchers.Main) {
|
||||
val session = sessionProvider.get()
|
||||
val name = session?.getUser(mxCall.opponentUserId)?.getBestName()
|
||||
?: mxCall.roomId
|
||||
CallService.onPendingCall(
|
||||
context = context,
|
||||
isVideo = mxCall.isVideoCall,
|
||||
roomName = name,
|
||||
roomId = mxCall.roomId,
|
||||
matrixId = session?.myUserId ?: "",
|
||||
callId = mxCall.callId
|
||||
)
|
||||
}
|
||||
|
|
|
@ -189,18 +189,12 @@ class WebRtcCallManager @Inject constructor(
|
|||
createWebRtcCall(mxCall)
|
||||
callAudioManager.startForCall(mxCall)
|
||||
|
||||
val name = currentSession?.getUser(mxCall.opponentUserId)?.getBestName()
|
||||
?: mxCall.opponentUserId
|
||||
CallService.onOutgoingCallRinging(
|
||||
context = context.applicationContext,
|
||||
isVideo = mxCall.isVideoCall,
|
||||
roomName = name,
|
||||
roomId = mxCall.roomId,
|
||||
matrixId = currentSession?.myUserId ?: "",
|
||||
callId = mxCall.callId)
|
||||
|
||||
// start the activity now
|
||||
context.startActivity(VectorCallActivity.newIntent(context, mxCall))
|
||||
context.startActivity(VectorCallActivity.newIntent(context, mxCall, VectorCallActivity.OUTGOING_CREATED))
|
||||
}
|
||||
|
||||
override fun onCallIceCandidateReceived(mxCall: MxCall, iceCandidatesContent: CallCandidatesContent) {
|
||||
|
@ -264,15 +258,10 @@ class WebRtcCallManager @Inject constructor(
|
|||
}
|
||||
callAudioManager.startForCall(mxCall)
|
||||
// Start background service with notification
|
||||
val name = currentSession?.getUser(mxCall.opponentUserId)?.getBestName()
|
||||
?: mxCall.opponentUserId
|
||||
CallService.onIncomingCallRinging(
|
||||
context = context,
|
||||
isVideo = mxCall.isVideoCall,
|
||||
roomName = name,
|
||||
roomId = mxCall.roomId,
|
||||
matrixId = currentSession?.myUserId ?: "",
|
||||
callId = mxCall.callId
|
||||
callId = mxCall.callId,
|
||||
isInBackground = isInBackground
|
||||
)
|
||||
// If this is received while in background, the app will not sync,
|
||||
// and thus won't be able to received events. For example if the call is
|
||||
|
@ -294,14 +283,8 @@ class WebRtcCallManager @Inject constructor(
|
|||
}
|
||||
val mxCall = call.mxCall
|
||||
// Update service state
|
||||
val name = currentSession?.getUser(mxCall.opponentUserId)?.getBestName()
|
||||
?: mxCall.opponentUserId
|
||||
CallService.onPendingCall(
|
||||
context = context,
|
||||
isVideo = mxCall.isVideoCall,
|
||||
roomName = name,
|
||||
roomId = mxCall.roomId,
|
||||
matrixId = currentSession?.myUserId ?: "",
|
||||
callId = mxCall.callId
|
||||
)
|
||||
call.onCallAnswerReceived(callAnswerContent)
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.crypto.verification
|
|||
import android.content.Context
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
|
@ -31,6 +32,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
|
|||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
|
@ -39,6 +41,7 @@ import javax.inject.Singleton
|
|||
@Singleton
|
||||
class IncomingVerificationRequestHandler @Inject constructor(
|
||||
private val context: Context,
|
||||
private var avatarRenderer: Provider<AvatarRenderer>,
|
||||
private val popupAlertManager: PopupAlertManager) : VerificationService.Listener {
|
||||
|
||||
private var session: Session? = null
|
||||
|
@ -60,9 +63,8 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
when (tx.state) {
|
||||
is VerificationTxState.OnStarted -> {
|
||||
// Add a notification for every incoming request
|
||||
val name = session?.getUser(tx.otherUserId)?.displayName
|
||||
?: tx.otherUserId
|
||||
|
||||
val user = session?.getUser(tx.otherUserId)
|
||||
val name = user?.displayName ?: tx.otherUserId
|
||||
val alert = VerificationVectorAlert(
|
||||
uid,
|
||||
context.getString(R.string.sas_incoming_request_notif_title),
|
||||
|
@ -77,10 +79,10 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
}
|
||||
} ?: true
|
||||
} else true
|
||||
},
|
||||
matrixItem = session?.getUser(tx.otherUserId)?.toMatrixItem()
|
||||
}
|
||||
)
|
||||
.apply {
|
||||
viewBinder = VerificationVectorAlert.ViewBinder(user?.toMatrixItem(), avatarRenderer.get())
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||
|
@ -120,8 +122,8 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
Timber.v("## SAS verificationRequestCreated ${pr.transactionId}")
|
||||
// For incoming request we should prompt (if not in activity where this request apply)
|
||||
if (pr.isIncoming) {
|
||||
val name = session?.getUser(pr.otherUserId)?.displayName
|
||||
?: pr.otherUserId
|
||||
val user = session?.getUser(pr.otherUserId)
|
||||
val name = user?.displayName ?: pr.otherUserId
|
||||
|
||||
val alert = VerificationVectorAlert(
|
||||
uniqueIdForVerificationRequest(pr),
|
||||
|
@ -134,10 +136,10 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
it.roomId != pr.roomId
|
||||
} ?: true
|
||||
} else true
|
||||
},
|
||||
matrixItem = session?.getUser(pr.otherUserId)?.toMatrixItem()
|
||||
}
|
||||
)
|
||||
.apply {
|
||||
viewBinder = VerificationVectorAlert.ViewBinder(user?.toMatrixItem(), avatarRenderer.get())
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
val roomId = pr.roomId
|
||||
|
@ -154,7 +156,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
pr.roomId ?: ""
|
||||
)
|
||||
}
|
||||
colorInt = ThemeUtils.getColor(context, R.attr.vctr_notice_secondary)
|
||||
colorAttribute = R.attr.vctr_notice_secondary
|
||||
// 5mn expiration
|
||||
expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L)
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
private val serverBackupStatusViewModel: ServerBackupStatusViewModel by viewModel()
|
||||
@Inject lateinit var serverBackupviewModelFactory: ServerBackupStatusViewModel.Factory
|
||||
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
|
||||
@Inject lateinit var pushManager: PushersManager
|
||||
|
@ -126,9 +127,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
when (sharedAction) {
|
||||
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenGroup -> {
|
||||
is HomeActivitySharedAction.OpenGroup -> {
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||
}
|
||||
|
@ -145,9 +146,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
homeActivityViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is HomeActivityViewEvents.AskPasswordToInitCrossSigning -> handleAskPasswordToInitCrossSigning(it)
|
||||
is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it)
|
||||
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
|
||||
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
|
||||
is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it)
|
||||
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
|
||||
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
|
||||
}.exhaustive
|
||||
}
|
||||
homeActivityViewModel.subscribe(this) { renderState(it) }
|
||||
|
@ -180,7 +181,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
|
||||
private fun renderState(state: HomeActivityViewState) {
|
||||
when (val status = state.initialSyncProgressServiceStatus) {
|
||||
is InitialSyncProgressService.Status.Idle -> {
|
||||
is InitialSyncProgressService.Status.Idle -> {
|
||||
waiting_view.isVisible = false
|
||||
}
|
||||
is InitialSyncProgressService.Status.Progressing -> {
|
||||
|
@ -251,7 +252,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
it is HomeActivity
|
||||
}
|
||||
).apply {
|
||||
colorInt = ThemeUtils.getColor(this@HomeActivity, R.attr.vctr_notice_secondary)
|
||||
colorAttribute = R.attr.vctr_notice_secondary
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
// action(it)
|
||||
|
@ -283,8 +284,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
title = getString(titleRes),
|
||||
description = getString(descRes),
|
||||
iconId = R.drawable.ic_shield_warning,
|
||||
matrixItem = userItem
|
||||
).apply {
|
||||
viewBinder = VerificationVectorAlert.ViewBinder(userItem, avatarRenderer)
|
||||
colorInt = ContextCompat.getColor(this@HomeActivity, R.color.riotx_positive_accent)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
|
|
|
@ -151,9 +151,9 @@ class HomeDetailFragment @Inject constructor(
|
|||
uid = uid,
|
||||
title = getString(R.string.new_session),
|
||||
description = getString(R.string.verify_this_session, newest.displayName ?: newest.deviceId ?: ""),
|
||||
iconId = R.drawable.ic_shield_warning,
|
||||
matrixItem = user
|
||||
iconId = R.drawable.ic_shield_warning
|
||||
).apply {
|
||||
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer)
|
||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)
|
||||
|
@ -179,9 +179,9 @@ class HomeDetailFragment @Inject constructor(
|
|||
uid = uid,
|
||||
title = getString(R.string.review_logins),
|
||||
description = getString(R.string.verify_other_sessions),
|
||||
iconId = R.drawable.ic_shield_warning,
|
||||
matrixItem = user
|
||||
iconId = R.drawable.ic_shield_warning
|
||||
).apply {
|
||||
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer)
|
||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
|
|
|
@ -72,7 +72,7 @@ class RoomDetailActivity :
|
|||
}
|
||||
|
||||
// Simple filter
|
||||
private var currentRoomId: String? = null
|
||||
var currentRoomId: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
|
@ -118,8 +118,8 @@ import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs
|
|||
import im.vector.app.features.attachments.toGroupedContentAttachmentData
|
||||
import im.vector.app.features.call.SharedActiveCallViewModel
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.command.Command
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
|
@ -311,7 +311,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
setupActiveCallView()
|
||||
setupJumpToBottomView()
|
||||
setupConfBannerView()
|
||||
|
||||
roomToolbarContentView.debouncedClicks {
|
||||
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
|
||||
}
|
||||
|
@ -340,9 +339,9 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
when (mode) {
|
||||
is SendMode.REGULAR -> renderRegularMode(mode.text)
|
||||
is SendMode.EDIT -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_edit, R.string.edit, mode.text)
|
||||
is SendMode.QUOTE -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_quote, R.string.quote, mode.text)
|
||||
is SendMode.REPLY -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_reply, R.string.reply, mode.text)
|
||||
is SendMode.EDIT -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_edit, R.string.edit, mode.text)
|
||||
is SendMode.QUOTE -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_quote, R.string.quote, mode.text)
|
||||
is SendMode.REPLY -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_reply, R.string.reply, mode.text)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,33 +351,33 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
roomDetailViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is RoomDetailViewEvents.Failure -> showErrorInSnackbar(it.throwable)
|
||||
is RoomDetailViewEvents.OnNewTimelineEvents -> scrollOnNewMessageCallback.addNewTimelineEventIds(it.eventIds)
|
||||
is RoomDetailViewEvents.ActionSuccess -> displayRoomDetailActionSuccess(it)
|
||||
is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it)
|
||||
is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG)
|
||||
is RoomDetailViewEvents.NavigateToEvent -> navigateToEvent(it)
|
||||
is RoomDetailViewEvents.FileTooBigError -> displayFileTooBigError(it)
|
||||
is RoomDetailViewEvents.DownloadFileState -> handleDownloadFileState(it)
|
||||
is RoomDetailViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
|
||||
is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it)
|
||||
is RoomDetailViewEvents.ShowE2EErrorMessage -> displayE2eError(it.withHeldCode)
|
||||
RoomDetailViewEvents.DisplayPromptForIntegrationManager -> displayPromptForIntegrationManager()
|
||||
is RoomDetailViewEvents.OpenStickerPicker -> openStickerPicker(it)
|
||||
is RoomDetailViewEvents.Failure -> showErrorInSnackbar(it.throwable)
|
||||
is RoomDetailViewEvents.OnNewTimelineEvents -> scrollOnNewMessageCallback.addNewTimelineEventIds(it.eventIds)
|
||||
is RoomDetailViewEvents.ActionSuccess -> displayRoomDetailActionSuccess(it)
|
||||
is RoomDetailViewEvents.ActionFailure -> displayRoomDetailActionFailure(it)
|
||||
is RoomDetailViewEvents.ShowMessage -> showSnackWithMessage(it.message, Snackbar.LENGTH_LONG)
|
||||
is RoomDetailViewEvents.NavigateToEvent -> navigateToEvent(it)
|
||||
is RoomDetailViewEvents.FileTooBigError -> displayFileTooBigError(it)
|
||||
is RoomDetailViewEvents.DownloadFileState -> handleDownloadFileState(it)
|
||||
is RoomDetailViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
|
||||
is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it)
|
||||
is RoomDetailViewEvents.ShowE2EErrorMessage -> displayE2eError(it.withHeldCode)
|
||||
RoomDetailViewEvents.DisplayPromptForIntegrationManager -> displayPromptForIntegrationManager()
|
||||
is RoomDetailViewEvents.OpenStickerPicker -> openStickerPicker(it)
|
||||
is RoomDetailViewEvents.DisplayEnableIntegrationsWarning -> displayDisabledIntegrationDialog()
|
||||
is RoomDetailViewEvents.OpenIntegrationManager -> openIntegrationManager()
|
||||
is RoomDetailViewEvents.OpenFile -> startOpenFileIntent(it)
|
||||
RoomDetailViewEvents.OpenActiveWidgetBottomSheet -> onViewWidgetsClicked()
|
||||
is RoomDetailViewEvents.ShowInfoOkDialog -> showDialogWithMessage(it.message)
|
||||
is RoomDetailViewEvents.JoinJitsiConference -> joinJitsiRoom(it.widget, it.withVideo)
|
||||
RoomDetailViewEvents.ShowWaitingView -> vectorBaseActivity.showWaitingView()
|
||||
RoomDetailViewEvents.HideWaitingView -> vectorBaseActivity.hideWaitingView()
|
||||
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
|
||||
is RoomDetailViewEvents.OpenRoom -> handleOpenRoom(it)
|
||||
RoomDetailViewEvents.OpenInvitePeople -> navigator.openInviteUsersToRoom(requireContext(), roomDetailArgs.roomId)
|
||||
RoomDetailViewEvents.OpenSetRoomAvatarDialog -> galleryOrCameraDialogHelper.show()
|
||||
RoomDetailViewEvents.OpenRoomSettings -> handleOpenRoomSettings()
|
||||
is RoomDetailViewEvents.ShowRoomAvatarFullScreen -> it.matrixItem?.let { item ->
|
||||
is RoomDetailViewEvents.OpenIntegrationManager -> openIntegrationManager()
|
||||
is RoomDetailViewEvents.OpenFile -> startOpenFileIntent(it)
|
||||
RoomDetailViewEvents.OpenActiveWidgetBottomSheet -> onViewWidgetsClicked()
|
||||
is RoomDetailViewEvents.ShowInfoOkDialog -> showDialogWithMessage(it.message)
|
||||
is RoomDetailViewEvents.JoinJitsiConference -> joinJitsiRoom(it.widget, it.withVideo)
|
||||
RoomDetailViewEvents.ShowWaitingView -> vectorBaseActivity.showWaitingView()
|
||||
RoomDetailViewEvents.HideWaitingView -> vectorBaseActivity.hideWaitingView()
|
||||
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
|
||||
is RoomDetailViewEvents.OpenRoom -> handleOpenRoom(it)
|
||||
RoomDetailViewEvents.OpenInvitePeople -> navigator.openInviteUsersToRoom(requireContext(), roomDetailArgs.roomId)
|
||||
RoomDetailViewEvents.OpenSetRoomAvatarDialog -> galleryOrCameraDialogHelper.show()
|
||||
RoomDetailViewEvents.OpenRoomSettings -> handleOpenRoomSettings()
|
||||
is RoomDetailViewEvents.ShowRoomAvatarFullScreen -> it.matrixItem?.let { item ->
|
||||
navigator.openBigImageViewer(requireActivity(), it.view, item)
|
||||
}
|
||||
}.exhaustive
|
||||
|
@ -525,14 +524,14 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun handleShareData() {
|
||||
when (val sharedData = roomDetailArgs.sharedData) {
|
||||
is SharedData.Text -> {
|
||||
is SharedData.Text -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterRegularMode(sharedData.text, fromSharing = true))
|
||||
}
|
||||
is SharedData.Attachments -> {
|
||||
// open share edition
|
||||
onContentAttachmentsReady(sharedData.attachmentData)
|
||||
}
|
||||
null -> Timber.v("No share data to process")
|
||||
null -> Timber.v("No share data to process")
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -657,8 +656,8 @@ class RoomDetailFragment @Inject constructor(
|
|||
withState(roomDetailViewModel) { state ->
|
||||
// Set the visual state of the call buttons (voice/video) to enabled/disabled according to user permissions
|
||||
val callButtonsEnabled = when (state.asyncRoomSummary.invoke()?.joinedMembersCount) {
|
||||
1 -> false
|
||||
2 -> state.isAllowedToStartWebRTCCall
|
||||
1 -> false
|
||||
2 -> state.isAllowedToStartWebRTCCall
|
||||
else -> state.isAllowedToManageWidgets
|
||||
}
|
||||
setOf(R.id.voice_call, R.id.video_call).forEach {
|
||||
|
@ -688,36 +687,36 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.invite -> {
|
||||
R.id.invite -> {
|
||||
navigator.openInviteUsersToRoom(requireActivity(), roomDetailArgs.roomId)
|
||||
true
|
||||
}
|
||||
R.id.timeline_setting -> {
|
||||
R.id.timeline_setting -> {
|
||||
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
|
||||
true
|
||||
}
|
||||
R.id.resend_all -> {
|
||||
R.id.resend_all -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ResendAll)
|
||||
true
|
||||
}
|
||||
R.id.open_matrix_apps -> {
|
||||
R.id.open_matrix_apps -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ManageIntegrations)
|
||||
true
|
||||
}
|
||||
R.id.voice_call,
|
||||
R.id.video_call -> {
|
||||
R.id.video_call -> {
|
||||
handleCallRequest(item)
|
||||
true
|
||||
}
|
||||
R.id.hangup_call -> {
|
||||
R.id.hangup_call -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EndCall)
|
||||
true
|
||||
}
|
||||
R.id.search -> {
|
||||
R.id.search -> {
|
||||
handleSearchAction()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -733,7 +732,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
val roomSummary = state.asyncRoomSummary.invoke() ?: return@withState
|
||||
val isVideoCall = item.itemId == R.id.video_call
|
||||
when (roomSummary.joinedMembersCount) {
|
||||
1 -> {
|
||||
1 -> {
|
||||
val pendingInvite = roomSummary.invitedMembersCount ?: 0 > 0
|
||||
if (pendingInvite) {
|
||||
// wait for other to join
|
||||
|
@ -743,7 +742,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
showDialogWithMessage(getString(R.string.cannot_call_yourself))
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
2 -> {
|
||||
val activeCall = sharedCallActionViewModel.activeCall.value
|
||||
if (activeCall != null) {
|
||||
// resume existing if same room, if not prompt to kill and then restart new call?
|
||||
|
@ -924,9 +923,9 @@ class RoomDetailFragment @Inject constructor(
|
|||
when (roomDetailPendingAction) {
|
||||
is RoomDetailPendingAction.JumpToReadReceipt ->
|
||||
roomDetailViewModel.handle(RoomDetailAction.JumpToReadReceipt(roomDetailPendingAction.userId))
|
||||
is RoomDetailPendingAction.MentionUser ->
|
||||
is RoomDetailPendingAction.MentionUser ->
|
||||
insertUserDisplayNameInTextEditor(roomDetailPendingAction.userId)
|
||||
is RoomDetailPendingAction.OpenOrCreateDm ->
|
||||
is RoomDetailPendingAction.OpenOrCreateDm ->
|
||||
roomDetailViewModel.handle(RoomDetailAction.OpenOrCreateDm(roomDetailPendingAction.userId))
|
||||
}.exhaustive
|
||||
}
|
||||
|
@ -1069,9 +1068,9 @@ class RoomDetailFragment @Inject constructor(
|
|||
withState(roomDetailViewModel) {
|
||||
val showJumpToUnreadBanner = when (it.unreadState) {
|
||||
UnreadState.Unknown,
|
||||
UnreadState.HasNoUnread -> false
|
||||
UnreadState.HasNoUnread -> false
|
||||
is UnreadState.ReadMarkerNotLoaded -> true
|
||||
is UnreadState.HasUnread -> {
|
||||
is UnreadState.HasUnread -> {
|
||||
if (it.canShowJumpToReadMarker) {
|
||||
val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
|
||||
val positionOfReadMarker = timelineEventController.getPositionOfReadMarker()
|
||||
|
@ -1280,7 +1279,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
navigator.openRoom(vectorBaseActivity, async())
|
||||
vectorBaseActivity.finish()
|
||||
}
|
||||
is Fail -> {
|
||||
is Fail -> {
|
||||
vectorBaseActivity.hideWaitingView()
|
||||
vectorBaseActivity.toast(errorFormatter.toHumanReadable(async.error))
|
||||
}
|
||||
|
@ -1289,19 +1288,19 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun renderSendMessageResult(sendMessageResult: RoomDetailViewEvents.SendMessageResult) {
|
||||
when (sendMessageResult) {
|
||||
is RoomDetailViewEvents.SlashCommandHandled -> {
|
||||
is RoomDetailViewEvents.SlashCommandHandled -> {
|
||||
sendMessageResult.messageRes?.let { showSnackWithMessage(getString(it)) }
|
||||
}
|
||||
is RoomDetailViewEvents.SlashCommandError -> {
|
||||
is RoomDetailViewEvents.SlashCommandError -> {
|
||||
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
|
||||
}
|
||||
is RoomDetailViewEvents.SlashCommandUnknown -> {
|
||||
is RoomDetailViewEvents.SlashCommandUnknown -> {
|
||||
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
|
||||
}
|
||||
is RoomDetailViewEvents.SlashCommandResultOk -> {
|
||||
is RoomDetailViewEvents.SlashCommandResultOk -> {
|
||||
updateComposerText("")
|
||||
}
|
||||
is RoomDetailViewEvents.SlashCommandResultError -> {
|
||||
is RoomDetailViewEvents.SlashCommandResultError -> {
|
||||
displayCommandError(errorFormatter.toHumanReadable(sendMessageResult.throwable))
|
||||
}
|
||||
is RoomDetailViewEvents.SlashCommandNotImplemented -> {
|
||||
|
@ -1323,7 +1322,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
private fun displayE2eError(withHeldCode: WithHeldCode?) {
|
||||
val msgId = when (withHeldCode) {
|
||||
WithHeldCode.BLACKLISTED -> R.string.crypto_error_withheld_blacklisted
|
||||
WithHeldCode.UNVERIFIED -> R.string.crypto_error_withheld_unverified
|
||||
WithHeldCode.UNVERIFIED -> R.string.crypto_error_withheld_unverified
|
||||
WithHeldCode.UNAUTHORISED,
|
||||
WithHeldCode.UNAVAILABLE -> R.string.crypto_error_withheld_generic
|
||||
else -> R.string.notice_crypto_unable_to_decrypt_friendly_desc
|
||||
|
@ -1375,7 +1374,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun displayRoomDetailActionSuccess(result: RoomDetailViewEvents.ActionSuccess) {
|
||||
when (val data = result.action) {
|
||||
is RoomDetailAction.ReportContent -> {
|
||||
is RoomDetailAction.ReportContent -> {
|
||||
when {
|
||||
data.spam -> {
|
||||
AlertDialog.Builder(requireActivity())
|
||||
|
@ -1412,7 +1411,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
is RoomDetailAction.RequestVerification -> {
|
||||
is RoomDetailAction.RequestVerification -> {
|
||||
Timber.v("## SAS RequestVerification action")
|
||||
VerificationBottomSheet.withArgs(
|
||||
roomDetailArgs.roomId,
|
||||
|
@ -1427,7 +1426,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
data.transactionId
|
||||
).show(parentFragmentManager, "REQ")
|
||||
}
|
||||
is RoomDetailAction.ResumeVerification -> {
|
||||
is RoomDetailAction.ResumeVerification -> {
|
||||
val otherUserId = data.otherUserId ?: return
|
||||
VerificationBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
|
@ -1571,11 +1570,11 @@ class RoomDetailFragment @Inject constructor(
|
|||
is MessageVerificationRequestContent -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ResumeVerification(informationData.eventId, null))
|
||||
}
|
||||
is MessageWithAttachmentContent -> {
|
||||
is MessageWithAttachmentContent -> {
|
||||
val action = RoomDetailAction.DownloadOrOpen(informationData.eventId, informationData.senderId, messageContent)
|
||||
roomDetailViewModel.handle(action)
|
||||
}
|
||||
is EncryptedEventContent -> {
|
||||
is EncryptedEventContent -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.TapOnFailedToDecrypt(informationData.eventId))
|
||||
}
|
||||
}
|
||||
|
@ -1716,75 +1715,75 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun handleActions(action: EventSharedAction) {
|
||||
when (action) {
|
||||
is EventSharedAction.OpenUserProfile -> {
|
||||
is EventSharedAction.OpenUserProfile -> {
|
||||
openRoomMemberProfile(action.userId)
|
||||
}
|
||||
is EventSharedAction.AddReaction -> {
|
||||
is EventSharedAction.AddReaction -> {
|
||||
emojiActivityResultLauncher.launch(EmojiReactionPickerActivity.intent(requireContext(), action.eventId))
|
||||
}
|
||||
is EventSharedAction.ViewReactions -> {
|
||||
is EventSharedAction.ViewReactions -> {
|
||||
ViewReactionsBottomSheet.newInstance(roomDetailArgs.roomId, action.messageInformationData)
|
||||
.show(requireActivity().supportFragmentManager, "DISPLAY_REACTIONS")
|
||||
}
|
||||
is EventSharedAction.Copy -> {
|
||||
is EventSharedAction.Copy -> {
|
||||
// I need info about the current selected message :/
|
||||
copyToClipboard(requireContext(), action.content, false)
|
||||
showSnackWithMessage(getString(R.string.copied_to_clipboard), Snackbar.LENGTH_SHORT)
|
||||
}
|
||||
is EventSharedAction.Redact -> {
|
||||
is EventSharedAction.Redact -> {
|
||||
promptConfirmationToRedactEvent(action)
|
||||
}
|
||||
is EventSharedAction.Share -> {
|
||||
is EventSharedAction.Share -> {
|
||||
onShareActionClicked(action)
|
||||
}
|
||||
is EventSharedAction.Save -> {
|
||||
is EventSharedAction.Save -> {
|
||||
onSaveActionClicked(action)
|
||||
}
|
||||
is EventSharedAction.ViewEditHistory -> {
|
||||
is EventSharedAction.ViewEditHistory -> {
|
||||
onEditedDecorationClicked(action.messageInformationData)
|
||||
}
|
||||
is EventSharedAction.ViewSource -> {
|
||||
is EventSharedAction.ViewSource -> {
|
||||
JSonViewerDialog.newInstance(
|
||||
action.content,
|
||||
-1,
|
||||
createJSonViewerStyleProvider(colorProvider)
|
||||
).show(childFragmentManager, "JSON_VIEWER")
|
||||
}
|
||||
is EventSharedAction.ViewDecryptedSource -> {
|
||||
is EventSharedAction.ViewDecryptedSource -> {
|
||||
JSonViewerDialog.newInstance(
|
||||
action.content,
|
||||
-1,
|
||||
createJSonViewerStyleProvider(colorProvider)
|
||||
).show(childFragmentManager, "JSON_VIEWER")
|
||||
}
|
||||
is EventSharedAction.QuickReact -> {
|
||||
is EventSharedAction.QuickReact -> {
|
||||
// eventId,ClickedOn,Add
|
||||
roomDetailViewModel.handle(RoomDetailAction.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
|
||||
}
|
||||
is EventSharedAction.Edit -> {
|
||||
is EventSharedAction.Edit -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterEditMode(action.eventId, composerLayout.text.toString()))
|
||||
}
|
||||
is EventSharedAction.Quote -> {
|
||||
is EventSharedAction.Quote -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterQuoteMode(action.eventId, composerLayout.text.toString()))
|
||||
}
|
||||
is EventSharedAction.Reply -> {
|
||||
is EventSharedAction.Reply -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(action.eventId, composerLayout.text.toString()))
|
||||
}
|
||||
is EventSharedAction.CopyPermalink -> {
|
||||
is EventSharedAction.CopyPermalink -> {
|
||||
val permalink = session.permalinkService().createPermalink(roomDetailArgs.roomId, action.eventId)
|
||||
copyToClipboard(requireContext(), permalink, false)
|
||||
showSnackWithMessage(getString(R.string.copied_to_clipboard), Snackbar.LENGTH_SHORT)
|
||||
}
|
||||
is EventSharedAction.Resend -> {
|
||||
is EventSharedAction.Resend -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ResendMessage(action.eventId))
|
||||
}
|
||||
is EventSharedAction.Remove -> {
|
||||
is EventSharedAction.Remove -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.RemoveFailedEcho(action.eventId))
|
||||
}
|
||||
is EventSharedAction.Cancel -> {
|
||||
is EventSharedAction.Cancel -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.CancelSend(action.eventId))
|
||||
}
|
||||
is EventSharedAction.ReportContentSpam -> {
|
||||
is EventSharedAction.ReportContentSpam -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ReportContent(
|
||||
action.eventId, action.senderId, "This message is spam", spam = true))
|
||||
}
|
||||
|
@ -1792,22 +1791,22 @@ class RoomDetailFragment @Inject constructor(
|
|||
roomDetailViewModel.handle(RoomDetailAction.ReportContent(
|
||||
action.eventId, action.senderId, "This message is inappropriate", inappropriate = true))
|
||||
}
|
||||
is EventSharedAction.ReportContentCustom -> {
|
||||
is EventSharedAction.ReportContentCustom -> {
|
||||
promptReasonToReportContent(action)
|
||||
}
|
||||
is EventSharedAction.IgnoreUser -> {
|
||||
is EventSharedAction.IgnoreUser -> {
|
||||
action.senderId?.let { askConfirmationToIgnoreUser(it) }
|
||||
}
|
||||
is EventSharedAction.OnUrlClicked -> {
|
||||
is EventSharedAction.OnUrlClicked -> {
|
||||
onUrlClicked(action.url, action.title)
|
||||
}
|
||||
is EventSharedAction.OnUrlLongClicked -> {
|
||||
is EventSharedAction.OnUrlLongClicked -> {
|
||||
onUrlLongClicked(action.url)
|
||||
}
|
||||
is EventSharedAction.ReRequestKey -> {
|
||||
is EventSharedAction.ReRequestKey -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ReRequestKeys(action.eventId))
|
||||
}
|
||||
is EventSharedAction.UseKeyBackup -> {
|
||||
is EventSharedAction.UseKeyBackup -> {
|
||||
context?.let {
|
||||
startActivity(KeysBackupRestoreActivity.intent(it))
|
||||
}
|
||||
|
@ -1947,10 +1946,10 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) {
|
||||
when (type) {
|
||||
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(requireContext(), attachmentPhotoActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(requireContext(), attachmentPhotoActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentImageActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment)
|
||||
}.exhaustive
|
||||
|
|
|
@ -52,6 +52,8 @@ import im.vector.app.features.home.room.detail.RoomDetailActivity
|
|||
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.settings.troubleshoot.TestNotificationReceiver
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -269,19 +271,19 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
* @param roomName the room name in which the call is pending.
|
||||
* @param matrixId the matrix id
|
||||
* @param callId the call id.
|
||||
* @param fromBg true if the app is in background when posting the notification
|
||||
* @return the call notification.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
fun buildIncomingCallNotification(isVideo: Boolean,
|
||||
otherUserId: String,
|
||||
roomId: String,
|
||||
callId: String): Notification {
|
||||
fun buildIncomingCallNotification(mxCall: MxCall,
|
||||
title: String,
|
||||
fromBg: Boolean): Notification {
|
||||
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(ensureTitleNotEmpty(otherUserId))
|
||||
val notificationChannel = if (fromBg) CALL_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID
|
||||
val builder = NotificationCompat.Builder(context, notificationChannel)
|
||||
.setContentTitle(ensureTitleNotEmpty(title))
|
||||
.apply {
|
||||
if (isVideo) {
|
||||
if (mxCall.isVideoCall) {
|
||||
setContentText(stringProvider.getString(R.string.incoming_video_call))
|
||||
} else {
|
||||
setContentText(stringProvider.getString(R.string.incoming_voice_call))
|
||||
|
@ -300,15 +302,11 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
|
||||
val contentIntent = VectorCallActivity.newIntent(
|
||||
context = context,
|
||||
callId = callId,
|
||||
roomId = roomId,
|
||||
otherUserId = otherUserId,
|
||||
isIncomingCall = true,
|
||||
isVideoCall = isVideo,
|
||||
mxCall = mxCall,
|
||||
mode = VectorCallActivity.INCOMING_RINGING
|
||||
).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
data = Uri.parse("foobar://$callId")
|
||||
data = Uri.parse("foobar://${mxCall.callId}")
|
||||
}
|
||||
val contentPendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), contentIntent, 0)
|
||||
|
||||
|
@ -316,20 +314,16 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
||||
.addNextIntent(VectorCallActivity.newIntent(
|
||||
context = context,
|
||||
callId = callId,
|
||||
roomId = roomId,
|
||||
otherUserId = otherUserId,
|
||||
isIncomingCall = true,
|
||||
isVideoCall = isVideo,
|
||||
mxCall = mxCall,
|
||||
mode = VectorCallActivity.INCOMING_ACCEPT)
|
||||
)
|
||||
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(callId)
|
||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(mxCall.callId)
|
||||
|
||||
builder.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_call,
|
||||
R.drawable.ic_call_answer,
|
||||
// IconCompat.createWithResource(applicationContext, R.drawable.ic_call)
|
||||
// .setTint(ContextCompat.getColor(applicationContext, R.color.riotx_positive_accent)),
|
||||
context.getString(R.string.call_notification_answer),
|
||||
|
@ -339,7 +333,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
|
||||
builder.addAction(
|
||||
NotificationCompat.Action(
|
||||
IconCompat.createWithResource(context, R.drawable.ic_call_end).setTint(ContextCompat.getColor(context, R.color.riotx_notice)),
|
||||
IconCompat.createWithResource(context, R.drawable.ic_call_hangup).setTint(ContextCompat.getColor(context, R.color.riotx_notice)),
|
||||
context.getString(R.string.call_notification_reject),
|
||||
rejectCallPendingIntent)
|
||||
)
|
||||
|
@ -349,14 +343,11 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
return builder.build()
|
||||
}
|
||||
|
||||
fun buildOutgoingRingingCallNotification(isVideo: Boolean,
|
||||
otherUserId: String,
|
||||
roomId: String,
|
||||
callId: String): Notification {
|
||||
fun buildOutgoingRingingCallNotification(mxCall: MxCall,
|
||||
title: String): Notification {
|
||||
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(ensureTitleNotEmpty(otherUserId))
|
||||
.setContentTitle(ensureTitleNotEmpty(title))
|
||||
.apply {
|
||||
setContentText(stringProvider.getString(R.string.call_ring))
|
||||
}
|
||||
|
@ -367,18 +358,14 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
|
||||
val contentIntent = VectorCallActivity.newIntent(
|
||||
context = context,
|
||||
callId = callId,
|
||||
roomId = roomId,
|
||||
otherUserId = otherUserId,
|
||||
isIncomingCall = true,
|
||||
isVideoCall = isVideo,
|
||||
mxCall = mxCall,
|
||||
mode = null).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
data = Uri.parse("foobar://$callId")
|
||||
data = Uri.parse("foobar://$mxCall.callId")
|
||||
}
|
||||
val contentPendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), contentIntent, 0)
|
||||
|
||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(callId)
|
||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(mxCall.callId)
|
||||
|
||||
builder.addAction(
|
||||
NotificationCompat.Action(
|
||||
|
@ -402,16 +389,13 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
* @return the call notification.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
fun buildPendingCallNotification(isVideo: Boolean,
|
||||
roomName: String,
|
||||
roomId: String,
|
||||
matrixId: String,
|
||||
callId: String,
|
||||
fun buildPendingCallNotification(mxCall: MxCall,
|
||||
title: String,
|
||||
fromBg: Boolean = false): Notification {
|
||||
val builder = NotificationCompat.Builder(context, if (fromBg) CALL_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(ensureTitleNotEmpty(roomName))
|
||||
.setContentTitle(ensureTitleNotEmpty(title))
|
||||
.apply {
|
||||
if (isVideo) {
|
||||
if (mxCall.isVideoCall) {
|
||||
setContentText(stringProvider.getString(R.string.video_call_in_progress))
|
||||
} else {
|
||||
setContentText(stringProvider.getString(R.string.call_in_progress))
|
||||
|
@ -425,7 +409,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
builder.setOngoing(true)
|
||||
}
|
||||
|
||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(callId)
|
||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(mxCall.callId)
|
||||
|
||||
builder.addAction(
|
||||
NotificationCompat.Action(
|
||||
|
@ -436,8 +420,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
|
||||
val contentPendingIntent = TaskStackBuilder.create(context)
|
||||
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
||||
// TODO other userId
|
||||
.addNextIntent(VectorCallActivity.newIntent(context, callId, roomId, "otherUserId", true, isVideo, null))
|
||||
.addNextIntent(VectorCallActivity.newIntent(context, mxCall, null))
|
||||
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
builder.setContentIntent(contentPendingIntent)
|
||||
|
@ -462,7 +445,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
|||
* Build a temporary (because service will be stopped just after) notification for the CallService, when a call is ended
|
||||
*/
|
||||
fun buildCallEndedNotification(): Notification {
|
||||
return NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID)
|
||||
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(stringProvider.getString(R.string.call_ended))
|
||||
.setSmallIcon(R.drawable.ic_material_call_end_grey)
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.popup
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import im.vector.app.R
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
class IncomingCallAlert(uid: String,
|
||||
override val shouldBeDisplayedIn: ((Activity) -> Boolean) = { true }
|
||||
) : DefaultVectorAlert(uid, "", "", 0, shouldBeDisplayedIn) {
|
||||
|
||||
override val layoutRes = R.layout.alerter_incoming_call_layout
|
||||
override var colorAttribute: Int? = R.attr.riotx_alerter_background
|
||||
|
||||
class ViewBinder(private val matrixItem: MatrixItem?,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val isVideoCall: Boolean,
|
||||
private val onAccept: () -> Unit,
|
||||
private val onReject: () -> Unit)
|
||||
: VectorAlert.ViewBinder {
|
||||
|
||||
override fun bind(view: View) {
|
||||
val callKind = if (isVideoCall) {
|
||||
R.string.action_video_call
|
||||
} else {
|
||||
R.string.action_voice_call
|
||||
}
|
||||
view.findViewById<TextView>(R.id.incomingCallKindView).setText(callKind)
|
||||
view.findViewById<TextView>(R.id.incomingCallNameView).text = matrixItem?.getBestName()
|
||||
view.findViewById<ImageView>(R.id.incomingCallAvatar)?.let { imageView ->
|
||||
matrixItem?.let { avatarRenderer.render(it, imageView) }
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.incomingCallAcceptView).setOnClickListener {
|
||||
onAccept()
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.incomingCallRejectView).setOnClickListener {
|
||||
onReject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,14 +21,11 @@ import android.os.Build
|
|||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.tapadoo.alerter.Alerter
|
||||
import com.tapadoo.alerter.OnHideAlertListener
|
||||
import dagger.Lazy
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.isAnimationDisabled
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.pin.PinActivity
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import timber.log.Timber
|
||||
|
@ -41,7 +38,7 @@ import javax.inject.Singleton
|
|||
* Alerts are stacked and will be displayed sequentially
|
||||
*/
|
||||
@Singleton
|
||||
class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<AvatarRenderer>) {
|
||||
class PopupAlertManager @Inject constructor() {
|
||||
|
||||
private var weakCurrentActivity: WeakReference<Activity>? = null
|
||||
private var currentAlerter: VectorAlert? = null
|
||||
|
@ -191,17 +188,13 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
val noAnimation = !animate || isAnimationDisabled(activity)
|
||||
|
||||
alert.weakCurrentActivity = WeakReference(activity)
|
||||
val alerter = if (alert is VerificationVectorAlert) Alerter.create(activity, R.layout.alerter_verification_layout)
|
||||
else Alerter.create(activity)
|
||||
val alerter = Alerter.create(activity, alert.layoutRes)
|
||||
|
||||
alerter.setTitle(alert.title)
|
||||
.setText(alert.description)
|
||||
.also { al ->
|
||||
if (alert is VerificationVectorAlert) {
|
||||
val tvCustomView = al.getLayoutContainer()
|
||||
tvCustomView?.findViewById<ImageView>(R.id.ivUserAvatar)?.let { imageView ->
|
||||
alert.matrixItem?.let { avatarRenderer.get().render(it, imageView) }
|
||||
}
|
||||
al.getLayoutContainer()?.also {
|
||||
alert.viewBinder?.bind(it)
|
||||
}
|
||||
}
|
||||
.apply {
|
||||
|
@ -251,6 +244,8 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
.apply {
|
||||
if (alert.colorInt != null) {
|
||||
setBackgroundColorInt(alert.colorInt!!)
|
||||
} else if (alert.colorAttribute != null) {
|
||||
setBackgroundColorInt(ThemeUtils.getColor(activity, alert.colorAttribute!!))
|
||||
} else {
|
||||
setBackgroundColorRes(alert.colorRes ?: R.color.notification_accent_color)
|
||||
}
|
||||
|
|
|
@ -17,12 +17,18 @@
|
|||
package im.vector.app.features.popup
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import im.vector.app.R
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
||||
interface VectorAlert {
|
||||
val uid: String
|
||||
val title: String
|
||||
|
@ -47,22 +53,34 @@ interface VectorAlert {
|
|||
actions.add(Button(title, action, autoClose))
|
||||
}
|
||||
|
||||
var viewBinder: ViewBinder?
|
||||
|
||||
val layoutRes: Int
|
||||
|
||||
var colorRes: Int?
|
||||
|
||||
var colorInt: Int?
|
||||
|
||||
var colorAttribute: Int?
|
||||
|
||||
interface ViewBinder {
|
||||
fun bind(view: View)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataclass to describe an important alert with actions.
|
||||
*/
|
||||
open class DefaultVectorAlert(override val uid: String,
|
||||
override val title: String,
|
||||
override val description: String,
|
||||
@DrawableRes override val iconId: Int?,
|
||||
/**
|
||||
* Alert are displayed by default, but let this lambda return false to prevent displaying
|
||||
*/
|
||||
override val shouldBeDisplayedIn: ((Activity) -> Boolean) = { true }
|
||||
open class DefaultVectorAlert(
|
||||
override val uid: String,
|
||||
override val title: String,
|
||||
override val description: String,
|
||||
@DrawableRes override val iconId: Int?,
|
||||
/**
|
||||
* Alert are displayed by default, but let this lambda return false to prevent displaying
|
||||
*/
|
||||
override val shouldBeDisplayedIn: ((Activity) -> Boolean) = { true },
|
||||
) : VectorAlert {
|
||||
|
||||
// will be set by manager, and accessible by actions at runtime
|
||||
|
@ -76,26 +94,19 @@ open class DefaultVectorAlert(override val uid: String,
|
|||
/** If this timestamp is after current time, this alert will be skipped */
|
||||
override var expirationTimestamp: Long? = null
|
||||
|
||||
override fun addButton(title: String, action: Runnable, autoClose: Boolean) {
|
||||
actions.add(VectorAlert.Button(title, action, autoClose))
|
||||
}
|
||||
@LayoutRes
|
||||
override val layoutRes = R.layout.alerter_alert_default_layout
|
||||
|
||||
@ColorRes
|
||||
override var colorRes: Int? = null
|
||||
|
||||
@ColorInt
|
||||
override var colorInt: Int? = null
|
||||
|
||||
@AttrRes
|
||||
override var colorAttribute: Int? = null
|
||||
|
||||
override var viewBinder: VectorAlert.ViewBinder? = null
|
||||
|
||||
}
|
||||
|
||||
class VerificationVectorAlert(uid: String,
|
||||
title: String,
|
||||
override val description: String,
|
||||
@DrawableRes override val iconId: Int?,
|
||||
/**
|
||||
* Alert are displayed by default, but let this lambda return false to prevent displaying
|
||||
*/
|
||||
override val shouldBeDisplayedIn: ((Activity) -> Boolean) = { true },
|
||||
val matrixItem: MatrixItem?
|
||||
) : DefaultVectorAlert(
|
||||
uid, title, description, iconId, shouldBeDisplayedIn
|
||||
)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.popup
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.DrawableRes
|
||||
import im.vector.app.R
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
class VerificationVectorAlert(uid: String,
|
||||
title: String,
|
||||
override val description: String,
|
||||
@DrawableRes override val iconId: Int?,
|
||||
/**
|
||||
* Alert are displayed by default, but let this lambda return false to prevent displaying
|
||||
*/
|
||||
override val shouldBeDisplayedIn: ((Activity) -> Boolean) = { true }
|
||||
) : DefaultVectorAlert(
|
||||
uid, title, description, iconId, shouldBeDisplayedIn
|
||||
) {
|
||||
override val layoutRes = R.layout.alerter_verification_layout
|
||||
|
||||
class ViewBinder(private val matrixItem: MatrixItem?,
|
||||
private val avatarRenderer: AvatarRenderer)
|
||||
: VectorAlert.ViewBinder {
|
||||
|
||||
override fun bind(view: View) {
|
||||
view.findViewById<ImageView>(R.id.ivUserAvatar)?.let { imageView ->
|
||||
matrixItem?.let { avatarRenderer.render(it, imageView) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
83
vector/src/main/res/layout/alerter_incoming_call_layout.xml
Normal file
83
vector/src/main/res/layout/alerter_incoming_call_layout.xml
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:style="@style/AlertStyle"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/incomingCallAvatar"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:contentDescription="@string/call_notification_answer"
|
||||
android:layout_margin="12dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/incomingCallNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@+id/incomingCallRejectView"
|
||||
app:layout_constraintStart_toEndOf="@id/incomingCallAvatar"
|
||||
app:layout_constraintTop_toTopOf="@id/incomingCallAvatar"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/incomingCallKindView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintEnd_toStartOf="@+id/incomingCallRejectView"
|
||||
app:layout_constraintStart_toStartOf="@id/incomingCallNameView"
|
||||
app:layout_constraintTop_toBottomOf="@id/incomingCallNameView"
|
||||
tools:text="@string/action_voice_call" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/incomingCallAcceptView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/oval_positive"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/call_notification_answer"
|
||||
android:focusable="true"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:src="@drawable/ic_call_answer" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/incomingCallRejectView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/oval_destructive"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/call_notification_reject"
|
||||
android:focusable="true"
|
||||
android:padding="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/incomingCallAcceptView"
|
||||
android:src="@drawable/ic_call_hangup" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -179,7 +179,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomToolbar"
|
||||
tools:visibility="visible" />
|
||||
tools:visibility="gone" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/badgeBarrier"
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:parentTag="android.widget.FrameLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
@ -200,4 +201,4 @@
|
|||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
||||
|
||||
</FrameLayout>
|
||||
</merge>
|
|
@ -238,9 +238,16 @@
|
|||
<color name="riotx_reaction_background_on_dark">#4011BC8A</color>
|
||||
<color name="riotx_reaction_background_on_black">#4011BC8A</color>
|
||||
|
||||
<attr name="riotx_alerter_background" format="color" />
|
||||
<color name="riotx_alerter_background_light">#FFF3F8FD</color>
|
||||
<color name="riotx_alerter_background_dark">#FF282C35</color>
|
||||
<color name="riotx_alerter_background_black">#FF282C35</color>
|
||||
|
||||
<!-- (color from RiotWeb) -->
|
||||
<attr name="riotx_keys_backup_banner_accent_color" format="color" />
|
||||
<color name="riotx_keys_backup_banner_accent_color_light">#FFF8E3</color>
|
||||
<color name="riotx_keys_backup_banner_accent_color_dark">#22262E</color>
|
||||
|
||||
|
||||
|
||||
</resources>
|
|
@ -38,6 +38,7 @@
|
|||
<item name="riotx_room_active_widgets_banner_text">@color/riotx_room_active_widgets_banner_text_black</item>
|
||||
<item name="riotx_reaction_background_off">@color/riotx_reaction_background_off_black</item>
|
||||
<item name="riotx_reaction_background_on">@color/riotx_reaction_background_on_black</item>
|
||||
<item name="riotx_alerter_background">@color/riotx_alerter_background_black</item>
|
||||
|
||||
<item name="riotx_bottom_nav_icon_color">@color/riotx_bottom_nav_icon_color_black</item>
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<item name="riotx_room_active_widgets_banner_text">@color/riotx_room_active_widgets_banner_text_dark</item>
|
||||
<item name="riotx_reaction_background_off">@color/riotx_reaction_background_off_dark</item>
|
||||
<item name="riotx_reaction_background_on">@color/riotx_reaction_background_on_dark</item>
|
||||
|
||||
<item name="riotx_alerter_background">@color/riotx_alerter_background_dark</item>
|
||||
<item name="riotx_bottom_nav_icon_color">@color/riotx_bottom_nav_icon_color_dark</item>
|
||||
|
||||
<item name="riotx_keys_backup_banner_accent_color">@color/riotx_keys_backup_banner_accent_color_dark</item>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<item name="riotx_room_active_widgets_banner_text">@color/riotx_room_active_widgets_banner_text_light</item>
|
||||
<item name="riotx_reaction_background_off">@color/riotx_reaction_background_off_light</item>
|
||||
<item name="riotx_reaction_background_on">@color/riotx_reaction_background_on_light</item>
|
||||
|
||||
<item name="riotx_alerter_background">@color/riotx_alerter_background_light</item>
|
||||
<item name="riotx_bottom_nav_icon_color">@color/riotx_bottom_nav_icon_color_light</item>
|
||||
|
||||
<!-- Material color: Note: this block should be the same in all theme because it references only common colors and ?riotx attributes -->
|
||||
|
|
Loading…
Reference in a new issue