mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Fix various flakey tests.
This commit is contained in:
parent
d2d3b28dc7
commit
4996137006
@ -31,23 +31,54 @@ struct SwipeRightAction<Label: View>: ViewModifier {
|
|||||||
content
|
content
|
||||||
.offset(x: xOffset, y: 0.0)
|
.offset(x: xOffset, y: 0.0)
|
||||||
.animation(.interactiveSpring().speed(0.5), value: xOffset)
|
.animation(.interactiveSpring().speed(0.5), value: xOffset)
|
||||||
.gesture(DragGesture()
|
.simultaneousGesture(gesture)
|
||||||
|
.onChange(of: dragGestureActive) { value in
|
||||||
|
if value == true {
|
||||||
|
if shouldStartAction() {
|
||||||
|
feedbackGenerator.prepare()
|
||||||
|
canStartAction = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.overlay(alignment: .leading) {
|
||||||
|
// We want the action icon to follow the view translation and gradually fade in
|
||||||
|
label()
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.frame(maxWidth: actionThreshold)
|
||||||
|
.opacity(xOffset / 50)
|
||||||
|
.animation(.interactiveSpring().speed(0.5), value: xOffset)
|
||||||
|
.offset(x: -actionThreshold + min(xOffset, actionThreshold), y: 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var gesture: some Gesture {
|
||||||
|
DragGesture()
|
||||||
.updating($dragGestureActive) { _, state, _ in
|
.updating($dragGestureActive) { _, state, _ in
|
||||||
// Available actions should be computed on the fly so we use a gesture state change
|
// 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.
|
// to ask whether the move should be started or not.
|
||||||
state = true
|
state = true
|
||||||
}
|
}
|
||||||
.onChanged { value in
|
.onChanged { value in
|
||||||
guard canStartAction else {
|
guard canStartAction, value.translation.width > value.translation.height else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to add a spring like behavior to the drag in which the view
|
// 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
|
// moves slower the more it's dragged. We use a circular easing function
|
||||||
// to generate those values up to the `swipeThreshold`
|
// to generate those values up to the `swipeThreshold`
|
||||||
// The final translation will be between 0 and `swipeThreshold` with the action being enabled from
|
// The final translation will be between 0 and `swipeThreshold` with the action being enabled from
|
||||||
// `actionThreshold` onwards
|
// `actionThreshold` onwards
|
||||||
let screenWidthNormalisedTranslation = max(0.0, min(value.translation.width, swipeThreshold)) / swipeThreshold
|
let screenWidthNormalisedTranslation = max(0.0, min(width, swipeThreshold)) / swipeThreshold
|
||||||
let easedTranslation = circularEaseOut(screenWidthNormalisedTranslation)
|
let easedTranslation = circularEaseOut(screenWidthNormalisedTranslation)
|
||||||
xOffset = easedTranslation * xOffsetThreshold
|
xOffset = easedTranslation * xOffsetThreshold
|
||||||
|
|
||||||
@ -66,23 +97,6 @@ struct SwipeRightAction<Label: View>: ViewModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
xOffset = 0.0
|
xOffset = 0.0
|
||||||
})
|
|
||||||
.onChange(of: dragGestureActive) { value in
|
|
||||||
if value == true {
|
|
||||||
if shouldStartAction() {
|
|
||||||
feedbackGenerator.prepare()
|
|
||||||
canStartAction = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.overlay(alignment: .leading) {
|
|
||||||
// We want the action icon to follow the view translation and gradually fade in
|
|
||||||
label()
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
.frame(maxWidth: actionThreshold)
|
|
||||||
.opacity(xOffset / 50)
|
|
||||||
.animation(.interactiveSpring().speed(0.5), value: xOffset)
|
|
||||||
.offset(x: -actionThreshold + min(xOffset, actionThreshold), y: 0.0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,6 +379,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
await self?.updatePinnedEventIDs()
|
await self?.updatePinnedEventIDs()
|
||||||
|
await self?.updatePermissions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutBottom-0-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutBottom-0-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutBottom-1-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutBottom-1-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutHighlight-0-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutHighlight-0-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutTop-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomLayoutTop-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomPlainNoAvatar-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomPlainNoAvatar-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomSmallTimeline-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomSmallTimeline-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomSmallTimelineLargePagination-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomSmallTimelineLargePagination-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomSmallTimelineWithReadReceipts-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomSmallTimelineWithReadReceipts-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomWithDisclosedPolls-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomWithDisclosedPolls-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomWithOutgoingPolls-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomWithOutgoingPolls-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/roomWithUndisclosedPolls-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/roomWithUndisclosedPolls-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/userSessionScreen-1-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/userSessionScreen-1-iPhone-16-en-GB.UI.png
(Stored with Git LFS)
Binary file not shown.
@ -380,10 +380,13 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
func testPinnedEvents() async throws {
|
func testPinnedEvents() async throws {
|
||||||
ServiceLocator.shared.settings.pinningEnabled = true
|
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: "",
|
let roomProxyMock = JoinedRoomProxyMock(.init(name: "",
|
||||||
pinnedEventIDs: .init(["test1"])))
|
pinnedEventIDs: .init(["test1"])))
|
||||||
let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
||||||
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()
|
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()
|
||||||
|
|
||||||
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
||||||
timelineController: MockRoomTimelineController(),
|
timelineController: MockRoomTimelineController(),
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
@ -409,9 +412,12 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
func testCanUserPinEvents() async throws {
|
func testCanUserPinEvents() async throws {
|
||||||
ServiceLocator.shared.settings.pinningEnabled = true
|
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>()
|
let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
||||||
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()
|
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()
|
||||||
|
|
||||||
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
||||||
timelineController: MockRoomTimelineController(),
|
timelineController: MockRoomTimelineController(),
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
@ -423,13 +429,13 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
analyticsService: ServiceLocator.shared.analytics)
|
analyticsService: ServiceLocator.shared.analytics)
|
||||||
|
|
||||||
var deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
var deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
||||||
!value.canCurrentUserPin
|
value.canCurrentUserPin
|
||||||
}
|
}
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
|
|
||||||
roomProxyMock.canUserPinOrUnpinUserIDReturnValue = .success(true)
|
roomProxyMock.canUserPinOrUnpinUserIDReturnValue = .success(false)
|
||||||
deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
||||||
value.canCurrentUserPin
|
!value.canCurrentUserPin
|
||||||
}
|
}
|
||||||
actionsSubject.send(.roomInfoUpdate)
|
actionsSubject.send(.roomInfoUpdate)
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user