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
@@ -29,6 +29,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
private let timelineController: RoomTimelineControllerProtocol
private let timelineViewFactory: RoomTimelineViewFactoryProtocol
// swiftlint:disable:next cyclomatic_complexity
init(timelineController: RoomTimelineControllerProtocol,
timelineViewFactory: RoomTimelineViewFactoryProtocol,
mediaProvider: MediaProviderProtocol,
@@ -66,6 +67,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
if self.state.isBackPaginating != isBackPaginating {
self.state.isBackPaginating = isBackPaginating
}
case .hasEncryptedItems(let hasEncryptedItems):
if self.state.showEncryptionBanner != hasEncryptedItems {
self.state.showEncryptionBanner = hasEncryptedItems
}
}
}
.store(in: &cancellables)
@@ -113,6 +118,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
state.bindings.composerText = ""
case .markRoomAsRead:
await markRoomAsRead()
case .retryDecryption:
retryDecryption()
case .contextMenuAction(let itemID, let action):
processContentMenuAction(action, itemID: itemID)
}
@@ -182,6 +189,19 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
}
/// Retry decrypting any encrypted items in the timeline.
private func retryDecryption() {
Task {
let firstEncryptedItem = state.items.first { $0.sessionID != nil }
if let sessionID = firstEncryptedItem?.sessionID {
// Request for the first encrypted item to be decrypted as the SDK
// will continue to decrypt any following items automatically.
await timelineController.retryDecryption(for: sessionID)
}
}
}
private func displayError(_ type: RoomScreenErrorType) {
switch type {
case .alert(let message):
@@ -224,12 +244,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
actions.append(.redact)
}
var debugActions: [TimelineItemContextMenuAction] = [.viewSource]
if let item = timelineItem as? EncryptedRoomTimelineItem,
case let .megolmV1AesSha2(sessionId) = item.encryptionType {
debugActions.append(.retryDecryption(sessionId: sessionId))
}
let debugActions: [TimelineItemContextMenuAction] = [.viewSource]
return .init(actions: actions, debugActions: debugActions)
}
@@ -271,10 +286,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
let debugDescription = timelineController.debugDescription(for: item.id)
MXLog.info(debugDescription)
state.bindings.debugInfo = .init(title: "Timeline item", content: debugDescription)
case .retryDecryption(let sessionId):
Task {
await timelineController.retryDecryption(for: sessionId)
}
}
if action.switchToDefaultComposer {
@@ -291,3 +302,14 @@ extension RoomScreenViewModel {
mediaProvider: MockMediaProvider(),
roomName: "Preview room")
}
private extension RoomTimelineViewProvider {
/// The item's session ID if it was unable to decrypt and uses megolm.
/// This will be nil for items that have already been decrypted.
var sessionID: String? {
guard case let .encrypted(item) = self,
case let .megolmV1AesSha2(sessionID) = item.encryptionType
else { return nil }
return sessionID
}
}