SwiftUI timeline refactor + TimelineViewState decoupling (#1392)

* swiftUI conversion + scroll to bottom

* remove unused

* back pagination implemented, however when a lot of elements are in the scroll the perfomance diminishes not sure what may be causing it

* scroll adapter solution

* way better

* works but height animation in cells are broken

* code improvement

* everything implemented

* rebase fix

* fix

* doc

* fix test compilation

* code improvement and animation improvement

* code improvement

* code improvements

* tests updated.

* pr comments

* better identifiers

* fix

* some PR comments

* pr comments
This commit is contained in:
Mauro
2023-07-25 14:20:13 +02:00
committed by GitHub
parent 43dafda3ef
commit 7cf32ba37c
17 changed files with 284 additions and 480 deletions
@@ -16,17 +16,27 @@
import SwiftUI
struct RoomTimelineItemView: View {
@ObservedObject var viewModel: RoomTimelineItemViewModel
@EnvironmentObject private var context: RoomScreenViewModel.Context
let viewState: RoomTimelineItemViewState
var body: some View {
timelineView
.environment(\.timelineGroupStyle, viewModel.groupStyle)
.animation(.elementDefault, value: viewModel.type)
.animation(.elementDefault, value: viewModel.groupStyle)
.environmentObject(context)
.environment(\.timelineGroupStyle, viewState.groupStyle)
.onAppear {
context.send(viewAction: .itemAppeared(itemID: viewState.identifier))
}
.onDisappear {
context.send(viewAction: .itemDisappeared(itemID: viewState.identifier))
}
.environment(\.openURL, OpenURLAction { url in
context.send(viewAction: .linkClicked(url: url))
return .systemAction
})
}
@ViewBuilder private var timelineView: some View {
switch viewModel.type {
switch viewState.type {
case .text(let item):
TextRoomTimelineView(timelineItem: item)
case .separator(let item):
@@ -69,6 +79,6 @@ struct RoomTimelineItemView: View {
}
var timelineGroupStyle: TimelineGroupStyle {
viewModel.groupStyle
viewState.groupStyle
}
}
@@ -16,25 +16,18 @@
import Foundation
final class RoomTimelineItemViewModel: Identifiable, Equatable, ObservableObject {
static func == (lhs: RoomTimelineItemViewModel, rhs: RoomTimelineItemViewModel) -> Bool {
lhs.type == rhs.type && lhs.groupStyle == rhs.groupStyle
}
struct RoomTimelineItemViewState: Identifiable, Equatable {
let type: RoomTimelineItemType
let groupStyle: TimelineGroupStyle
@Published var type: RoomTimelineItemType
@Published var groupStyle: TimelineGroupStyle
var id: TimelineItemIdentifier {
/// Contains all the identification info of the item, `timelineID`, `eventID` and `transactionID`
var identifier: TimelineItemIdentifier {
type.id
}
convenience init(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) {
self.init(type: .init(item: item), groupStyle: groupStyle)
}
init(type: RoomTimelineItemType, groupStyle: TimelineGroupStyle) {
self.type = type
self.groupStyle = groupStyle
/// The `timelineID` of the item, used for the timeline view level identification, do not use for any business logic use `identifier` instead
var id: String {
identifier.timelineID
}
var isReactable: Bool {
@@ -42,6 +35,12 @@ final class RoomTimelineItemViewModel: Identifiable, Equatable, ObservableObject
}
}
extension RoomTimelineItemViewState {
init(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) {
self.init(type: .init(item: item), groupStyle: groupStyle)
}
}
enum RoomTimelineItemType: Equatable {
case text(TextRoomTimelineItem)
case separator(SeparatorRoomTimelineItem)