mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Delay rendering bottom timeline items when scrolled up and avoid content shifts
- builds on top of langleyd/timeline_defer_new_items - improve animations
This commit is contained in:
committed by
Stefan Ceriu
parent
beaf9a8dbf
commit
3c8daebfe1
@@ -80,6 +80,11 @@ struct RoomScreen: View {
|
||||
context.send(viewAction: .cancelSend(itemID: info.itemID))
|
||||
}
|
||||
}
|
||||
.onChange(of: context.isScrolledToBottom) { isScrolledToBottom in
|
||||
if isScrolledToBottom {
|
||||
context.send(viewAction: .scrolledToBottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var timeline: some View {
|
||||
@@ -94,7 +99,7 @@ struct RoomScreen: View {
|
||||
private var timelineSwitch: some View {
|
||||
if context.viewState.swiftUITimelineEnabled {
|
||||
TimelineView(viewState: context.viewState.timelineViewState,
|
||||
scrollToBottomButtonVisible: $context.scrollToBottomButtonVisible) {
|
||||
isScrolledToBottom: $context.isScrolledToBottom) {
|
||||
context.send(viewAction: .paginateBackwards)
|
||||
}
|
||||
} else {
|
||||
@@ -121,9 +126,9 @@ struct RoomScreen: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.opacity(context.scrollToBottomButtonVisible ? 1.0 : 0.0)
|
||||
.accessibilityHidden(!context.scrollToBottomButtonVisible)
|
||||
.animation(.elementDefault, value: context.scrollToBottomButtonVisible)
|
||||
.opacity(context.isScrolledToBottom ? 0.0 : 1.0)
|
||||
.accessibilityHidden(context.isScrolledToBottom)
|
||||
.animation(.elementDefault, value: context.isScrolledToBottom)
|
||||
}
|
||||
|
||||
private var messageComposer: some View {
|
||||
|
||||
@@ -54,8 +54,7 @@ struct TimelineItemPlainStylerView<Content: View>: View {
|
||||
Rectangle()
|
||||
.foregroundColor(.global.melon)
|
||||
.frame(width: 4.0)
|
||||
TimelineReplyView(placement: .timeline,
|
||||
timelineItemReplyDetails: replyDetails)
|
||||
TimelineReplyView(placement: .timeline, timelineItemReplyDetails: replyDetails)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class TimelineTableViewController: UIViewController {
|
||||
|
||||
var contextMenuActionProvider: (@MainActor (_ itemID: TimelineItemIdentifier) -> TimelineItemMenuActions?)?
|
||||
|
||||
@Binding private var scrollToBottomButtonVisible: Bool
|
||||
@Binding private var isScrolledToBottom: Bool
|
||||
|
||||
private var timelineItemsIDs: [String] {
|
||||
timelineItemsDictionary.keys.elements.reversed()
|
||||
@@ -90,11 +90,11 @@ class TimelineTableViewController: UIViewController {
|
||||
|
||||
init(coordinator: UITimelineView.Coordinator,
|
||||
timelineStyle: TimelineStyle,
|
||||
scrollToBottomButtonVisible: Binding<Bool>,
|
||||
isScrolledToBottom: Binding<Bool>,
|
||||
scrollToBottomPublisher: PassthroughSubject<Void, Never>) {
|
||||
self.coordinator = coordinator
|
||||
self.timelineStyle = timelineStyle
|
||||
_scrollToBottomButtonVisible = scrollToBottomButtonVisible
|
||||
_isScrolledToBottom = isScrolledToBottom
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
@@ -253,11 +253,11 @@ extension TimelineTableViewController: UITableViewDelegate {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
let scrollToBottomButtonVisible = scrollView.contentOffset.y > 0
|
||||
let isScrolledToBottom = scrollView.contentOffset.y <= 0
|
||||
|
||||
// Only update the binding on changes to avoid needlessly recomputing the hierarchy when scrolling.
|
||||
if self.scrollToBottomButtonVisible != scrollToBottomButtonVisible {
|
||||
self.scrollToBottomButtonVisible = scrollToBottomButtonVisible
|
||||
if self.isScrolledToBottom != isScrolledToBottom {
|
||||
self.isScrolledToBottom = isScrolledToBottom
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ struct UITimelineView: UIViewControllerRepresentable {
|
||||
func makeUIViewController(context: Context) -> TimelineTableViewController {
|
||||
let tableViewController = TimelineTableViewController(coordinator: context.coordinator,
|
||||
timelineStyle: timelineStyle,
|
||||
scrollToBottomButtonVisible: $viewModelContext.scrollToBottomButtonVisible,
|
||||
isScrolledToBottom: $viewModelContext.isScrolledToBottom,
|
||||
scrollToBottomPublisher: viewModelContext.viewState.timelineViewState.scrollToBottomPublisher)
|
||||
return tableViewController
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import SwiftUIIntrospect
|
||||
|
||||
struct TimelineView: View {
|
||||
let viewState: TimelineViewState
|
||||
@Binding var scrollToBottomButtonVisible: Bool
|
||||
@Binding var isScrolledToBottom: Bool
|
||||
let paginationAction: () -> Void
|
||||
|
||||
@Environment(\.timelineStyle) private var timelineStyle
|
||||
@@ -61,17 +61,17 @@ struct TimelineView: View {
|
||||
.scrollDismissesKeyboard(.immediately)
|
||||
}
|
||||
.overlay(scrollToBottomButton, alignment: .bottomTrailing)
|
||||
.animation(.elementDefault, value: viewState.timelineIDs)
|
||||
.onReceive(scrollViewAdapter.didScroll) { _ in
|
||||
guard let scrollView = scrollViewAdapter.scrollView else {
|
||||
return
|
||||
}
|
||||
let offset = scrollView.contentOffset.y + scrollView.contentInset.top
|
||||
|
||||
// We give it a bit of tollerance which solves the issue when of it being displayed when the keyboard appears
|
||||
let scrollToBottomButtonVisibleValue = offset > 5
|
||||
if scrollToBottomButtonVisibleValue != scrollToBottomButtonVisible {
|
||||
scrollToBottomButtonVisible = scrollToBottomButtonVisibleValue
|
||||
let isScrolledToBottom = offset <= 0
|
||||
|
||||
// Only update the binding on changes to avoid needlessly recomputing the hierarchy when scrolling.
|
||||
if self.isScrolledToBottom != isScrolledToBottom {
|
||||
self.isScrolledToBottom = isScrolledToBottom
|
||||
}
|
||||
|
||||
// Allows the scroll to top to work properly
|
||||
@@ -100,6 +100,7 @@ struct TimelineView: View {
|
||||
.scaleEffect(x: 1, y: -1)
|
||||
}
|
||||
}
|
||||
.animation(.elementDefault, value: viewState.itemViewStates)
|
||||
topPin
|
||||
}
|
||||
}
|
||||
@@ -138,9 +139,9 @@ struct TimelineView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.opacity(scrollToBottomButtonVisible ? 1.0 : 0.0)
|
||||
.accessibilityHidden(!scrollToBottomButtonVisible)
|
||||
.animation(.elementDefault, value: scrollToBottomButtonVisible)
|
||||
.opacity(isScrolledToBottom ? 0.0 : 1.0)
|
||||
.accessibilityHidden(isScrolledToBottom)
|
||||
.animation(.elementDefault, value: isScrolledToBottom)
|
||||
}
|
||||
|
||||
private func paginateBackwardsIfNeeded() {
|
||||
|
||||
Reference in New Issue
Block a user