Files
letro-ios/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/HighlightedTimelineItemModifier.swift
Mauro 56eec826df Fix A11y tests (#5104)
* replace NavigationStack with ElementNavigationStack to allow the content to be rendered without a NavigationStack in a11y tests

* fix a11y tests

* update xcodeproject

* swiftformat fix

* use iOS 26.1 for CI

* use a wrapper to solve the issue for a11y tests

* ElementNavigationStack only uses the trick in DEBUG mode, and added a swiftlint rule to prevent the usage of NavigationStack
2026-02-13 16:45:58 +01:00

113 lines
5.4 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// Copyright 2025 Element Creations Ltd.
// Copyright 2024-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Compound
import SwiftUI
extension View {
func highlightedTimelineItem(_ isHighlighted: Bool) -> some View {
modifier(HighlightedTimelineItemModifier(isHighlighted: isHighlighted))
}
}
private struct HighlightedTimelineItemModifier: ViewModifier {
let isHighlighted: Bool
func body(content: Content) -> some View {
content
.padding(.top, isHighlighted ? 1 : 0)
.background {
if isHighlighted {
VStack(spacing: 0) {
Color.compound.gradientSubtleStop1
LinearGradient(gradient: .compound.subtle,
startPoint: .top,
endPoint: .bottom)
.frame(maxHeight: 200)
.layoutPriority(1)
}
.overlay(alignment: .top) {
Color.compound.borderAccentSubtle
.frame(height: 1)
}
}
}
}
}
// MARK: - Previews
// swiftlint:disable line_length blanket_disable_command
struct HighlightedTimelineItemModifier_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
ScrollView {
VStack(spacing: 16) {
Bubble(text: "Hello 👋")
.highlightedTimelineItem(true)
Bubble(text: "Not highlighted")
.highlightedTimelineItem(false)
// swiftlint:disable line_length
Bubble(text: """
Bacon ipsum dolor amet brisket bacon hamburger filet mignon ham hock, capicola meatloaf corned beef tongue. Ribeye filet mignon shoulder drumstick doner shank. Landjaeger shankle chislic brisket short loin pig. Frankfurter sirloin jerky bresaola tri-tip cow buffalo. Beef tongue shankle venison, sirloin boudin biltong ham hock corned beef. Sirloin shankle pork belly, strip steak pancetta brisket flank ribeye cow chislic. Pork ham landjaeger, pastrami beef sausage capicola meatball.
Cow brisket bresaola, burgdoggen cupim turducken sirloin andouille shankle sausage jerky chicken pig. Tail capicola landjaeger frankfurter. Kevin pancetta brisket spare ribs, sausage chuck tail pork. Ground round boudin chuck tri-tip corned beef. Pork belly ham bresaola tail, pork chop meatloaf biltong filet mignon strip steak ribeye boudin shoulder frankfurter.
""",
isOutgoing: true)
.highlightedTimelineItem(true)
// swiftlint:enable line_length
}
}
.previewDisplayName("Layout")
}
struct Bubble: View {
let text: String
var isOutgoing = false
var body: some View {
Text(text)
.padding(10)
.background(isOutgoing ? .compound._bgBubbleOutgoing : .compound._bgBubbleIncoming,
in: RoundedRectangle(cornerRadius: 12))
.padding(isOutgoing ? .leading : .trailing, 40)
.frame(maxWidth: .infinity, alignment: isOutgoing ? .trailing : .leading)
.padding(12)
}
}
}
/// A preview that allows quick testing of the highlight appearance across various timeline scenarios.
struct HighlightedTimelineItemTimeline_Previews: PreviewProvider {
static let roomProxyMock = JoinedRoomProxyMock(.init(name: "Preview room"))
static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock)
static let focussedEventID = "RoomTimelineItemFixtures.default.5"
static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock,
focussedEventID: focussedEventID,
timelineController: MockTimelineController(),
userSession: UserSessionMock(.init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
linkMetadataProvider: LinkMetadataProvider(),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
static var previews: some View {
ElementNavigationStack {
RoomScreen(context: roomViewModel.context,
timelineContext: timelineViewModel.context,
composerToolbar: ComposerToolbar.mock())
}
.previewDisplayName("Timeline")
}
}