Skip to content

Commit

Permalink
Move ListHeader to SpeziViews
Browse files Browse the repository at this point in the history
  • Loading branch information
Supereg committed Dec 15, 2024
1 parent 678f3cc commit d4cc1af
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions Sources/SpeziViews/SpeziViews.docc/SpeziViews.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Default layouts and utilities to automatically adapt your view layouts to dynami
- ``DynamicHStack``
- ``ListRow``
- ``DescriptionGridRow``
- ``ListHeader``

### Controls

Expand Down
105 changes: 105 additions & 0 deletions Sources/SpeziViews/Views/List/ListHeader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// This source file is part of the Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SwiftUI


/// Header view for Lists or Forms.
///
/// A header view that can be used in List or Form views.
public struct ListHeader<Image: View, Title: View, Instructions: View>: View {
private let image: Image
private let title: Title
private let instructions: Instructions


public var body: some View {
VStack {
VStack {
image
.foregroundColor(.accentColor)
.symbolRenderingMode(.multicolor)
.font(.custom("XXL", size: 50, relativeTo: .title))
.accessibilityHidden(true)
title
.accessibilityAddTraits(.isHeader)
.font(.title)
.bold()
.padding(.bottom, 4)
}
.accessibilityElement(children: .combine)
instructions
.padding([.leading, .trailing], 25)
}
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
}

/// Create a new list header.
/// - Parameters:
/// - image: The image view.
/// - title: The title view.
public init(@ViewBuilder image: () -> Image, @ViewBuilder title: () -> Title) where Instructions == EmptyView {
self.init(image: image, title: title) {
EmptyView()
}
}

Check warning on line 51 in Sources/SpeziViews/Views/List/ListHeader.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziViews/Views/List/ListHeader.swift#L47-L51

Added lines #L47 - L51 were not covered by tests

/// Create a new list header.
/// - Parameters:
/// - image: The image view.
/// - title: The title view.
/// - instructions: The instructions subheadline.
public init(@ViewBuilder image: () -> Image, @ViewBuilder title: () -> Title, @ViewBuilder instructions: () -> Instructions) {
self.image = image()
self.title = title()
self.instructions = instructions()
}

/// Create a new list header.
/// - Parameters:
/// - systemImage: The name of the system symbol image.
/// - title: The title view.
public init(systemImage: String, @ViewBuilder title: () -> Title) where Image == SwiftUI.Image, Instructions == EmptyView {
// swiftlint:disable:next accessibility_label_for_image
self.init(image: { SwiftUI.Image(systemName: systemImage) }, title: title) {
EmptyView()
}
}

/// Create a new list header.
/// - Parameters:
/// - systemImage: The name of the system symbol image.
/// - title: The title view.
/// - instructions: The instructions subheadline.
public init(systemImage: String, @ViewBuilder title: () -> Title, @ViewBuilder instructions: () -> Instructions) where Image == SwiftUI.Image {
// swiftlint:disable:next accessibility_label_for_image
self.init(image: { SwiftUI.Image(systemName: systemImage) }, title: title, instructions: instructions)
}
}


#if DEBUG
#Preview {
List {
ListHeader(systemImage: "person.fill.badge.plus") {
Text("Create a new Account", bundle: .module)
} instructions: {
Text("Please fill out the details below to create your new account.", bundle: .module)
}
}
}

#Preview {
List {
ListHeader(systemImage: "person.fill.badge.plus") {
Text("Create a new Account", bundle: .module)
}
}
}
#endif
18 changes: 18 additions & 0 deletions Tests/SpeziViewsTests/SnapshotTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,22 @@ final class SnapshotTests: XCTestCase {
Text("World")
}
}

@MainActor
func testListHeader() {
let listHeader0 = ListHeader(systemImage: "person.fill.badge.plus") {
Text("Create a new Account", bundle: .module)
} instructions: {
Text("Please fill out the details below to create your new account.", bundle: .module)
}

let listHeader1 = ListHeader(systemImage: "person.fill.badge.plus") {
Text("Create a new Account", bundle: .module)
}

#if os(iOS)
assertSnapshot(of: listHeader0, as: .image(layout: .device(config: .iPhone13Pro)), named: "list-header-instructions")
assertSnapshot(of: listHeader1, as: .image(layout: .device(config: .iPhone13Pro)), named: "list-header")
#endif
}
}
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.

0 comments on commit d4cc1af

Please sign in to comment.