From 4996137006a69381c56a2d8f7c382610b7febf30 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 19 Sep 2024 11:03:26 +0100 Subject: [PATCH] Fix various flakey tests. --- .../RoomScreen/View/SwipeRightAction.swift | 86 +++++++++++-------- .../Screens/Timeline/TimelineViewModel.swift | 1 + .../roomLayoutBottom-0-iPhone-16-en-GB.UI.png | 4 +- .../roomLayoutBottom-1-iPhone-16-en-GB.UI.png | 4 +- ...omLayoutHighlight-0-iPhone-16-en-GB.UI.png | 4 +- .../roomLayoutTop-iPhone-16-en-GB.UI.png | 4 +- .../roomPlainNoAvatar-iPhone-16-en-GB.UI.png | 4 +- .../roomSmallTimeline-iPhone-16-en-GB.UI.png | 4 +- ...gAndSmallPagination-iPhone-16-en-GB.UI.png | 4 +- ...lineLargePagination-iPhone-16-en-GB.UI.png | 4 +- ...ineWithReadReceipts-iPhone-16-en-GB.UI.png | 4 +- ...mWithDisclosedPolls-iPhone-16-en-GB.UI.png | 4 +- ...omWithOutgoingPolls-iPhone-16-en-GB.UI.png | 4 +- ...ithUndisclosedPolls-iPhone-16-en-GB.UI.png | 4 +- ...userSessionScreen-1-iPhone-16-en-GB.UI.png | 4 +- .../Sources/TimelineViewModelTests.swift | 14 ++- 16 files changed, 87 insertions(+), 66 deletions(-) diff --git a/ElementX/Sources/Screens/RoomScreen/View/SwipeRightAction.swift b/ElementX/Sources/Screens/RoomScreen/View/SwipeRightAction.swift index 2c4a8eed0..ad5ce5806 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/SwipeRightAction.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/SwipeRightAction.swift @@ -31,42 +31,7 @@ struct SwipeRightAction: ViewModifier { content .offset(x: xOffset, y: 0.0) .animation(.interactiveSpring().speed(0.5), value: xOffset) - .gesture(DragGesture() - .updating($dragGestureActive) { _, state, _ in - // Available actions should be computed on the fly so we use a gesture state change - // to ask whether the move should be started or not. - state = true - } - .onChanged { value in - guard canStartAction else { - return - } - - // We want to add a spring like behavior to the drag in which the view - // moves slower the more it's dragged. We use a circular easing function - // to generate those values up to the `swipeThreshold` - // The final translation will be between 0 and `swipeThreshold` with the action being enabled from - // `actionThreshold` onwards - let screenWidthNormalisedTranslation = max(0.0, min(value.translation.width, swipeThreshold)) / swipeThreshold - let easedTranslation = circularEaseOut(screenWidthNormalisedTranslation) - xOffset = easedTranslation * xOffsetThreshold - - if xOffset > actionThreshold { - if !hasReachedActionThreshold { - feedbackGenerator.impactOccurred() - hasReachedActionThreshold = true - } - } else { - hasReachedActionThreshold = false - } - } - .onEnded { _ in - if xOffset > actionThreshold { - action() - } - - xOffset = 0.0 - }) + .simultaneousGesture(gesture) .onChange(of: dragGestureActive) { value in if value == true { if shouldStartAction() { @@ -86,6 +51,55 @@ struct SwipeRightAction: ViewModifier { } } + private var gesture: some Gesture { + DragGesture() + .updating($dragGestureActive) { _, state, _ in + // Available actions should be computed on the fly so we use a gesture state change + // to ask whether the move should be started or not. + state = true + } + .onChanged { value in + guard canStartAction, value.translation.width > value.translation.height else { + return + } + + // Due to https://forums.developer.apple.com/forums/thread/760035 we had to make + // the drag a simultaneous gesture otherwise it was impossible to scroll the timeline. + // Therefore we need to prevent the animation to run if the user is to scrolling vertically. + // It would be nice if we could somehow abort the gesture in this case. + let width: CGFloat = if value.translation.width > abs(value.translation.height) { + value.translation.width + } else { + 0.0 + } + + // We want to add a spring like behaviour to the drag in which the view + // moves slower the more it's dragged. We use a circular easing function + // to generate those values up to the `swipeThreshold` + // The final translation will be between 0 and `swipeThreshold` with the action being enabled from + // `actionThreshold` onwards + let screenWidthNormalisedTranslation = max(0.0, min(width, swipeThreshold)) / swipeThreshold + let easedTranslation = circularEaseOut(screenWidthNormalisedTranslation) + xOffset = easedTranslation * xOffsetThreshold + + if xOffset > actionThreshold { + if !hasReachedActionThreshold { + feedbackGenerator.impactOccurred() + hasReachedActionThreshold = true + } + } else { + hasReachedActionThreshold = false + } + } + .onEnded { _ in + if xOffset > actionThreshold { + action() + } + + xOffset = 0.0 + } + } + /// Used to compute the horizontal translation amount. /// The more it's dragged the less it moves on a circular ease out curve private func circularEaseOut(_ value: Double) -> Double { diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index 45081efd5..623b5d412 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -379,6 +379,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { return } await self?.updatePinnedEventIDs() + await self?.updatePermissions() } } .store(in: &cancellables) diff --git a/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-0-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-0-iPhone-16-en-GB.UI.png index 4a3662487..612652406 100644 --- a/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-0-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-0-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3f1793388cf6ef7f41c06ee75bacf8666691bc58dbfc3fa0cfaf5ef6d605923 -size 334552 +oid sha256:9f2b1bb7cd121631f9064509e6d7be090abd62c5a4afb09d083ab0b33d67a355 +size 329861 diff --git a/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-1-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-1-iPhone-16-en-GB.UI.png index 1ede34819..d845bb217 100644 --- a/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-1-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomLayoutBottom-1-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f19d1195da5c2fffa2ed4da45983e2d4734078ffc42b1078adb4fdbfa2be1c9 -size 319244 +oid sha256:0805c9072d8de90ff269e80be6c245d1bff4a0f5dc143d19bfaf59a05b170148 +size 317722 diff --git a/UITests/Sources/__Snapshots__/Application/roomLayoutHighlight-0-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomLayoutHighlight-0-iPhone-16-en-GB.UI.png index cac2907ad..292642f97 100644 --- a/UITests/Sources/__Snapshots__/Application/roomLayoutHighlight-0-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomLayoutHighlight-0-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cf2b33540efccf9c5ad3a5d183bda468c4e79f760ecd3e99d4d7fb43eb49c2b -size 331768 +oid sha256:f5a0569910e56f38be84e6d14bc721d5ab09ac90229a46eccbadcf54b2b88eec +size 326819 diff --git a/UITests/Sources/__Snapshots__/Application/roomLayoutTop-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomLayoutTop-iPhone-16-en-GB.UI.png index 7c6ed1637..c78df95e3 100644 --- a/UITests/Sources/__Snapshots__/Application/roomLayoutTop-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomLayoutTop-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02ddb5960d8da733b7a732da13e92d59794df1828208f9d118694425b821cae8 -size 346141 +oid sha256:ecca3b6f3357d2e5868224b6005079c33543564d08f1b6c32c5b4cde291183eb +size 341217 diff --git a/UITests/Sources/__Snapshots__/Application/roomPlainNoAvatar-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomPlainNoAvatar-iPhone-16-en-GB.UI.png index 638a4dd88..ef5bf35dd 100644 --- a/UITests/Sources/__Snapshots__/Application/roomPlainNoAvatar-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomPlainNoAvatar-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:091843bb18a614544534f0eabd2970a5cd6f775e75591428bd3fed1ac9c74328 -size 374446 +oid sha256:5eb3e3ca8c28ba9f1e4fcd5b7dcf30d162a98ec3cf8539bb8e60ac8802928bf7 +size 369833 diff --git a/UITests/Sources/__Snapshots__/Application/roomSmallTimeline-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomSmallTimeline-iPhone-16-en-GB.UI.png index f85d5b598..5c51abfbc 100644 --- a/UITests/Sources/__Snapshots__/Application/roomSmallTimeline-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomSmallTimeline-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36b7bbbb3452a4f20b5790b84cb83adecbfcd02f8e9e325db06a22a7c6c74115 -size 185184 +oid sha256:1fd4349c47465504cae19187ac770f5f72a9ebd139d6635e88e4f780c3766a88 +size 180406 diff --git a/UITests/Sources/__Snapshots__/Application/roomSmallTimelineIncomingAndSmallPagination-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomSmallTimelineIncomingAndSmallPagination-iPhone-16-en-GB.UI.png index e2f23f481..9ad65331e 100644 --- a/UITests/Sources/__Snapshots__/Application/roomSmallTimelineIncomingAndSmallPagination-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomSmallTimelineIncomingAndSmallPagination-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1343835253f92915a5b2dad424653ac4d5f2452cb54c3d62725c24e97b08ca33 -size 221532 +oid sha256:b7816944b84404a010641d131a766b06a8bddab609204ebb58b9b8f13e94562e +size 216901 diff --git a/UITests/Sources/__Snapshots__/Application/roomSmallTimelineLargePagination-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomSmallTimelineLargePagination-iPhone-16-en-GB.UI.png index 357b69dea..26e12acc1 100644 --- a/UITests/Sources/__Snapshots__/Application/roomSmallTimelineLargePagination-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomSmallTimelineLargePagination-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b55a58018122218861fa16e640108743b174596da8a30912079dc2ed1f5961b -size 344558 +oid sha256:3a083dfcee55c1be624d228589a041712b8d8f5669bd167fefb92aa8e203a6a4 +size 342283 diff --git a/UITests/Sources/__Snapshots__/Application/roomSmallTimelineWithReadReceipts-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomSmallTimelineWithReadReceipts-iPhone-16-en-GB.UI.png index 292e7ff29..6db7ab36b 100644 --- a/UITests/Sources/__Snapshots__/Application/roomSmallTimelineWithReadReceipts-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomSmallTimelineWithReadReceipts-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81ecddd245e889c442f43fd429c86a72ec0a125b650f030e2548200e4e692529 -size 216998 +oid sha256:9d78cbc723080c15e1ae3e5ce518517ac329d11a77e959179c84d275411ed976 +size 212177 diff --git a/UITests/Sources/__Snapshots__/Application/roomWithDisclosedPolls-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomWithDisclosedPolls-iPhone-16-en-GB.UI.png index 98fce26d8..84e852be2 100644 --- a/UITests/Sources/__Snapshots__/Application/roomWithDisclosedPolls-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomWithDisclosedPolls-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4dc2896ad8f7837fb8e21078379d1d5534e23b87ec8ac8673e7c649ae92fab11 -size 291283 +oid sha256:21a4406c80a619c4a7f97b39200d565f8cb9d84f47ce4bb8bb847fa3de187c09 +size 286492 diff --git a/UITests/Sources/__Snapshots__/Application/roomWithOutgoingPolls-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomWithOutgoingPolls-iPhone-16-en-GB.UI.png index 4758b3d27..9016d3624 100644 --- a/UITests/Sources/__Snapshots__/Application/roomWithOutgoingPolls-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomWithOutgoingPolls-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:711fb928fd51daf4148823c7d8ea7622169d7dfc71ef275a6f62683923aff7e5 -size 233789 +oid sha256:b8d92e74b63fd664d19b8757336b32fe6b01fe7301a30ea591eee0e98e8a99e7 +size 228856 diff --git a/UITests/Sources/__Snapshots__/Application/roomWithUndisclosedPolls-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/roomWithUndisclosedPolls-iPhone-16-en-GB.UI.png index 2e411ab93..2d5830db6 100644 --- a/UITests/Sources/__Snapshots__/Application/roomWithUndisclosedPolls-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/roomWithUndisclosedPolls-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d04f489f65c0269b1020b311808833f47a9600a727fef9aa8f0eb63881fe537 -size 287557 +oid sha256:4fce73fbf4e5c70b18fe8cd4c4d0ffbb2507c8da30a34d8eaa5d16513343e6e0 +size 282805 diff --git a/UITests/Sources/__Snapshots__/Application/userSessionScreen-1-iPhone-16-en-GB.UI.png b/UITests/Sources/__Snapshots__/Application/userSessionScreen-1-iPhone-16-en-GB.UI.png index cd123e6a5..1fa07f5f4 100644 --- a/UITests/Sources/__Snapshots__/Application/userSessionScreen-1-iPhone-16-en-GB.UI.png +++ b/UITests/Sources/__Snapshots__/Application/userSessionScreen-1-iPhone-16-en-GB.UI.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9ade4638d6436a04240b6695665eff1e302783bd1090715664e52040ace6d24 -size 298036 +oid sha256:672046d4289a23075b82789d5fca2b6b4f1cab3b75147cd2a5eec5d5dd79c398 +size 299984 diff --git a/UnitTests/Sources/TimelineViewModelTests.swift b/UnitTests/Sources/TimelineViewModelTests.swift index c4434c8f2..9876a7cad 100644 --- a/UnitTests/Sources/TimelineViewModelTests.swift +++ b/UnitTests/Sources/TimelineViewModelTests.swift @@ -380,10 +380,13 @@ class TimelineViewModelTests: XCTestCase { func testPinnedEvents() async throws { ServiceLocator.shared.settings.pinningEnabled = true + + // Note: We need to start the test with a non-default value so we know the view model has finished the Task. let roomProxyMock = JoinedRoomProxyMock(.init(name: "", pinnedEventIDs: .init(["test1"]))) let actionsSubject = PassthroughSubject() roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher() + let viewModel = TimelineViewModel(roomProxy: roomProxyMock, timelineController: MockRoomTimelineController(), mediaProvider: MockMediaProvider(), @@ -409,9 +412,12 @@ class TimelineViewModelTests: XCTestCase { func testCanUserPinEvents() async throws { ServiceLocator.shared.settings.pinningEnabled = true - let roomProxyMock = JoinedRoomProxyMock(.init(name: "", canUserPin: false)) + + // Note: We need to start the test with the non-default value so we know the view model has finished the Task. + let roomProxyMock = JoinedRoomProxyMock(.init(name: "", canUserPin: true)) let actionsSubject = PassthroughSubject() roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher() + let viewModel = TimelineViewModel(roomProxy: roomProxyMock, timelineController: MockRoomTimelineController(), mediaProvider: MockMediaProvider(), @@ -423,13 +429,13 @@ class TimelineViewModelTests: XCTestCase { analyticsService: ServiceLocator.shared.analytics) var deferred = deferFulfillment(viewModel.context.$viewState) { value in - !value.canCurrentUserPin + value.canCurrentUserPin } try await deferred.fulfill() - roomProxyMock.canUserPinOrUnpinUserIDReturnValue = .success(true) + roomProxyMock.canUserPinOrUnpinUserIDReturnValue = .success(false) deferred = deferFulfillment(viewModel.context.$viewState) { value in - value.canCurrentUserPin + !value.canCurrentUserPin } actionsSubject.send(.roomInfoUpdate) try await deferred.fulfill()