mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Render incoming Element Call in the timeline (unsupported)
This commit is contained in:
parent
ac94bff81e
commit
066545a4b3
@ -2937,6 +2937,8 @@
|
|||||||
|
|
||||||
<string name="call_slide_to_end_conference">Slide to end the call</string>
|
<string name="call_slide_to_end_conference">Slide to end the call</string>
|
||||||
|
|
||||||
|
<string name="call_unsupported_matrix_rtc_call">Unsupported call. The new Element X app is needed to join this call.</string>
|
||||||
|
|
||||||
<string name="re_authentication_activity_title">Re-Authentication Needed</string>
|
<string name="re_authentication_activity_title">Re-Authentication Needed</string>
|
||||||
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
||||||
<string name="re_authentication_default_confirm_text">${app_name} requires you to enter your credentials to perform this action.</string>
|
<string name="re_authentication_default_confirm_text">${app_name} requires you to enter your credentials to perform this action.</string>
|
||||||
|
@ -87,6 +87,9 @@ object EventType {
|
|||||||
// This type is not processed by the client, just sent to the server
|
// This type is not processed by the client, just sent to the server
|
||||||
const val CALL_REPLACES = "m.call.replaces"
|
const val CALL_REPLACES = "m.call.replaces"
|
||||||
|
|
||||||
|
// Element Call
|
||||||
|
val ELEMENT_CALL_NOTIFY = StableUnstableId(stable = "m.call.notify", unstable = "org.matrix.msc4075.call.notify")
|
||||||
|
|
||||||
// Key share events
|
// Key share events
|
||||||
const val ROOM_KEY_REQUEST = "m.room_key_request"
|
const val ROOM_KEY_REQUEST = "m.room_key_request"
|
||||||
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
|
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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 org.matrix.android.sdk.api.session.room.model.message
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class ElementCallNotifyContent(
|
||||||
|
@Json(name = "application") val application: String? = null,
|
||||||
|
@Json(name = "call_id") val callId: String? = null,
|
||||||
|
@Json(name = "m.mentions") val mentions: Mentions? = null,
|
||||||
|
@Json(name = "notify_type") val notifyType: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class Mentions(
|
||||||
|
@Json(name = "room") val room: Boolean? = null,
|
||||||
|
@Json(name = "user_ids") val userIds: List<String>? = null,
|
||||||
|
)
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
package im.vector.app.features.home.room.detail.timeline.factory
|
||||||
|
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.resources.UserPreferencesProvider
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.item.ElementCallTileTimelineItem
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.item.ElementCallTileTimelineItem_
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.item.ReactionsSummaryEvents
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.ElementCallNotifyContent
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ElementCallItemFactory @Inject constructor(
|
||||||
|
private val session: Session,
|
||||||
|
private val userPreferencesProvider: UserPreferencesProvider,
|
||||||
|
private val messageColorProvider: MessageColorProvider,
|
||||||
|
private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||||
|
private val messageItemAttributesFactory: MessageItemAttributesFactory,
|
||||||
|
private val avatarSizeProvider: AvatarSizeProvider,
|
||||||
|
private val noticeItemFactory: NoticeItemFactory
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? {
|
||||||
|
val event = params.event
|
||||||
|
if (event.root.eventId == null) return null
|
||||||
|
val showHiddenEvents = userPreferencesProvider.shouldShowHiddenEvents()
|
||||||
|
val roomSummary = params.partialState.roomSummary ?: return null
|
||||||
|
val informationData = messageInformationDataFactory.create(params)
|
||||||
|
val callItem = when (event.root.getClearType()) {
|
||||||
|
in EventType.ELEMENT_CALL_NOTIFY.values -> {
|
||||||
|
val notifyContent: ElementCallNotifyContent = event.root.content.toModel() ?: return null
|
||||||
|
createElementCallTileTimelineItem(
|
||||||
|
roomSummary = roomSummary,
|
||||||
|
callId = notifyContent.callId.orEmpty(),
|
||||||
|
callStatus = ElementCallTileTimelineItem.CallStatus.INVITED,
|
||||||
|
callKind = ElementCallTileTimelineItem.CallKind.VIDEO,
|
||||||
|
callback = params.callback,
|
||||||
|
highlight = params.isHighlighted,
|
||||||
|
informationData = informationData,
|
||||||
|
reactionsSummaryEvents = params.reactionsSummaryEvents
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
return if (callItem == null && showHiddenEvents) {
|
||||||
|
// Fallback to notice item for showing hidden events
|
||||||
|
noticeItemFactory.create(params)
|
||||||
|
} else {
|
||||||
|
callItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createElementCallTileTimelineItem(
|
||||||
|
roomSummary: RoomSummary,
|
||||||
|
callId: String,
|
||||||
|
callKind: ElementCallTileTimelineItem.CallKind,
|
||||||
|
callStatus: ElementCallTileTimelineItem.CallStatus,
|
||||||
|
informationData: MessageInformationData,
|
||||||
|
highlight: Boolean,
|
||||||
|
callback: TimelineEventController.Callback?,
|
||||||
|
reactionsSummaryEvents: ReactionsSummaryEvents?
|
||||||
|
): ElementCallTileTimelineItem? {
|
||||||
|
val userOfInterest = roomSummary.toMatrixItem()
|
||||||
|
val attributes = messageItemAttributesFactory.create(null, informationData, callback, reactionsSummaryEvents).let {
|
||||||
|
ElementCallTileTimelineItem.Attributes(
|
||||||
|
callId = callId,
|
||||||
|
callKind = callKind,
|
||||||
|
callStatus = callStatus,
|
||||||
|
informationData = informationData,
|
||||||
|
avatarRenderer = it.avatarRenderer,
|
||||||
|
messageColorProvider = messageColorProvider,
|
||||||
|
itemClickListener = it.itemClickListener,
|
||||||
|
itemLongClickListener = it.itemLongClickListener,
|
||||||
|
reactionPillCallback = it.reactionPillCallback,
|
||||||
|
readReceiptsCallback = it.readReceiptsCallback,
|
||||||
|
userOfInterest = userOfInterest,
|
||||||
|
callback = callback,
|
||||||
|
reactionsSummaryEvents = reactionsSummaryEvents
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ElementCallTileTimelineItem_()
|
||||||
|
.attributes(attributes)
|
||||||
|
.highlighted(highlight)
|
||||||
|
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,7 @@ class TimelineItemFactory @Inject constructor(
|
|||||||
private val widgetItemFactory: WidgetItemFactory,
|
private val widgetItemFactory: WidgetItemFactory,
|
||||||
private val verificationConclusionItemFactory: VerificationItemFactory,
|
private val verificationConclusionItemFactory: VerificationItemFactory,
|
||||||
private val callItemFactory: CallItemFactory,
|
private val callItemFactory: CallItemFactory,
|
||||||
|
private val elementCallItemFactory: ElementCallItemFactory,
|
||||||
private val decryptionFailureTracker: DecryptionFailureTracker,
|
private val decryptionFailureTracker: DecryptionFailureTracker,
|
||||||
private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper,
|
private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
@ -119,6 +120,8 @@ class TimelineItemFactory @Inject constructor(
|
|||||||
noticeItemFactory.create(params)
|
noticeItemFactory.create(params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Element Call
|
||||||
|
in EventType.ELEMENT_CALL_NOTIFY.values -> elementCallItemFactory.create(params)
|
||||||
// Calls
|
// Calls
|
||||||
EventType.CALL_INVITE,
|
EventType.CALL_INVITE,
|
||||||
EventType.CALL_HANGUP,
|
EventType.CALL_HANGUP,
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
package im.vector.app.features.home.room.detail.timeline.item
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.features.displayname.getBestName
|
||||||
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
import im.vector.lib.strings.CommonStrings
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class ElementCallTileTimelineItem : AbsBaseMessageItem<ElementCallTileTimelineItem.Holder>(R.layout.item_timeline_event_base_state) {
|
||||||
|
|
||||||
|
override val baseAttributes: AbsBaseMessageItem.Attributes
|
||||||
|
get() = attributes
|
||||||
|
|
||||||
|
override fun isCacheable() = false
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
lateinit var attributes: Attributes
|
||||||
|
|
||||||
|
override fun getViewStubId() = STUB_ID
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.endGuideline.updateLayoutParams<RelativeLayout.LayoutParams> {
|
||||||
|
this.marginEnd = leftGuideline
|
||||||
|
}
|
||||||
|
holder.creatorNameView.text = attributes.userOfInterest.getBestName()
|
||||||
|
attributes.avatarRenderer.render(attributes.userOfInterest, holder.creatorAvatarView)
|
||||||
|
renderSendState(holder.view, null, holder.failedToSendIndicator)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : AbsBaseMessageItem.Holder(STUB_ID) {
|
||||||
|
val creatorAvatarView by bind<ImageView>(R.id.itemCallCreatorAvatar)
|
||||||
|
val creatorNameView by bind<TextView>(R.id.itemCallCreatorNameTextView)
|
||||||
|
val endGuideline by bind<View>(R.id.messageEndGuideline)
|
||||||
|
val failedToSendIndicator by bind<ImageView>(R.id.messageFailToSendIndicator)
|
||||||
|
|
||||||
|
val resources: Resources
|
||||||
|
get() = view.context.resources
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val STUB_ID = R.id.messageElementCallStub
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Attributes(
|
||||||
|
val callId: String,
|
||||||
|
val callKind: CallKind,
|
||||||
|
val callStatus: CallStatus,
|
||||||
|
val userOfInterest: MatrixItem,
|
||||||
|
val callback: TimelineEventController.Callback? = null,
|
||||||
|
override val informationData: MessageInformationData,
|
||||||
|
override val avatarRenderer: AvatarRenderer,
|
||||||
|
override val messageColorProvider: MessageColorProvider,
|
||||||
|
override val itemLongClickListener: View.OnLongClickListener? = null,
|
||||||
|
override val itemClickListener: ClickListener? = null,
|
||||||
|
override val reactionPillCallback: TimelineEventController.ReactionPillCallback? = null,
|
||||||
|
override val readReceiptsCallback: TimelineEventController.ReadReceiptsCallback? = null,
|
||||||
|
override val reactionsSummaryEvents: ReactionsSummaryEvents? = null
|
||||||
|
) : AbsBaseMessageItem.Attributes
|
||||||
|
|
||||||
|
enum class CallKind(@DrawableRes val icon: Int, @StringRes val title: Int) {
|
||||||
|
VIDEO(R.drawable.ic_call_video_small, CommonStrings.action_video_call),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class CallStatus {
|
||||||
|
INVITED,
|
||||||
|
}
|
||||||
|
}
|
@ -52,21 +52,28 @@
|
|||||||
android:id="@+id/messageVerificationRequestStub"
|
android:id="@+id/messageVerificationRequestStub"
|
||||||
style="@style/TimelineContentStubBaseParams"
|
style="@style/TimelineContentStubBaseParams"
|
||||||
android:layout="@layout/item_timeline_event_verification_stub"
|
android:layout="@layout/item_timeline_event_verification_stub"
|
||||||
tools:layout_marginTop="250dp"
|
tools:layout_marginTop="200dp"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
android:id="@+id/messageVerificationDoneStub"
|
android:id="@+id/messageVerificationDoneStub"
|
||||||
style="@style/TimelineContentStubBaseParams"
|
style="@style/TimelineContentStubBaseParams"
|
||||||
android:layout="@layout/item_timeline_event_status_tile_stub"
|
android:layout="@layout/item_timeline_event_status_tile_stub"
|
||||||
tools:layout_marginTop="450dp"
|
tools:layout_marginTop="360dp"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
android:id="@+id/messageWidgetStub"
|
android:id="@+id/messageWidgetStub"
|
||||||
style="@style/TimelineContentStubBaseParams"
|
style="@style/TimelineContentStubBaseParams"
|
||||||
android:layout="@layout/item_timeline_event_widget_stub"
|
android:layout="@layout/item_timeline_event_widget_stub"
|
||||||
tools:layout_marginTop="280dp"
|
tools:layout_marginTop="440dp"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ViewStub
|
||||||
|
android:id="@+id/messageElementCallStub"
|
||||||
|
style="@style/TimelineContentStubBaseParams"
|
||||||
|
android:layout="@layout/item_timeline_event_element_call_tile_stub"
|
||||||
|
tools:layout_marginTop="520dp"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout 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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:viewBindingIgnore="true">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemCallCreatorAvatar"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
tools:src="@sample/user_round_avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemCallCreatorNameTextView"
|
||||||
|
style="@style/Widget.Vector.TextView.Subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:drawablePadding="6dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="@sample/users.json/data/displayName" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemCallStatusTextView"
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:gravity="start"
|
||||||
|
android:maxLines="3"
|
||||||
|
android:text="@string/call_unsupported_matrix_rtc_call"
|
||||||
|
android:textColor="?vctr_content_secondary"
|
||||||
|
app:drawableStartCompat="@drawable/ic_call_audio_small" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
Loading…
Reference in New Issue
Block a user