mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 16:24:11 +00:00
Remove the "unflip" of the timeline when in voice over mode (#5835)
Keep the timeline as it is in voice over mode, and don't "unflip" it
This commit is contained in:
@@ -81,10 +81,10 @@ struct RoomScreen: View {
|
||||
TopBannerLayer(knockRequestsBanner, isVisible: context.viewState.shouldSeeKnockRequests)
|
||||
], footer: dateBadge)
|
||||
.safeAreaInset(edge: .top) {
|
||||
// When VoiceOver is enabled, the table view isn't reversed and the scroll gestures
|
||||
// don't trigger meaning the banner never hides itself and so the .overlay layout
|
||||
// above permanently obscures the top of the timeline. So whenever VoiceOver is
|
||||
// enabled we use a safe area inset to vertically stack it above the timeline.
|
||||
// When VoiceOver is enabled the scroll gestures don't trigger, so the banner never
|
||||
// hides itself and the .overlay layout above would permanently obscure the top of
|
||||
// the timeline. So whenever VoiceOver is enabled we use a safe area inset to
|
||||
// vertically stack it above the timeline instead.
|
||||
if context.viewState.shouldShowPinnedEventsBanner || context.viewState.isSharingLiveLocation, isVoiceOverEnabled {
|
||||
VStack(spacing: 0) {
|
||||
if context.viewState.shouldShowPinnedEventsBanner {
|
||||
|
||||
@@ -180,11 +180,6 @@ class TimelineTableViewController: UIViewController {
|
||||
/// Whether or not the view has been shown on screen yet.
|
||||
private var hasAppearedOnce = false
|
||||
|
||||
/// Value that determines if the table view is flipped or not according to the VoiceOver status.
|
||||
private var scaleY: CGFloat {
|
||||
UIAccessibility.isVoiceOverRunning ? 1 : -1
|
||||
}
|
||||
|
||||
init(coordinator: TimelineViewRepresentable.Coordinator,
|
||||
isScrolledToBottom: Binding<Bool>,
|
||||
isReadMarkerVisible: Binding<Bool>,
|
||||
@@ -208,9 +203,8 @@ class TimelineTableViewController: UIViewController {
|
||||
tableView.keyboardDismissMode = .onDrag
|
||||
tableView.backgroundColor = .compound.bgCanvasDefault
|
||||
|
||||
// The tableview should be flipped to display the newest items at the top
|
||||
// the only exception is VoiceOver, where we want to keep the latest item at the top as Android.
|
||||
tableView.transform = CGAffineTransform(scaleX: 1, y: scaleY)
|
||||
// The tableview is flipped to display the newest items at the bottom.
|
||||
tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
|
||||
view.addSubview(tableView)
|
||||
|
||||
// Prevents XCUITest from invoking the diffable dataSource's cellProvider
|
||||
@@ -256,15 +250,6 @@ class TimelineTableViewController: UIViewController {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Observe voice over status changes to flip the table view accordingly
|
||||
NotificationCenter.default.publisher(for: UIAccessibility.voiceOverStatusDidChangeNotification)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
tableView.transform = CGAffineTransform(scaleX: 1, y: scaleY)
|
||||
tableView.reloadData()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
configureDataSource()
|
||||
}
|
||||
|
||||
@@ -312,7 +297,7 @@ class TimelineTableViewController: UIViewController {
|
||||
.background(Color.clear)
|
||||
|
||||
// Flipping the cell can create some issues with cell resizing, so flip the content View
|
||||
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: scaleY)
|
||||
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)
|
||||
cell.accessibilityElements = [cell.contentView] // Ensure VoiceOver reads the content view only
|
||||
|
||||
return cell
|
||||
@@ -339,7 +324,7 @@ class TimelineTableViewController: UIViewController {
|
||||
.background(Color.clear)
|
||||
|
||||
// Flipping the cell can create some issues with cell resizing, so flip the content View
|
||||
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: scaleY)
|
||||
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
@@ -633,19 +618,16 @@ extension TimelineTableViewController {
|
||||
|
||||
/// Returns the timestamp of the newest visible timeline item.
|
||||
///
|
||||
/// The table view is flipped (unless VoiceOver is running), so the "newest"
|
||||
/// visible cell on screen is actually the *last* index path in `indexPathsForVisibleRows`
|
||||
/// when the table is flipped, or the *first* when it is not.
|
||||
/// The table view is flipped, so the "newest" visible cell on screen is
|
||||
/// actually the *last* index path in `indexPathsForVisibleRows`.
|
||||
private func newestVisibleDate() -> Date? {
|
||||
guard let visibleIndexPaths = tableView.indexPathsForVisibleRows,
|
||||
!visibleIndexPaths.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// In a flipped table view the last index path is the topmost item on screen;
|
||||
// when VoiceOver is active the table is not flipped so the first is topmost.
|
||||
let isFlipped = scaleY == -1
|
||||
let orderedPaths = isFlipped ? visibleIndexPaths.reversed() : visibleIndexPaths
|
||||
// In a flipped table view the last index path is the topmost item on screen.
|
||||
let orderedPaths = visibleIndexPaths.reversed()
|
||||
|
||||
// Walk from topmost downward and return the timestamp of the first item that has one.
|
||||
for indexPath in orderedPaths {
|
||||
|
||||
Reference in New Issue
Block a user