Redacted events in timeline (#199)

* Add redacted timeline item and view

* Use isOwn and isRedacted properties from sdk

* Build redacted items in factory

* Include redacted events in timeline

* Add changelog

* Fix unit tests
This commit is contained in:
ismailgulek
2022-09-21 14:13:04 +03:00
committed by GitHub
parent 5ebe923991
commit 40e878cbb1
10 changed files with 145 additions and 4 deletions
@@ -0,0 +1,59 @@
//
// Copyright 2022 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.
//
import Foundation
import SwiftUI
struct RedactedRoomTimelineView: View {
let timelineItem: RedactedRoomTimelineItem
var body: some View {
TimelineStyler(timelineItem: timelineItem) {
HStack {
Image(systemName: "trash")
FormattedBodyText(isOutgoing: timelineItem.isOutgoing, text: timelineItem.text)
}
}
.id(timelineItem.id)
}
}
struct RedactedRoomTimelineView_Previews: PreviewProvider {
static var previews: some View {
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@ViewBuilder
static var body: some View {
VStack(alignment: .leading, spacing: 20.0) {
RedactedRoomTimelineView(timelineItem: itemWith(text: ElementL10n.eventRedacted,
timestamp: "Later",
senderId: "Anne"))
}
.padding()
}
private static func itemWith(text: String, timestamp: String, senderId: String) -> RedactedRoomTimelineItem {
RedactedRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: true,
inGroupState: .single,
isOutgoing: false,
senderId: senderId)
}
}
@@ -146,7 +146,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
switch item {
case .event(let eventItem):
guard eventItem.isMessage else { break } // To be handled in the future
guard eventItem.isMessage || eventItem.isRedacted else { break } // To be handled in the future
newTimelineItems.append(await timelineItemFactory.buildTimelineItemFor(eventItem: eventItem,
showSenderDetails: inGroupState.shouldShowSenderDetails,
@@ -70,6 +70,14 @@ struct EventTimelineItem {
var content: TimelineItemContent {
item.content()
}
var isRedacted: Bool {
content.isRedactedMessage()
}
var isOwn: Bool {
item.isOwn()
}
var sender: String {
item.sender()
@@ -0,0 +1,33 @@
//
// Copyright 2022 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.
//
import Foundation
import UIKit
struct RedactedRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Equatable {
let id: String
let text: String
let timestamp: String
let shouldShowSenderDetails: Bool
let inGroupState: TimelineItemInGroupState
let isOutgoing: Bool
let senderId: String
var senderDisplayName: String?
var senderAvatar: UIImage?
var properties = RoomTimelineItemProperties()
}
@@ -38,11 +38,16 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
func buildTimelineItemFor(eventItem: EventTimelineItem,
showSenderDetails: Bool,
inGroupState: TimelineItemInGroupState) async -> RoomTimelineItemProtocol {
guard let messageContent = eventItem.content.asMessage() else { fatalError("Must be a message for now.") }
let displayName = roomProxy.displayNameForUserId(eventItem.sender)
let avatarURL = roomProxy.avatarURLStringForUserId(eventItem.sender)
let avatarImage = mediaProvider.imageFromURLString(avatarURL, size: MediaProviderDefaultAvatarSize)
let isOutgoing = eventItem.sender == userID
let isOutgoing = eventItem.isOwn
if eventItem.isRedacted {
return buildRedactedTimelineItemFromEvent(eventItem, isOutgoing, showSenderDetails, inGroupState, displayName, avatarImage)
}
guard let messageContent = eventItem.content.asMessage() else { fatalError("Must be a message for now.") }
switch messageContent.msgtype() {
case .text(content: let content):
@@ -66,6 +71,24 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
// swiftformat:disable function_parameter_count
// swiftlint:disable function_parameter_count
private func buildRedactedTimelineItemFromEvent(_ event: EventTimelineItem,
_ isOutgoing: Bool,
_ showSenderDetails: Bool,
_ inGroupState: TimelineItemInGroupState,
_ displayName: String?,
_ avatarImage: UIImage?) -> RoomTimelineItemProtocol {
RedactedRoomTimelineItem(id: event.id,
text: ElementL10n.eventRedacted,
timestamp: event.originServerTs.formatted(date: .omitted, time: .shortened),
shouldShowSenderDetails: showSenderDetails,
inGroupState: inGroupState,
isOutgoing: isOutgoing,
senderId: event.sender,
senderDisplayName: displayName,
senderAvatar: avatarImage,
properties: RoomTimelineItemProperties())
}
private func buildFallbackTimelineItem(_ item: EventTimelineItem,
_ isOutgoing: Bool,
_ showSenderDetails: Bool,
@@ -29,6 +29,8 @@ struct RoomTimelineViewFactory: RoomTimelineViewFactoryProtocol {
return .notice(item)
case let item as EmoteRoomTimelineItem:
return .emote(item)
case let item as RedactedRoomTimelineItem:
return .redacted(item)
default:
fatalError("Unknown timeline item")
}
@@ -23,6 +23,7 @@ enum RoomTimelineViewProvider: Identifiable, Equatable {
case image(ImageRoomTimelineItem)
case emote(EmoteRoomTimelineItem)
case notice(NoticeRoomTimelineItem)
case redacted(RedactedRoomTimelineItem)
var id: String {
switch self {
@@ -36,6 +37,8 @@ enum RoomTimelineViewProvider: Identifiable, Equatable {
return item.id
case .notice(let item):
return item.id
case .redacted(let item):
return item.id
}
}
}
@@ -53,6 +56,8 @@ extension RoomTimelineViewProvider: View {
EmoteRoomTimelineView(timelineItem: item)
case .notice(let item):
NoticeRoomTimelineView(timelineItem: item)
case .redacted(let item):
RedactedRoomTimelineView(timelineItem: item)
}
}
}