element-x-ios/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift

187 lines
7.9 KiB
Swift

//
// 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
enum RoomTimelineViewProvider: Identifiable, Hashable {
case text(TextRoomTimelineItem, TimelineGroupStyle)
case separator(SeparatorRoomTimelineItem, TimelineGroupStyle)
case image(ImageRoomTimelineItem, TimelineGroupStyle)
case video(VideoRoomTimelineItem, TimelineGroupStyle)
case audio(AudioRoomTimelineItem, TimelineGroupStyle)
case file(FileRoomTimelineItem, TimelineGroupStyle)
case emote(EmoteRoomTimelineItem, TimelineGroupStyle)
case notice(NoticeRoomTimelineItem, TimelineGroupStyle)
case redacted(RedactedRoomTimelineItem, TimelineGroupStyle)
case encrypted(EncryptedRoomTimelineItem, TimelineGroupStyle)
case readMarker(ReadMarkerRoomTimelineItem, TimelineGroupStyle)
case paginationIndicator(PaginationIndicatorRoomTimelineItem, TimelineGroupStyle)
case sticker(StickerRoomTimelineItem, TimelineGroupStyle)
case unsupported(UnsupportedRoomTimelineItem, TimelineGroupStyle)
case timelineStart(TimelineStartRoomTimelineItem, TimelineGroupStyle)
case state(StateRoomTimelineItem, TimelineGroupStyle)
case group(CollapsibleTimelineItem, TimelineGroupStyle)
// swiftlint:disable:next cyclomatic_complexity
init(timelineItem: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) {
switch timelineItem {
case let item as TextRoomTimelineItem:
self = .text(item, groupStyle)
case let item as ImageRoomTimelineItem:
self = .image(item, groupStyle)
case let item as VideoRoomTimelineItem:
self = .video(item, groupStyle)
case let item as AudioRoomTimelineItem:
self = .audio(item, groupStyle)
case let item as FileRoomTimelineItem:
self = .file(item, groupStyle)
case let item as SeparatorRoomTimelineItem:
self = .separator(item, groupStyle)
case let item as NoticeRoomTimelineItem:
self = .notice(item, groupStyle)
case let item as EmoteRoomTimelineItem:
self = .emote(item, groupStyle)
case let item as RedactedRoomTimelineItem:
self = .redacted(item, groupStyle)
case let item as EncryptedRoomTimelineItem:
self = .encrypted(item, groupStyle)
case let item as ReadMarkerRoomTimelineItem:
self = .readMarker(item, groupStyle)
case let item as PaginationIndicatorRoomTimelineItem:
self = .paginationIndicator(item, groupStyle)
case let item as StickerRoomTimelineItem:
self = .sticker(item, groupStyle)
case let item as UnsupportedRoomTimelineItem:
self = .unsupported(item, groupStyle)
case let item as TimelineStartRoomTimelineItem:
self = .timelineStart(item, groupStyle)
case let item as StateRoomTimelineItem:
self = .state(item, groupStyle)
case let item as CollapsibleTimelineItem:
self = .group(item, groupStyle)
default:
fatalError("Unknown timeline item")
}
}
var id: String {
switch self {
case .text(let item as RoomTimelineItemProtocol, _),
.separator(let item as RoomTimelineItemProtocol, _),
.image(let item as RoomTimelineItemProtocol, _),
.video(let item as RoomTimelineItemProtocol, _),
.audio(let item as RoomTimelineItemProtocol, _),
.file(let item as RoomTimelineItemProtocol, _),
.emote(let item as RoomTimelineItemProtocol, _),
.notice(let item as RoomTimelineItemProtocol, _),
.redacted(let item as RoomTimelineItemProtocol, _),
.encrypted(let item as RoomTimelineItemProtocol, _),
.readMarker(let item as RoomTimelineItemProtocol, _),
.paginationIndicator(let item as RoomTimelineItemProtocol, _),
.sticker(let item as RoomTimelineItemProtocol, _),
.unsupported(let item as RoomTimelineItemProtocol, _),
.timelineStart(let item as RoomTimelineItemProtocol, _),
.state(let item as RoomTimelineItemProtocol, _),
.group(let item as RoomTimelineItemProtocol, _):
return item.id
}
}
/// Whether or not it is possible to send a reaction to this timeline item.
var isReactable: Bool {
switch self {
case .text, .image, .video, .audio, .file, .emote, .notice, .sticker:
return true
case .redacted, .encrypted, .unsupported, .state: // Event based items that aren't reactable
return false
case .timelineStart, .separator, .readMarker, .paginationIndicator: // Virtual items are never reactable
return false
case .group:
return false
}
}
}
extension RoomTimelineViewProvider: View {
var body: some View {
timelineView
.timelineGroupStyle(timelineGroupStyle)
}
@ViewBuilder private var timelineView: some View {
switch self {
case .text(let item, _):
TextRoomTimelineView(timelineItem: item)
case .separator(let item, _):
SeparatorRoomTimelineView(timelineItem: item)
case .image(let item, _):
ImageRoomTimelineView(timelineItem: item)
case .video(let item, _):
VideoRoomTimelineView(timelineItem: item)
case .audio(let item, _):
AudioRoomTimelineView(timelineItem: item)
case .file(let item, _):
FileRoomTimelineView(timelineItem: item)
case .emote(let item, _):
EmoteRoomTimelineView(timelineItem: item)
case .notice(let item, _):
NoticeRoomTimelineView(timelineItem: item)
case .redacted(let item, _):
RedactedRoomTimelineView(timelineItem: item)
case .encrypted(let item, _):
EncryptedRoomTimelineView(timelineItem: item)
case .readMarker(let item, _):
ReadMarkerRoomTimelineView(timelineItem: item)
case .paginationIndicator(let item, _):
PaginationIndicatorRoomTimelineView(timelineItem: item)
case .sticker(let item, _):
StickerRoomTimelineView(timelineItem: item)
case .unsupported(let item, _):
UnsupportedRoomTimelineView(timelineItem: item)
case .timelineStart(let item, _):
TimelineStartRoomTimelineView(timelineItem: item)
case .state(let item, _):
StateRoomTimelineView(timelineItem: item)
case .group(let item, _):
CollapsibleRoomTimelineView(timelineItem: item)
}
}
var timelineGroupStyle: TimelineGroupStyle {
switch self {
case .text(_, let groupStyle),
.separator(_, let groupStyle),
.image(_, let groupStyle),
.video(_, let groupStyle),
.audio(_, let groupStyle),
.file(_, let groupStyle),
.emote(_, let groupStyle),
.notice(_, let groupStyle),
.redacted(_, let groupStyle),
.encrypted(_, let groupStyle),
.readMarker(_, let groupStyle),
.paginationIndicator(_, let groupStyle),
.sticker(_, let groupStyle),
.unsupported(_, let groupStyle),
.timelineStart(_, let groupStyle),
.state(_, let groupStyle),
.group(_, let groupStyle):
return groupStyle
}
}
}