From 8fdce937bdb134ed654a5c579ce6bdf6a7f728a2 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 20 Feb 2019 11:39:25 +0100 Subject: [PATCH 1/5] Timeline: handle notice events and hide some not displayable events. --- app/build.gradle | 1 + .../vector/riotredesign/core/di/AppModule.kt | 5 +++ .../riotredesign/core/epoxy/EmptyItem.kt | 27 +++++++++++++ .../home => core/epoxy}/LoadingItem.kt | 2 +- .../core/resources/ColorProvider.kt | 31 +++++++++++++++ .../riotredesign/features/home/HomeModule.kt | 11 +----- .../detail/timeline/MessageItemFactory.kt | 39 ++++++++++++++----- .../timeline/TimelineEventController.kt | 2 +- .../detail/timeline/TimelineItemFactory.kt | 4 ++ app/src/main/res/layout/item_empty.xml | 4 ++ 10 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/im/vector/riotredesign/core/epoxy/EmptyItem.kt rename app/src/main/java/im/vector/riotredesign/{features/home => core/epoxy}/LoadingItem.kt (94%) create mode 100644 app/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt create mode 100644 app/src/main/res/layout/item_empty.xml diff --git a/app/build.gradle b/app/build.gradle index b569a182..12b174e0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -96,6 +96,7 @@ dependencies { kapt 'com.github.bumptech.glide:compiler:4.8.0' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation 'com.google.android.material:material:1.1.0-alpha02' + implementation 'me.gujun.android:span:1.7' // DI implementation "org.koin:koin-android:$koin_version" diff --git a/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt index 13f93eba..bbc97315 100644 --- a/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ b/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt @@ -18,6 +18,7 @@ package im.vector.riotredesign.core.di import android.content.Context import android.content.Context.MODE_PRIVATE +import im.vector.riotredesign.core.resources.ColorProvider import im.vector.riotredesign.core.resources.LocaleProvider import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository @@ -35,6 +36,10 @@ class AppModule(private val context: Context) { StringProvider(context.resources) } + single { + ColorProvider(context) + } + single { context.getSharedPreferences("im.vector.riot", MODE_PRIVATE) } diff --git a/app/src/main/java/im/vector/riotredesign/core/epoxy/EmptyItem.kt b/app/src/main/java/im/vector/riotredesign/core/epoxy/EmptyItem.kt new file mode 100644 index 00000000..9abf7c7a --- /dev/null +++ b/app/src/main/java/im/vector/riotredesign/core/epoxy/EmptyItem.kt @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2019 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.riotredesign.core.epoxy + +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.riotredesign.R + +@EpoxyModelClass(layout = R.layout.item_empty) +abstract class EmptyItem : RiotEpoxyModel() { + class Holder : RiotEpoxyHolder() +} \ No newline at end of file diff --git a/app/src/main/java/im/vector/riotredesign/features/home/LoadingItem.kt b/app/src/main/java/im/vector/riotredesign/core/epoxy/LoadingItem.kt similarity index 94% rename from app/src/main/java/im/vector/riotredesign/features/home/LoadingItem.kt rename to app/src/main/java/im/vector/riotredesign/core/epoxy/LoadingItem.kt index c803c047..cade275b 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/LoadingItem.kt +++ b/app/src/main/java/im/vector/riotredesign/core/epoxy/LoadingItem.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.riotredesign.features.home +package im.vector.riotredesign.core.epoxy import android.content.Context import android.widget.ProgressBar diff --git a/app/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt b/app/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt new file mode 100644 index 00000000..4fd37212 --- /dev/null +++ b/app/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt @@ -0,0 +1,31 @@ +/* + * + * * Copyright 2019 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.riotredesign.core.resources + +import android.content.Context +import androidx.annotation.ColorRes +import androidx.core.content.ContextCompat + +class ColorProvider(private val context: Context) { + + fun getColor(@ColorRes colorRes: Int): Int { + return ContextCompat.getColor(context, colorRes) + } + +} \ No newline at end of file diff --git a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index b63f7142..05001818 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -18,14 +18,7 @@ package im.vector.riotredesign.features.home import im.vector.riotredesign.features.home.group.SelectedGroupStore import im.vector.riotredesign.features.home.room.VisibleRoomStore -import im.vector.riotredesign.features.home.room.detail.timeline.DefaultItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.MessageItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.RoomMemberItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.RoomNameItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.RoomTopicItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.TimelineDateFormatter -import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController -import im.vector.riotredesign.features.home.room.detail.timeline.TimelineItemFactory +import im.vector.riotredesign.features.home.room.detail.timeline.* import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator import im.vector.riotredesign.features.home.room.list.RoomSummaryController @@ -40,7 +33,7 @@ class HomeModule { } single { - MessageItemFactory(get(), get()) + MessageItemFactory(get(), get(), get()) } single { diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt index fc377798..e2f61cf0 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt @@ -22,17 +22,18 @@ import im.vector.matrix.android.api.permalinks.MatrixLinkify import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.message.MessageContent -import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent -import im.vector.matrix.android.api.session.room.model.message.MessageImageContent -import im.vector.matrix.android.api.session.room.model.message.MessageTextContent +import im.vector.matrix.android.api.session.room.model.message.* import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.R import im.vector.riotredesign.core.epoxy.RiotEpoxyModel import im.vector.riotredesign.core.extensions.localDateTime +import im.vector.riotredesign.core.resources.ColorProvider import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.riotredesign.features.media.MediaContentRenderer +import me.gujun.android.span.span -class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSizeProvider, +class MessageItemFactory(private val colorProvider: ColorProvider, + private val timelineMediaSizeProvider: TimelineMediaSizeProvider, private val timelineDateFormatter: TimelineDateFormatter) { private val messagesDisplayedWithInformation = HashSet() @@ -66,10 +67,11 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz val informationData = MessageInformationData(time, avatarUrl, memberName, showInformation) return when (messageContent) { - is MessageTextContent -> buildTextMessageItem(messageContent, informationData, callback) - is MessageImageContent -> buildImageMessageItem(messageContent, informationData) - is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, callback) - else -> buildNotHandledMessageItem(messageContent) + is MessageTextContent -> buildTextMessageItem(messageContent, informationData, callback) + is MessageImageContent -> buildImageMessageItem(messageContent, informationData) + is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, callback) + is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback) + else -> buildNotHandledMessageItem(messageContent) } } @@ -106,6 +108,23 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz .informationData(informationData) } + private fun buildNoticeMessageItem(messageContent: MessageNoticeContent, + informationData: MessageInformationData, + callback: TimelineEventController.Callback?): MessageTextItem? { + + val message = messageContent.body.let { + val formattedBody = span { + text = it + textColor = colorProvider.getColor(R.color.slate_grey) + textStyle = "italic" + } + linkifyBody(formattedBody, callback) + } + return MessageTextItem_() + .message(message) + .informationData(informationData) + } + private fun buildEmoteMessageItem(messageContent: MessageEmoteContent, informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageTextItem? { @@ -119,7 +138,7 @@ class MessageItemFactory(private val timelineMediaSizeProvider: TimelineMediaSiz .informationData(informationData) } - private fun linkifyBody(body: String, callback: TimelineEventController.Callback?): CharSequence { + private fun linkifyBody(body: CharSequence, callback: TimelineEventController.Callback?): CharSequence { val spannable = SpannableStringBuilder(body) MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback { override fun onUrlClicked(url: String) { diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index 75b3f265..373612c1 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -23,9 +23,9 @@ import com.airbnb.epoxy.VisibilityState import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.room.timeline.TimelineData import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.core.epoxy.LoadingItemModel_ import im.vector.riotredesign.core.epoxy.RiotEpoxyModel import im.vector.riotredesign.core.extensions.localDateTime -import im.vector.riotredesign.features.home.LoadingItemModel_ import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.riotredesign.features.home.room.detail.timeline.paging.PagedListEpoxyController diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt index 8fca5301..366ea2d9 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt @@ -18,6 +18,7 @@ package im.vector.riotredesign.features.home.room.detail.timeline import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.core.epoxy.EmptyItem_ import im.vector.riotredesign.core.epoxy.RiotEpoxyModel class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, @@ -36,6 +37,9 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event) EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event) EventType.STATE_ROOM_MEMBER -> roomMemberItemFactory.create(event) + EventType.STATE_ROOM_CREATE, + EventType.STATE_ROOM_POWER_LEVELS, + EventType.REDACTION -> EmptyItem_() else -> defaultItemFactory.create(event) } } catch (e: Exception) { diff --git a/app/src/main/res/layout/item_empty.xml b/app/src/main/res/layout/item_empty.xml new file mode 100644 index 00000000..f7afb775 --- /dev/null +++ b/app/src/main/res/layout/item_empty.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file From 42cf45c8f34435ac2c4c8f71a14bfbc9771f020c Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 20 Feb 2019 12:06:33 +0100 Subject: [PATCH 2/5] Timeline: handle room history visibility --- .../riotredesign/features/home/HomeModule.kt | 6 +- .../RoomHistoryVisibilityItemFactory.kt | 56 +++++++++++++++++++ .../detail/timeline/TimelineItemFactory.kt | 14 +++-- .../model/RoomHistoryVisibilityContent.kt | 27 +++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt diff --git a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index 05001818..4514fe15 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -48,12 +48,16 @@ class HomeModule { RoomMemberItemFactory(get()) } + single { + RoomHistoryVisibilityItemFactory(get()) + } + single { DefaultItemFactory() } single { - TimelineItemFactory(get(), get(), get(), get(), get()) + TimelineItemFactory(get(), get(), get(), get(), get(), get()) } single { diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt new file mode 100644 index 00000000..e692b81d --- /dev/null +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt @@ -0,0 +1,56 @@ +/* + * + * * Copyright 2019 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.riotredesign.features.home.room.detail.timeline + +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibilityContent +import im.vector.matrix.android.api.session.room.model.RoomMember +import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.R +import im.vector.riotredesign.core.resources.StringProvider + + +class RoomHistoryVisibilityItemFactory(private val stringProvider: StringProvider) { + + fun create(event: TimelineEvent): NoticeItem? { + val roomMember = event.roomMember ?: return null + val noticeText = buildRoomMemberNotice(event.root, roomMember) ?: return null + return NoticeItem_() + .noticeText(noticeText) + .avatarUrl(roomMember.avatarUrl) + .memberName(roomMember.displayName) + } + + private fun buildRoomMemberNotice(event: Event, roomMember: RoomMember): CharSequence? { + val content = event.content.toModel() ?: return null + val formattedVisibility = when (content.historyVisibility) { + RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared) + RoomHistoryVisibility.INVITED -> stringProvider.getString(R.string.notice_room_visibility_invited) + RoomHistoryVisibility.JOINED -> stringProvider.getString(R.string.notice_room_visibility_joined) + RoomHistoryVisibility.WORLD_READABLE -> stringProvider.getString(R.string.notice_room_visibility_world_readable) + } + return stringProvider.getString(R.string.notice_made_future_room_visibility, roomMember.displayName, formattedVisibility) + } + + +} + + diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt index 366ea2d9..3f6a7b4b 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt @@ -25,6 +25,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, private val roomNameItemFactory: RoomNameItemFactory, private val roomTopicItemFactory: RoomTopicItemFactory, private val roomMemberItemFactory: RoomMemberItemFactory, + private val roomHistoryVisibilityItemFactory: RoomHistoryVisibilityItemFactory, private val defaultItemFactory: DefaultItemFactory) { fun create(event: TimelineEvent, @@ -33,14 +34,15 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, return try { when (event.root.type) { - EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback) - EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event) - EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event) - EventType.STATE_ROOM_MEMBER -> roomMemberItemFactory.create(event) + EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback) + EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event) + EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event) + EventType.STATE_ROOM_MEMBER -> roomMemberItemFactory.create(event) + EventType.STATE_HISTORY_VISIBILITY -> roomHistoryVisibilityItemFactory.create(event) EventType.STATE_ROOM_CREATE, EventType.STATE_ROOM_POWER_LEVELS, - EventType.REDACTION -> EmptyItem_() - else -> defaultItemFactory.create(event) + EventType.REDACTION -> EmptyItem_() + else -> defaultItemFactory.create(event) } } catch (e: Exception) { defaultItemFactory.create(event, e) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt new file mode 100644 index 00000000..0c9a1f9e --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomHistoryVisibilityContent.kt @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2019 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.matrix.android.api.session.room.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class RoomHistoryVisibilityContent( + @Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility +) \ No newline at end of file From 28c837a47f5e878cfa1ed9467563c4dd724dc14f Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 20 Feb 2019 15:47:20 +0100 Subject: [PATCH 3/5] Timeline: handle call events --- .../riotredesign/features/home/HomeModule.kt | 6 +- .../room/detail/timeline/CallItemFactory.kt | 60 +++++++++++++++++++ .../detail/timeline/TimelineItemFactory.kt | 7 +++ .../api/session/events/model/EventType.kt | 6 ++ .../room/model/call/CallAnswerContent.kt | 37 ++++++++++++ .../room/model/call/CallCandidatesContent.kt | 38 ++++++++++++ .../room/model/call/CallHangupContent.kt | 28 +++++++++ .../room/model/call/CallInviteContent.kt | 42 +++++++++++++ 8 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/CallItemFactory.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallHangupContent.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt diff --git a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index 4514fe15..2f2d85a0 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -48,6 +48,10 @@ class HomeModule { RoomMemberItemFactory(get()) } + single { + CallItemFactory(get()) + } + single { RoomHistoryVisibilityItemFactory(get()) } @@ -57,7 +61,7 @@ class HomeModule { } single { - TimelineItemFactory(get(), get(), get(), get(), get(), get()) + TimelineItemFactory(get(), get(), get(), get(), get(), get(), get()) } single { diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/CallItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/CallItemFactory.kt new file mode 100644 index 00000000..b5bc183f --- /dev/null +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/CallItemFactory.kt @@ -0,0 +1,60 @@ +/* + * + * * Copyright 2019 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.riotredesign.features.home.room.detail.timeline + +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.room.model.RoomMember +import im.vector.matrix.android.api.session.room.model.call.CallInviteContent +import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.R +import im.vector.riotredesign.core.resources.StringProvider + +class CallItemFactory(private val stringProvider: StringProvider) { + + fun create(event: TimelineEvent): NoticeItem? { + val roomMember = event.roomMember ?: return null + val text = buildNoticeText(event.root, roomMember) ?: return null + return NoticeItem_() + .noticeText(text) + .avatarUrl(roomMember.avatarUrl) + .memberName(roomMember.displayName) + } + + private fun buildNoticeText(event: Event, roomMember: RoomMember): CharSequence? { + return when { + EventType.CALL_INVITE == event.type -> { + val content = event.content.toModel()?: return null + val isVideoCall = content.offer.sdp == CallInviteContent.Offer.SDP_VIDEO + return if(isVideoCall){ + stringProvider.getString(R.string.notice_placed_video_call, roomMember.displayName) + }else{ + stringProvider.getString(R.string.notice_placed_voice_call, roomMember.displayName) + } + } + EventType.CALL_ANSWER == event.type -> stringProvider.getString(R.string.notice_answered_call, roomMember.displayName) + EventType.CALL_HANGUP == event.type -> stringProvider.getString(R.string.notice_ended_call, roomMember.displayName) + else -> null + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt index 3f6a7b4b..5909a01c 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt @@ -26,6 +26,7 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, private val roomTopicItemFactory: RoomTopicItemFactory, private val roomMemberItemFactory: RoomMemberItemFactory, private val roomHistoryVisibilityItemFactory: RoomHistoryVisibilityItemFactory, + private val callItemFactory: CallItemFactory, private val defaultItemFactory: DefaultItemFactory) { fun create(event: TimelineEvent, @@ -39,8 +40,14 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event) EventType.STATE_ROOM_MEMBER -> roomMemberItemFactory.create(event) EventType.STATE_HISTORY_VISIBILITY -> roomHistoryVisibilityItemFactory.create(event) + EventType.CALL_INVITE, + EventType.CALL_HANGUP, + EventType.CALL_ANSWER -> callItemFactory.create(event) EventType.STATE_ROOM_CREATE, EventType.STATE_ROOM_POWER_LEVELS, + EventType.STATE_ROOM_JOIN_RULES, + EventType.STATE_ROOM_GUEST_ACCESS, + EventType.CALL_CANDIDATES, EventType.REDACTION -> EmptyItem_() else -> defaultItemFactory.create(event) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt index e0f10bdd..4315fd59 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/EventType.kt @@ -86,4 +86,10 @@ object EventType { return STATE_EVENTS.contains(type) } + fun isCallEvent(type: String): Boolean { + return type == CALL_INVITE + || type == CALL_CANDIDATES + || type == CALL_ANSWER + || type == CALL_HANGUP + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt new file mode 100644 index 00000000..89c5d1a4 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallAnswerContent.kt @@ -0,0 +1,37 @@ +/* + * + * * Copyright 2019 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.matrix.android.api.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class CallAnswerContent( + @Json(name = "call_id") val callId: String, + @Json(name = "version") val version: Int, + @Json(name = "answer") val answer: Answer +) { + + @JsonClass(generateAdapter = true) + data class Answer( + @Json(name = "type") val type: String, + @Json(name = "sdp") val sdp: String + ) + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt new file mode 100644 index 00000000..81f7d48f --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallCandidatesContent.kt @@ -0,0 +1,38 @@ +/* + * + * * Copyright 2019 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.matrix.android.api.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class CallCandidatesContent( + @Json(name = "call_id") val callId: String, + @Json(name = "version") val version: Int, + @Json(name = "candidates") val candidates: List = emptyList() +) { + + @JsonClass(generateAdapter = true) + data class Candidate( + @Json(name = "sdpMid") val sdpMid: String, + @Json(name = "sdpMLineIndex") val sdpMLineIndex: String, + @Json(name = "candidate") val candidate: String + ) + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallHangupContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallHangupContent.kt new file mode 100644 index 00000000..2b7f6acd --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallHangupContent.kt @@ -0,0 +1,28 @@ +/* + * + * * Copyright 2019 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.matrix.android.api.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class CallHangupContent( + @Json(name = "call_id") val callId: String, + @Json(name = "version") val version: Int +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt new file mode 100644 index 00000000..b47e7ba2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt @@ -0,0 +1,42 @@ +/* + * + * * Copyright 2019 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.matrix.android.api.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class CallInviteContent( + @Json(name = "call_id") val callId: String, + @Json(name = "version") val version: Int, + @Json(name = "lifetime") val lifetime: Int, + @Json(name = "offer") val offer: Offer +) { + + @JsonClass(generateAdapter = true) + data class Offer( + @Json(name = "type") val type: String, + @Json(name = "sdp") val sdp: String + ) { + companion object { + const val SDP_VIDEO = "m=video" + } + } + +} \ No newline at end of file From 9cc2cf8360855511efba0b9d36573b0729707bea Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 20 Feb 2019 16:14:12 +0100 Subject: [PATCH 4/5] Timeline: set empty item as fallback item --- .../RoomHistoryVisibilityItemFactory.kt | 4 ++-- .../timeline/TimelineEventController.kt | 2 +- .../detail/timeline/TimelineItemFactory.kt | 21 +++++++++++-------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt index e692b81d..91972af2 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/RoomHistoryVisibilityItemFactory.kt @@ -32,14 +32,14 @@ class RoomHistoryVisibilityItemFactory(private val stringProvider: StringProvide fun create(event: TimelineEvent): NoticeItem? { val roomMember = event.roomMember ?: return null - val noticeText = buildRoomMemberNotice(event.root, roomMember) ?: return null + val noticeText = buildNoticeText(event.root, roomMember) ?: return null return NoticeItem_() .noticeText(noticeText) .avatarUrl(roomMember.avatarUrl) .memberName(roomMember.displayName) } - private fun buildRoomMemberNotice(event: Event, roomMember: RoomMember): CharSequence? { + private fun buildNoticeText(event: Event, roomMember: RoomMember): CharSequence? { val content = event.content.toModel() ?: return null val formattedVisibility = when (content.historyVisibility) { RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared) diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index 373612c1..0d12ae8e 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -74,7 +74,7 @@ class TimelineEventController(private val roomId: String, val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() - timelineItemFactory.create(event, nextEvent, callback)?.also { + timelineItemFactory.create(event, nextEvent, callback).also { it.id(event.localId) it.setOnVisibilityStateChanged(TimelineEventVisibilityStateChangedListener(callback, event, currentPosition)) epoxyModels.add(it) diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt index 5909a01c..80ed553a 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineItemFactory.kt @@ -31,29 +31,32 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, fun create(event: TimelineEvent, nextEvent: TimelineEvent?, - callback: TimelineEventController.Callback?): RiotEpoxyModel<*>? { + callback: TimelineEventController.Callback?): RiotEpoxyModel<*> { - return try { + val computedModel = try { when (event.root.type) { EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, callback) EventType.STATE_ROOM_NAME -> roomNameItemFactory.create(event) EventType.STATE_ROOM_TOPIC -> roomTopicItemFactory.create(event) EventType.STATE_ROOM_MEMBER -> roomMemberItemFactory.create(event) EventType.STATE_HISTORY_VISIBILITY -> roomHistoryVisibilityItemFactory.create(event) + EventType.CALL_INVITE, EventType.CALL_HANGUP, EventType.CALL_ANSWER -> callItemFactory.create(event) - EventType.STATE_ROOM_CREATE, - EventType.STATE_ROOM_POWER_LEVELS, - EventType.STATE_ROOM_JOIN_RULES, - EventType.STATE_ROOM_GUEST_ACCESS, - EventType.CALL_CANDIDATES, - EventType.REDACTION -> EmptyItem_() - else -> defaultItemFactory.create(event) + + EventType.ENCRYPTED, + EventType.ENCRYPTION, + EventType.STATE_ROOM_THIRD_PARTY_INVITE, + EventType.STICKER, + EventType.STATE_ROOM_CREATE -> defaultItemFactory.create(event) + + else -> null } } catch (e: Exception) { defaultItemFactory.create(event, e) } + return computedModel ?: EmptyItem_() } } \ No newline at end of file From ca890e1ef473eaddcd251c0504dfc00b308d22e6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 20 Feb 2019 18:09:07 +0100 Subject: [PATCH 5/5] Room tag: let the tag order be anything to avoid breaking at the moment. --- .../android/api/session/room/model/tag/RoomTagContent.kt | 2 +- .../matrix/android/internal/session/sync/RoomTagHandler.kt | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTagContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTagContent.kt index a5f7650b..388f494d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTagContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/tag/RoomTagContent.kt @@ -21,5 +21,5 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class RoomTagContent( - @Json(name = "tags") val tags: Map> = emptyMap() + @Json(name = "tags") val tags: Map> = emptyMap() ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt index c3722ea6..90915b42 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomTagHandler.kt @@ -32,15 +32,16 @@ internal class RoomTagHandler { val tags = ArrayList() for (tagName in content.tags.keys) { val params = content.tags[tagName] - val tag = if (params != null) { - RoomTagEntity(tagName, params["order"]) + val order = params?.get("order") + val tag = if (order is Double) { + RoomTagEntity(tagName, order) } else { RoomTagEntity(tagName, null) } tags.add(tag) } val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() - ?: RoomSummaryEntity(roomId) + ?: RoomSummaryEntity(roomId) roomSummaryEntity.tags.clear() roomSummaryEntity.tags.addAll(tags)