mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Fixes #641 - Room previews failing to load because of incorrect sliding sync view ranges
This commit is contained in:
committed by
Stefan Ceriu
parent
0ed69d5649
commit
b564036b68
@@ -25,29 +25,38 @@ class ScrollViewAdapter: NSObject, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isScrolling = CurrentValueSubject<Bool, Never>(false)
|
let didScroll = PassthroughSubject<Void, Never>()
|
||||||
|
let isScrolling = CurrentValueSubject<Bool, Never>(false)
|
||||||
|
|
||||||
private func update(_ scrollView: UIScrollView) {
|
// MARK: - UIScrollViewDelegate
|
||||||
isScrolling.send(scrollView.isDragging || scrollView.isDecelerating)
|
|
||||||
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
|
didScroll.send(())
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||||
update(scrollView)
|
updateDidScroll(scrollView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||||
update(scrollView)
|
updateDidScroll(scrollView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
||||||
update(scrollView)
|
updateDidScroll(scrollView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||||
update(scrollView)
|
updateDidScroll(scrollView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
|
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
|
||||||
update(scrollView)
|
updateDidScroll(scrollView)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private func updateDidScroll(_ scrollView: UIScrollView) {
|
||||||
|
isScrolling.send(scrollView.isDragging || scrollView.isDecelerating)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,17 +23,8 @@ struct HomeScreen: View {
|
|||||||
|
|
||||||
@ObservedObject var context: HomeScreenViewModel.Context
|
@ObservedObject var context: HomeScreenViewModel.Context
|
||||||
|
|
||||||
@State private var isViewVisible = false
|
|
||||||
|
|
||||||
@State private var scrollViewAdapter = ScrollViewAdapter()
|
@State private var scrollViewAdapter = ScrollViewAdapter()
|
||||||
@State private var showingLogoutConfirmation = false
|
@State private var showingLogoutConfirmation = false
|
||||||
@State private var visibleItemIdentifiers = Set<String>() {
|
|
||||||
didSet {
|
|
||||||
if isViewVisible {
|
|
||||||
updateVisibleRange()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@@ -69,16 +60,6 @@ struct HomeScreen: View {
|
|||||||
HomeScreenRoomCell(room: room, context: context)
|
HomeScreenRoomCell(room: room, context: context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
|
||||||
// Ignore while filtering rooms
|
|
||||||
guard context.searchQuery.isEmpty else { return }
|
|
||||||
visibleItemIdentifiers.insert(room.id)
|
|
||||||
}
|
|
||||||
.onDisappear {
|
|
||||||
// Ignore while filtering rooms
|
|
||||||
guard context.searchQuery.isEmpty else { return }
|
|
||||||
visibleItemIdentifiers.remove(room.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.searchable(text: $context.searchQuery)
|
.searchable(text: $context.searchQuery)
|
||||||
@@ -86,18 +67,27 @@ struct HomeScreen: View {
|
|||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
|
||||||
isViewVisible = true
|
|
||||||
}
|
|
||||||
.onDisappear {
|
|
||||||
isViewVisible = false
|
|
||||||
}
|
|
||||||
.introspectScrollView { scrollView in
|
.introspectScrollView { scrollView in
|
||||||
guard scrollView != scrollViewAdapter.scrollView else { return }
|
guard scrollView != scrollViewAdapter.scrollView else { return }
|
||||||
scrollViewAdapter.scrollView = scrollView
|
scrollViewAdapter.scrollView = scrollView
|
||||||
}
|
}
|
||||||
.onReceive(scrollViewAdapter.isScrolling) { isScrolling in
|
.onReceive(scrollViewAdapter.didScroll) { _ in
|
||||||
if !isScrolling {
|
updateVisibleRange()
|
||||||
|
}
|
||||||
|
.onReceive(scrollViewAdapter.isScrolling) { _ in
|
||||||
|
updateVisibleRange()
|
||||||
|
}
|
||||||
|
.onChange(of: context.searchQuery) { searchQuery in
|
||||||
|
if searchQuery.isEmpty {
|
||||||
|
// Allow the view to update after changing the query
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
updateVisibleRange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: context.viewState.visibleRooms) { _ in
|
||||||
|
// Give the view a chance to update
|
||||||
|
DispatchQueue.main.async {
|
||||||
updateVisibleRange()
|
updateVisibleRange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,21 +215,22 @@ struct HomeScreen: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateVisibleRange() {
|
private func updateVisibleRange() {
|
||||||
let result = visibleItemIdentifiers.compactMap { itemIdentifier in
|
guard let scrollView = scrollViewAdapter.scrollView,
|
||||||
context.viewState.rooms.firstIndex { $0.id == itemIdentifier }
|
context.viewState.rooms.count > 0 else {
|
||||||
}.sorted()
|
|
||||||
|
|
||||||
guard !result.isEmpty else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let firstIndex = result.first, let lastIndex = result.last else {
|
let adjustedContentSize = max(scrollView.contentSize.height - scrollView.contentInset.top - scrollView.contentInset.bottom, scrollView.bounds.height)
|
||||||
return
|
let cellHeight = adjustedContentSize / Double(context.viewState.rooms.count)
|
||||||
}
|
|
||||||
|
|
||||||
|
let firstIndex = Int(max(0.0, scrollView.contentOffset.y + scrollView.contentInset.top) / cellHeight)
|
||||||
|
let lastIndex = Int(max(0.0, scrollView.contentOffset.y + scrollView.bounds.height) / cellHeight)
|
||||||
|
|
||||||
|
// Add some extra padding just to be on the safe side
|
||||||
let lowerBound = max(0, firstIndex - Constants.slidingWindowBoundsPadding)
|
let lowerBound = max(0, firstIndex - Constants.slidingWindowBoundsPadding)
|
||||||
let upperBound = min(Int(context.viewState.rooms.count), lastIndex + Constants.slidingWindowBoundsPadding)
|
let upperBound = min(Int(context.viewState.rooms.count), lastIndex + Constants.slidingWindowBoundsPadding)
|
||||||
|
|
||||||
|
// This will be deduped and throttled on the view model layer
|
||||||
context.send(viewAction: .updateVisibleItemRange(range: lowerBound..<upperBound, isScrolling: scrollViewAdapter.isScrolling.value))
|
context.send(viewAction: .updateVisibleItemRange(range: lowerBound..<upperBound, isScrolling: scrollViewAdapter.isScrolling.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Fixed room previews failing to load because of incorrect sliding sync view ranges
|
||||||
Reference in New Issue
Block a user