Skip to content

Commit

Permalink
Fix various flakey tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
pixlwave committed Sep 23, 2024
1 parent d2d3b28 commit 4996137
Show file tree
Hide file tree
Showing 16 changed files with 87 additions and 66 deletions.
86 changes: 50 additions & 36 deletions ElementX/Sources/Screens/RoomScreen/View/SwipeRightAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,42 +31,7 @@ struct SwipeRightAction<Label: View>: 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() {
Expand All @@ -86,6 +51,55 @@ struct SwipeRightAction<Label: View>: 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 {
Expand Down
1 change: 1 addition & 0 deletions ElementX/Sources/Screens/Timeline/TimelineViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
return
}
await self?.updatePinnedEventIDs()
await self?.updatePermissions()
}
}
.store(in: &cancellables)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions UnitTests/Sources/TimelineViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<JoinedRoomProxyAction, Never>()
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()

let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
Expand All @@ -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<JoinedRoomProxyAction, Never>()
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()

let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
Expand All @@ -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()
Expand Down

0 comments on commit 4996137

Please sign in to comment.