Further design updates to the timeline. (#524)

- Decryption banner on the timeline
- Bubble colours
- Background insets
- Multiline composer corner radius
- Read marker
- GIF indicator
- Reactions shape
- Use RoomTimelineViewLabelStyle everywhere possible
- Only set a line limit on reply quotes, allow all the lines for regular quotes.
- Message label icons
- Yes/No button casing
- Make sender profiles immutable.
- Enable copy link and invite buttons.
- Fix layout loop detecting multiline composer text.
- Add animation to the encryption banner.
This commit is contained in:
Doug
2023-02-03 14:09:48 +00:00
committed by GitHub
parent 183cc88114
commit 2aaeb576d2
52 changed files with 379 additions and 166 deletions
@@ -78,9 +78,9 @@ enum RoomTimelineItemFixtures {
TextRoomTimelineItem(id: UUID().uuidString,
text: "",
attributedComponents: [
AttributedStringBuilderComponent(attributedString: "Hol' up", isBlockquote: false),
AttributedStringBuilderComponent(attributedString: "New home office set up!", isBlockquote: true),
AttributedStringBuilderComponent(attributedString: "That's amazing! Congrats 🥳", isBlockquote: false)
AttributedStringBuilderComponent(attributedString: "Hol' up", isBlockquote: false, isReply: false),
AttributedStringBuilderComponent(attributedString: "New home office set up!", isBlockquote: true, isReply: false),
AttributedStringBuilderComponent(attributedString: "That's amazing! Congrats 🥳", isBlockquote: false, isReply: false)
],
timestamp: "5 PM",
groupState: .single,
@@ -218,11 +218,12 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
updateTimelineItems()
}
// swiftlint:disable:next cyclomatic_complexity
// swiftlint:disable:next cyclomatic_complexity function_body_length
private func updateTimelineItems() {
var newTimelineItems = [RoomTimelineItemProtocol]()
var canBackPaginate = true
var isBackPaginating = false
var hasEncryptedItems = false
var createdIdentifiers = [String: Bool]()
@@ -243,6 +244,9 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
if createdIdentifiers[timelineItem.id] == nil {
newTimelineItems.append(timelineItem)
createdIdentifiers[timelineItem.id] = true
if timelineItem is EncryptedRoomTimelineItem {
hasEncryptedItems = true
}
} else {
MXLog.error("Found duplicated timeline item, ignoring")
}
@@ -280,6 +284,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
callbacks.send(.updatedTimelineItems)
callbacks.send(.canBackPaginate(canBackPaginate))
callbacks.send(.isBackPaginating(isBackPaginating))
callbacks.send(.hasEncryptedItems(hasEncryptedItems))
}
private func computeGroupState(for itemProxy: TimelineItemProxy,
@@ -23,6 +23,7 @@ enum RoomTimelineControllerCallback {
case updatedTimelineItem(_ itemId: String)
case canBackPaginate(Bool)
case isBackPaginating(Bool)
case hasEncryptedItems(Bool)
}
enum RoomTimelineControllerAction {
@@ -17,6 +17,7 @@
import CoreGraphics
import Foundation
import MatrixRustSDK
import UniformTypeIdentifiers
/// A protocol that contains the base `m.room.message` event content properties.
/// The `CustomStringConvertible` conformance is to redact specific properties from the logs.
@@ -95,6 +96,10 @@ extension MessageTimelineItem where Content == MatrixRustSDK.ImageMessageContent
var blurhash: String? {
content.info?.blurhash
}
var type: UTType? {
content.info?.mimetype.flatMap { UTType(mimeType: $0) }
}
}
extension MatrixRustSDK.VideoMessageContent: MessageContentProtocol { }
@@ -16,11 +16,14 @@
import UIKit
#warning("This could be replaced by RoomMemberProxy if Rust includes a RoomMember.")
struct TimelineItemSender: Identifiable, Hashable {
let id: String
let displayName: String?
let avatarURL: URL?
// Lazy loaded properties, displayName and avatarURL will be come lets.
var displayName: String?
var avatarURL: URL?
init(id: String, displayName: String? = nil, avatarURL: URL? = nil) {
self.id = id
self.displayName = displayName
self.avatarURL = avatarURL
}
}
@@ -41,7 +41,7 @@ protocol EventBasedTimelineItemProtocol: RoomTimelineItemProtocol {
var isOutgoing: Bool { get }
var isEditable: Bool { get }
var sender: TimelineItemSender { get set }
var sender: TimelineItemSender { get }
var properties: RoomTimelineItemProperties { get }
}
@@ -25,7 +25,7 @@ struct EmoteRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hash
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -24,7 +24,7 @@ struct FileRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hasha
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
let source: MediaSourceProxy?
let thumbnailSource: MediaSourceProxy?
@@ -15,6 +15,7 @@
//
import UIKit
import UniformTypeIdentifiers
struct ImageRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hashable {
let id: String
@@ -24,7 +25,7 @@ struct ImageRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hash
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
let source: MediaSourceProxy?
var cachedFileURL: URL?
@@ -33,6 +34,7 @@ struct ImageRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hash
var height: CGFloat?
var aspectRatio: CGFloat?
var blurhash: String?
var type: UTType?
var properties = RoomTimelineItemProperties()
}
@@ -25,7 +25,7 @@ struct NoticeRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Has
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -25,7 +25,7 @@ struct TextRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hasha
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -24,7 +24,7 @@ struct VideoRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hash
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
let duration: UInt64
let source: MediaSourceProxy?
@@ -31,7 +31,7 @@ struct EncryptedRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable,
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -25,7 +25,7 @@ struct RedactedRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, H
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -24,7 +24,7 @@ struct StateRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Hash
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -24,7 +24,7 @@ struct StickerRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Ha
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
let imageURL: URL
@@ -28,7 +28,7 @@ struct UnsupportedRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable
let isOutgoing: Bool
let isEditable: Bool
var sender: TimelineItemSender
let sender: TimelineItemSender
var properties = RoomTimelineItemProperties()
}
@@ -237,6 +237,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
height: message.height,
aspectRatio: aspectRatio,
blurhash: message.blurhash,
type: message.type,
properties: RoomTimelineItemProperties(isEdited: message.isEdited,
reactions: aggregateReactions(eventItemProxy.reactions),
deliveryStatus: eventItemProxy.deliveryStatus))