feat: Moves flagged styles into their view files

This commit is contained in:
2024-06-07 23:23:27 -04:00
parent 11ec24586e
commit 68da203164
10 changed files with 582 additions and 589 deletions

View File

@@ -20,6 +20,128 @@ public struct FlaggedEquipmentMeasurementView: View {
}
}
public protocol FlaggedEquipmentMeasurementStyle {
associatedtype Body: View
typealias Configuration = FlaggedEquipmentMeasurementStyleConfiguration
@ViewBuilder
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedEquipmentMeasurementStyleConfiguration {
public let measurement: FlaggedEquipmentMeasurement
}
public struct AnyFlaggedEquipmentMeasurementStyle: FlaggedEquipmentMeasurementStyle {
private var _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<S: FlaggedEquipmentMeasurementStyle>(_ style: S) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct GridFlaggedEquipmentMeasurementStyle: FlaggedEquipmentMeasurementStyle {
public func makeBody(configuration: Configuration) -> some View {
Grid(alignment: .leading, verticalSpacing: 20) {
ForEach(FlaggedEquipmentMeasurement.Key.allCases) { field in
FlaggedView(
field.title,
flagged: configuration.measurement[keyPath: field.flaggedKeyPath]
)
.flaggedViewStyle(.gridRow(fractionLength: field == .airflow ? 0 : 2))
}
}
}
}
extension FlaggedEquipmentMeasurementStyle where Self == GridFlaggedEquipmentMeasurementStyle {
public static var grid: Self { .init() }
}
private struct FlaggedEquipmentMeasurementStyleKey: EnvironmentKey {
static let defaultValue = AnyFlaggedEquipmentMeasurementStyle(GridFlaggedEquipmentMeasurementStyle())
}
extension EnvironmentValues {
public var flaggedEquipmentMeasurementStyle: AnyFlaggedEquipmentMeasurementStyle {
get { self[FlaggedEquipmentMeasurementStyleKey.self] }
set { self[FlaggedEquipmentMeasurementStyleKey.self] = newValue }
}
}
extension View {
public func flaggedEquipmentMeasurementStyle(_ style: AnyFlaggedEquipmentMeasurementStyle) -> some View {
environment(\.flaggedEquipmentMeasurementStyle, style)
}
public func flaggedEquipmentMeasurementStyle<S: FlaggedEquipmentMeasurementStyle>(
_ style: S
) -> some View {
flaggedEquipmentMeasurementStyle(AnyFlaggedEquipmentMeasurementStyle(style))
}
}
// MARK: - Key
fileprivate extension FlaggedEquipmentMeasurement {
// NOTE: These need to be kept in display order.
enum Key: Hashable, CaseIterable, Identifiable {
case returnPlenum
case filterDrop
case coilDrop
case supplyPlenum
case staticPressure
case airflow
var id: Self { self }
var title: String {
switch self {
case .returnPlenum:
return "Return Plenum"
case .filterDrop:
return "Filter Pressure Drop"
case .coilDrop:
return "Coil Pressure Drop"
case .supplyPlenum:
return "Supply Plenum"
case .staticPressure:
return "External Static Pressure"
case .airflow:
return "System Airflow"
}
}
var flaggedKeyPath: KeyPath<FlaggedEquipmentMeasurement, Flagged> {
switch self {
case .returnPlenum:
return \.returnPlenumPressure
case .filterDrop:
return \.filterPressureDrop
case .coilDrop:
return \.coilPressureDrop
case .supplyPlenum:
return \.supplyPlenumPressure
case .staticPressure:
return \.externalStaticPressure
case .airflow:
return \.airflow
}
}
}
}
#if DEBUG
private let equipmentMeasurement = EquipmentMeasurement.airHandler(.init(
airflow: 1600,

View File

@@ -22,6 +22,28 @@ public struct FlaggedMessageLabel: View {
}
}
private struct FlaggedMessageLabelStyleKey: EnvironmentKey {
static var defaultValue = AnyTextLabelStyle(style: .font(.caption))
}
extension EnvironmentValues {
var flaggedMessageLabelStyle: AnyTextLabelStyle {
get { self[FlaggedMessageLabelStyleKey.self] }
set { self[FlaggedMessageLabelStyleKey.self] = newValue }
}
}
extension View {
public func flaggedMessageLabelStyle(_ style: AnyTextLabelStyle) -> some View {
environment(\.flaggedMessageLabelStyle, style)
}
public func flaggedMessageLabelStyle<S: TextLabelStyle>(_ style: S) -> some View {
flaggedMessageLabelStyle(AnyTextLabelStyle(style: style))
}
}
#Preview {
FlaggedStatusLabel(status: .warning)
.flaggedStatusLabelStyle(.textLabel(.heavyTitle2))

View File

@@ -26,3 +26,130 @@ extension FlaggedMessageView {
self.init(message: flagged.message, status: flagged.status)
}
}
public protocol FlaggedMessageViewStyle {
associatedtype Body: View
typealias Configuration = FlaggedMessageViewStyleConfiguration
@ViewBuilder
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedMessageViewStyleConfiguration {
public let message: String?
public let status: Flagged.CheckResult.Status
public init(message: String?, status: Flagged.CheckResult.Status) {
self.message = message
self.status = status
}
}
public struct AnyFlaggedMessageViewStyle: FlaggedMessageViewStyle {
private let _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<S: FlaggedMessageViewStyle>(_ style: S) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct HorizontalFlaggedMessageViewStyle: FlaggedMessageViewStyle {
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if configuration.message != nil {
HStack {
FlaggedStatusLabel(status: configuration.status)
FlaggedMessageLabel(message: configuration.message)
}
}
}
}
public struct VerticalFlaggedMessageViewStyle: FlaggedMessageViewStyle {
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if configuration.message != nil {
VStack(alignment: .leading) {
FlaggedStatusLabel(status: configuration.status)
FlaggedMessageLabel(message: configuration.message)
}
}
}
}
public struct AutomaticFlaggedMessageViewStyle: FlaggedMessageViewStyle {
let horizontalSizeClass: UserInterfaceSizeClass?
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if horizontalSizeClass == .compact {
VerticalFlaggedMessageViewStyle().makeBody(configuration: configuration)
} else {
HorizontalFlaggedMessageViewStyle().makeBody(configuration: configuration)
}
}
}
extension FlaggedMessageViewStyle where Self == VerticalFlaggedMessageViewStyle {
public static var vertical: Self { .init() }
}
extension FlaggedMessageViewStyle where Self == HorizontalFlaggedMessageViewStyle {
public static var horizontal: Self { .init() }
}
extension FlaggedMessageViewStyle where Self == AutomaticFlaggedMessageViewStyle {
public static func automatic(horizontalSizeClass: UserInterfaceSizeClass? = nil) -> Self {
.init(horizontalSizeClass: horizontalSizeClass)
}
}
private struct FlaggedMessageViewStyleKey: EnvironmentKey {
static var defaultValue = AnyFlaggedMessageViewStyle(
AutomaticFlaggedMessageViewStyle(horizontalSizeClass: nil)
)
}
extension EnvironmentValues {
public var flaggedMessageViewStyle: AnyFlaggedMessageViewStyle {
get { self[FlaggedMessageViewStyleKey.self] }
set { self[FlaggedMessageViewStyleKey.self] = newValue }
}
}
extension View {
public func flaggedMessageViewStyle(_ style: AnyFlaggedMessageViewStyle) -> some View {
environment(\.flaggedMessageViewStyle, style)
}
public func flaggedMessageViewStyle<S: FlaggedMessageViewStyle>(_ style: S) -> some View {
flaggedMessageViewStyle(AnyFlaggedMessageViewStyle(style))
}
}
extension Flagged.CheckResult.Status {
public var color: Color {
switch self {
case .good:
return .green
case .warning:
return .yellow
case .error:
return .red
}
}
}

View File

@@ -23,6 +23,136 @@ public struct FlaggedStatusLabel: View {
}
}
public protocol FlaggedStatusLabelStyle {
associatedtype Body: View
typealias Configuration = FlaggedStatusLabelStyleConfiguration
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedStatusLabelStyleConfiguration {
public let status: Flagged.CheckResult.Status
}
public struct AnyFlaggedStatusLabelStyle: FlaggedStatusLabelStyle {
private let _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<Style: FlaggedStatusLabelStyle>(_ style: Style) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct FlaggedStatusTextLabelStyle: FlaggedStatusLabelStyle {
let textLabelStyle: AnyTextLabelStyle?
public func makeBody(configuration: Configuration) -> some View {
TextLabel(configuration.status.title)
.textLabelStyle(
textLabelStyle
?? AnyTextLabelStyle(
style: .colored(configuration.status.color).font(.caption, fontWeight: .bold)
)
)
}
}
private struct FlaggedStatusLabelStyleKey: EnvironmentKey {
static var defaultValue = AnyFlaggedStatusLabelStyle(
FlaggedStatusTextLabelStyle(
textLabelStyle: AnyTextLabelStyle(
style: .font(.callout, fontWeight: .bold)
)
)
)
}
extension FlaggedStatusLabelStyle where Self == FlaggedStatusTextLabelStyle {
public static var textLabel: Self { textLabel() }
public static func textLabel(
_ style: AnyTextLabelStyle? = nil
) -> Self {
.init(textLabelStyle: style)
}
public static func textLabel<S: TextLabelStyle>(
_ style: S
) -> Self {
.init(textLabelStyle: AnyTextLabelStyle(style: style))
}
}
public struct FlaggedStatusPillStyle: FlaggedStatusLabelStyle {
let labelStyle: AnyTextLabelStyle?
let opacity: Double
public func makeBody(configuration: Configuration) -> some View {
TextLabel(configuration.status.title)
.textLabelStyle(labelStyle ?? AnyTextLabelStyle(
style: .font(.caption, fontWeight: .bold).combining(.colored(.white))
)
)
.padding(.horizontal, 10)
.padding(.vertical, 5)
.background {
Capsule()
.foregroundStyle(configuration.status.color.opacity(opacity))
}
}
}
extension FlaggedStatusLabelStyle where Self == FlaggedStatusPillStyle {
public static var pill: Self { .pill() }
public static func pill(
_ style: AnyTextLabelStyle? = nil,
opacity: Double = 1
) -> Self {
.init(labelStyle: style, opacity: opacity)
}
public static func pill<S: TextLabelStyle>(_ style: S, opacity: Double = 1) -> Self {
.init(labelStyle: AnyTextLabelStyle(style: style), opacity: opacity)
}
}
extension EnvironmentValues {
public var flaggedStatusLabelStyle: AnyFlaggedStatusLabelStyle {
get { self[FlaggedStatusLabelStyleKey.self] }
set { self[FlaggedStatusLabelStyleKey.self] = newValue }
}
}
extension View {
public func flaggedStatusLabelStyle(
_ style: AnyFlaggedStatusLabelStyle
) -> some View {
environment(
\.flaggedStatusLabelStyle,
style
)
}
public func flaggedStatusLabelStyle<S: FlaggedStatusLabelStyle>(_ style: S) -> some View {
flaggedStatusLabelStyle(AnyFlaggedStatusLabelStyle(style))
}
}
#Preview {
VStack {
FlaggedStatusLabel(status: .warning)

View File

@@ -18,7 +18,10 @@ public struct FlaggedView<Label: View>: View {
public var body: some View {
flaggedViewStyle.makeBody(
configuration: FlaggedViewStyleConfiguration(flagged: flagged, label: .init(label()))
configuration: FlaggedViewStyleConfiguration(
flagged: flagged,
label: .init(label())
)
)
}
}
@@ -38,3 +41,180 @@ extension FlaggedView where Label == EmptyView {
self.init(flagged: flagged) { EmptyView() }
}
}
public protocol FlaggedViewStyle {
associatedtype Body: View
typealias Configuration = FlaggedViewStyleConfiguration
@ViewBuilder
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedViewStyleConfiguration {
public let flagged: Flagged
public let label: Label
/// A type erased label for a flagged view.
public struct Label: View {
public let body: AnyView
public init<Content: View>(_ content: Content) {
self.body = AnyView(content)
}
}
}
public struct AnyFlaggedViewStyle: FlaggedViewStyle {
private var _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<S: FlaggedViewStyle>(style: S) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct DefaultFlagViewStyle: FlaggedViewStyle {
let alignment: HorizontalAlignment
let fractionLength: Int
let spacing: CGFloat
init(
alignment: HorizontalAlignment = .leading,
fractionLength: Int = 2,
spacing: CGFloat = 8
) {
self.alignment = alignment
self.fractionLength = fractionLength
self.spacing = spacing
}
public func makeBody(configuration: Configuration) -> some View {
VStack(alignment: alignment, spacing: spacing) {
HStack {
configuration.label
Spacer()
Text(
configuration.flagged.wrappedValue,
format: .number.precision(.fractionLength(fractionLength))
)
configuration.flagged.flagImage
}
FlaggedMessageView(flagged: configuration.flagged)
}
}
}
public struct FlagAndMessageOnlyStyle: FlaggedViewStyle {
public enum StackStyle {
case horizontal
case vertical
}
let stackStyle: StackStyle
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
switch stackStyle {
case .horizontal:
HStack {
FlaggedMessageView(flagged: configuration.flagged)
configuration.flagged.flagImage
}
case .vertical:
VStack {
configuration.flagged.flagImage
FlaggedMessageView(flagged: configuration.flagged)
}
}
}
}
extension FlaggedViewStyle where Self == FlagAndMessageOnlyStyle {
public static func flagAndMessageOnly(_ stackStyle: FlagAndMessageOnlyStyle.StackStyle = .vertical) -> Self {
.init(stackStyle: stackStyle)
}
}
public struct FlaggedGridRowStyle: FlaggedViewStyle {
let fractionLength: Int
public func makeBody(configuration: Configuration) -> some View {
GridRow {
VStack(alignment: .leading, spacing: 8) {
configuration.label
.foregroundStyle(Color.secondary)
FlaggedMessageView(flagged: configuration.flagged)
}
Spacer()
HStack(spacing: 10) {
Text(
configuration.flagged.wrappedValue,
format: .number.precision(.fractionLength(fractionLength))
)
configuration.flagged.flagImage
}
.gridCellAnchor(.trailing)
}
}
}
extension FlaggedViewStyle where Self == FlaggedGridRowStyle {
public static func gridRow(fractionLength: Int = 2) -> Self {
.init(fractionLength: fractionLength)
}
}
private struct FlaggedViewStyleKey: EnvironmentKey {
static let defaultValue = AnyFlaggedViewStyle(style: DefaultFlagViewStyle())
}
extension EnvironmentValues {
public var flaggedViewStyle: AnyFlaggedViewStyle {
get { self[FlaggedViewStyleKey.self] }
set { self[FlaggedViewStyleKey.self] = newValue }
}
}
extension FlaggedViewStyle where Self == DefaultFlagViewStyle {
public static func `default`(alignment: HorizontalAlignment = .leading, fractionLength: Int = 2, spacing: CGFloat = 8) -> Self {
.init(alignment: alignment, fractionLength: fractionLength, spacing: spacing)
}
}
extension Flagged {
public var statusColor: Color { self.status.color }
public var flagImage: some View {
Image(systemName: "flag.fill")
.foregroundStyle(statusColor)
}
public var messageView: some View {
FlaggedMessageView(flagged: self)
}
}
extension View {
public func flaggedViewStyle(_ style: AnyFlaggedViewStyle) -> some View {
environment(\.flaggedViewStyle, style)
}
public func flaggedViewStyle<S: FlaggedViewStyle>(
_ style: S
) -> some View {
flaggedViewStyle(AnyFlaggedViewStyle(style: style))
}
}

View File

@@ -1,123 +0,0 @@
import SharedModels
import SwiftUI
public protocol FlaggedEquipmentMeasurementStyle {
associatedtype Body: View
typealias Configuration = FlaggedEquipmentMeasurementStyleConfiguration
@ViewBuilder
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedEquipmentMeasurementStyleConfiguration {
public let measurement: FlaggedEquipmentMeasurement
}
public struct AnyFlaggedEquipmentMeasurementStyle: FlaggedEquipmentMeasurementStyle {
private var _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<S: FlaggedEquipmentMeasurementStyle>(_ style: S) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct GridFlaggedEquipmentMeasurementStyle: FlaggedEquipmentMeasurementStyle {
public func makeBody(configuration: Configuration) -> some View {
Grid(alignment: .leading, verticalSpacing: 20) {
ForEach(FlaggedEquipmentMeasurement.Key.allCases) { field in
FlaggedView(
field.title,
flagged: configuration.measurement[keyPath: field.flaggedKeyPath]
)
.flaggedViewStyle(.gridRow(fractionLength: field == .airflow ? 0 : 2))
}
}
}
}
extension FlaggedEquipmentMeasurementStyle where Self == GridFlaggedEquipmentMeasurementStyle {
public static var grid: Self { .init() }
}
private struct FlaggedEquipmentMeasurementStyleKey: EnvironmentKey {
static let defaultValue = AnyFlaggedEquipmentMeasurementStyle(GridFlaggedEquipmentMeasurementStyle())
}
extension EnvironmentValues {
public var flaggedEquipmentMeasurementStyle: AnyFlaggedEquipmentMeasurementStyle {
get { self[FlaggedEquipmentMeasurementStyleKey.self] }
set { self[FlaggedEquipmentMeasurementStyleKey.self] = newValue }
}
}
extension View {
public func flaggedEquipmentMeasurementStyle(_ style: AnyFlaggedEquipmentMeasurementStyle) -> some View {
environment(\.flaggedEquipmentMeasurementStyle, style)
}
public func flaggedEquipmentMeasurementStyle<S: FlaggedEquipmentMeasurementStyle>(
_ style: S
) -> some View {
flaggedEquipmentMeasurementStyle(AnyFlaggedEquipmentMeasurementStyle(style))
}
}
// MARK: - Key
fileprivate extension FlaggedEquipmentMeasurement {
// NOTE: These need to be kept in display order.
enum Key: Hashable, CaseIterable, Identifiable {
case returnPlenum
case filterDrop
case coilDrop
case supplyPlenum
case staticPressure
case airflow
var id: Self { self }
var title: String {
switch self {
case .returnPlenum:
return "Return Plenum"
case .filterDrop:
return "Filter Pressure Drop"
case .coilDrop:
return "Coil Pressure Drop"
case .supplyPlenum:
return "Supply Plenum"
case .staticPressure:
return "External Static Pressure"
case .airflow:
return "System Airflow"
}
}
var flaggedKeyPath: KeyPath<FlaggedEquipmentMeasurement, Flagged> {
switch self {
case .returnPlenum:
return \.returnPlenumPressure
case .filterDrop:
return \.filterPressureDrop
case .coilDrop:
return \.coilPressureDrop
case .supplyPlenum:
return \.supplyPlenumPressure
case .staticPressure:
return \.externalStaticPressure
case .airflow:
return \.airflow
}
}
}
}

View File

@@ -1,24 +0,0 @@
import Styleguide
import SwiftUI
private struct FlaggedMessageLabelStyleKey: EnvironmentKey {
static var defaultValue = AnyTextLabelStyle(style: .font(.caption))
}
extension EnvironmentValues {
var flaggedMessageLabelStyle: AnyTextLabelStyle {
get { self[FlaggedMessageLabelStyleKey.self] }
set { self[FlaggedMessageLabelStyleKey.self] = newValue }
}
}
extension View {
public func flaggedMessageLabelStyle(_ style: AnyTextLabelStyle) -> some View {
environment(\.flaggedMessageLabelStyle, style)
}
public func flaggedMessageLabelStyle<S: TextLabelStyle>(_ style: S) -> some View {
flaggedMessageLabelStyle(AnyTextLabelStyle(style: style))
}
}

View File

@@ -1,130 +0,0 @@
import SharedModels
import Styleguide
import SwiftUI
public protocol FlaggedMessageViewStyle {
associatedtype Body: View
typealias Configuration = FlaggedMessageViewStyleConfiguration
@ViewBuilder
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedMessageViewStyleConfiguration {
public let message: String?
public let status: Flagged.CheckResult.Status
public init(message: String?, status: Flagged.CheckResult.Status) {
self.message = message
self.status = status
}
}
public struct AnyFlaggedMessageViewStyle: FlaggedMessageViewStyle {
private let _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<S: FlaggedMessageViewStyle>(_ style: S) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct HorizontalFlaggedMessageViewStyle: FlaggedMessageViewStyle {
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if configuration.message != nil {
HStack {
FlaggedStatusLabel(status: configuration.status)
FlaggedMessageLabel(message: configuration.message)
}
}
}
}
public struct VerticalFlaggedMessageViewStyle: FlaggedMessageViewStyle {
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if configuration.message != nil {
VStack(alignment: .leading) {
FlaggedStatusLabel(status: configuration.status)
FlaggedMessageLabel(message: configuration.message)
}
}
}
}
public struct AutomaticFlaggedMessageViewStyle: FlaggedMessageViewStyle {
let horizontalSizeClass: UserInterfaceSizeClass?
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if horizontalSizeClass == .compact {
VerticalFlaggedMessageViewStyle().makeBody(configuration: configuration)
} else {
HorizontalFlaggedMessageViewStyle().makeBody(configuration: configuration)
}
}
}
extension FlaggedMessageViewStyle where Self == VerticalFlaggedMessageViewStyle {
public static var vertical: Self { .init() }
}
extension FlaggedMessageViewStyle where Self == HorizontalFlaggedMessageViewStyle {
public static var horizontal: Self { .init() }
}
extension FlaggedMessageViewStyle where Self == AutomaticFlaggedMessageViewStyle {
public static func automatic(horizontalSizeClass: UserInterfaceSizeClass? = nil) -> Self {
.init(horizontalSizeClass: horizontalSizeClass)
}
}
private struct FlaggedMessageViewStyleKey: EnvironmentKey {
static var defaultValue = AnyFlaggedMessageViewStyle(
AutomaticFlaggedMessageViewStyle(horizontalSizeClass: nil)
)
}
extension EnvironmentValues {
public var flaggedMessageViewStyle: AnyFlaggedMessageViewStyle {
get { self[FlaggedMessageViewStyleKey.self] }
set { self[FlaggedMessageViewStyleKey.self] = newValue }
}
}
extension View {
public func flaggedMessageViewStyle(_ style: AnyFlaggedMessageViewStyle) -> some View {
environment(\.flaggedMessageViewStyle, style)
}
public func flaggedMessageViewStyle<S: FlaggedMessageViewStyle>(_ style: S) -> some View {
flaggedMessageViewStyle(AnyFlaggedMessageViewStyle(style))
}
}
extension Flagged.CheckResult.Status {
public var color: Color {
switch self {
case .good:
return .green
case .warning:
return .yellow
case .error:
return .red
}
}
}

View File

@@ -1,132 +0,0 @@
import SharedModels
import Styleguide
import SwiftUI
public protocol FlaggedStatusLabelStyle {
associatedtype Body: View
typealias Configuration = FlaggedStatusLabelStyleConfiguration
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedStatusLabelStyleConfiguration {
public let status: Flagged.CheckResult.Status
}
public struct AnyFlaggedStatusLabelStyle: FlaggedStatusLabelStyle {
private let _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<Style: FlaggedStatusLabelStyle>(_ style: Style) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct FlaggedStatusTextLabelStyle: FlaggedStatusLabelStyle {
let textLabelStyle: AnyTextLabelStyle?
public func makeBody(configuration: Configuration) -> some View {
TextLabel(configuration.status.title)
.textLabelStyle(
textLabelStyle
?? AnyTextLabelStyle(
style: .colored(configuration.status.color).font(.caption, fontWeight: .bold)
)
)
}
}
private struct FlaggedStatusLabelStyleKey: EnvironmentKey {
static var defaultValue = AnyFlaggedStatusLabelStyle(
FlaggedStatusTextLabelStyle(
textLabelStyle: AnyTextLabelStyle(
style: .font(.callout, fontWeight: .bold)
)
)
)
}
extension FlaggedStatusLabelStyle where Self == FlaggedStatusTextLabelStyle {
public static var textLabel: Self { textLabel() }
public static func textLabel(
_ style: AnyTextLabelStyle? = nil
) -> Self {
.init(textLabelStyle: style)
}
public static func textLabel<S: TextLabelStyle>(
_ style: S
) -> Self {
.init(textLabelStyle: AnyTextLabelStyle(style: style))
}
}
public struct FlaggedStatusPillStyle: FlaggedStatusLabelStyle {
let labelStyle: AnyTextLabelStyle?
let opacity: Double
public func makeBody(configuration: Configuration) -> some View {
TextLabel(configuration.status.title)
.textLabelStyle(labelStyle ?? AnyTextLabelStyle(
style: .font(.caption, fontWeight: .bold).combining(.colored(.white))
)
)
.padding(.horizontal, 10)
.padding(.vertical, 5)
.background {
Capsule()
.foregroundStyle(configuration.status.color.opacity(opacity))
}
}
}
extension FlaggedStatusLabelStyle where Self == FlaggedStatusPillStyle {
public static var pill: Self { .pill() }
public static func pill(
_ style: AnyTextLabelStyle? = nil,
opacity: Double = 1
) -> Self {
.init(labelStyle: style, opacity: opacity)
}
public static func pill<S: TextLabelStyle>(_ style: S, opacity: Double = 1) -> Self {
.init(labelStyle: AnyTextLabelStyle(style: style), opacity: opacity)
}
}
extension EnvironmentValues {
public var flaggedStatusLabelStyle: AnyFlaggedStatusLabelStyle {
get { self[FlaggedStatusLabelStyleKey.self] }
set { self[FlaggedStatusLabelStyleKey.self] = newValue }
}
}
extension View {
public func flaggedStatusLabelStyle(
_ style: AnyFlaggedStatusLabelStyle
) -> some View {
environment(
\.flaggedStatusLabelStyle,
style
)
}
public func flaggedStatusLabelStyle<S: FlaggedStatusLabelStyle>(_ style: S) -> some View {
flaggedStatusLabelStyle(AnyFlaggedStatusLabelStyle(style))
}
}

View File

@@ -1,179 +0,0 @@
import SharedModels
import SwiftUI
public protocol FlaggedViewStyle {
associatedtype Body: View
typealias Configuration = FlaggedViewStyleConfiguration
@ViewBuilder
func makeBody(configuration: Self.Configuration) -> Self.Body
}
public struct FlaggedViewStyleConfiguration {
public let flagged: Flagged
public let label: Label
/// A type erased label for a flagged view.
public struct Label: View {
public let body: AnyView
public init<Content: View>(_ content: Content) {
self.body = AnyView(content)
}
}
}
public struct AnyFlaggedViewStyle: FlaggedViewStyle {
private var _makeBody: (Configuration) -> AnyView
internal init(makeBody: @escaping (Configuration) -> AnyView) {
self._makeBody = makeBody
}
public init<S: FlaggedViewStyle>(style: S) {
self.init { configuration in
AnyView(style.makeBody(configuration: configuration))
}
}
public func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
public struct DefaultFlagViewStyle: FlaggedViewStyle {
let alignment: HorizontalAlignment
let fractionLength: Int
let spacing: CGFloat
init(
alignment: HorizontalAlignment = .leading,
fractionLength: Int = 2,
spacing: CGFloat = 8
) {
self.alignment = alignment
self.fractionLength = fractionLength
self.spacing = spacing
}
public func makeBody(configuration: Configuration) -> some View {
VStack(alignment: alignment, spacing: spacing) {
HStack {
configuration.label
Spacer()
Text(
configuration.flagged.wrappedValue,
format: .number.precision(.fractionLength(fractionLength))
)
configuration.flagged.flagImage
}
FlaggedMessageView(flagged: configuration.flagged)
}
}
}
public struct FlagAndMessageOnlyStyle: FlaggedViewStyle {
public enum StackStyle {
case horizontal
case vertical
}
let stackStyle: StackStyle
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
switch stackStyle {
case .horizontal:
HStack {
FlaggedMessageView(flagged: configuration.flagged)
configuration.flagged.flagImage
}
case .vertical:
VStack {
configuration.flagged.flagImage
FlaggedMessageView(flagged: configuration.flagged)
}
}
}
}
extension FlaggedViewStyle where Self == FlagAndMessageOnlyStyle {
public static func flagAndMessageOnly(_ stackStyle: FlagAndMessageOnlyStyle.StackStyle = .vertical) -> Self {
.init(stackStyle: stackStyle)
}
}
public struct FlaggedGridRowStyle: FlaggedViewStyle {
let fractionLength: Int
public func makeBody(configuration: Configuration) -> some View {
GridRow {
VStack(alignment: .leading, spacing: 8) {
configuration.label
.foregroundStyle(Color.secondary)
FlaggedMessageView(flagged: configuration.flagged)
}
Spacer()
HStack(spacing: 10) {
Text(
configuration.flagged.wrappedValue,
format: .number.precision(.fractionLength(fractionLength))
)
configuration.flagged.flagImage
}
.gridCellAnchor(.trailing)
}
}
}
extension FlaggedViewStyle where Self == FlaggedGridRowStyle {
public static func gridRow(fractionLength: Int = 2) -> Self {
.init(fractionLength: fractionLength)
}
}
private struct FlaggedViewStyleKey: EnvironmentKey {
static let defaultValue = AnyFlaggedViewStyle(style: DefaultFlagViewStyle())
}
extension EnvironmentValues {
public var flaggedViewStyle: AnyFlaggedViewStyle {
get { self[FlaggedViewStyleKey.self] }
set { self[FlaggedViewStyleKey.self] = newValue }
}
}
extension FlaggedViewStyle where Self == DefaultFlagViewStyle {
public static func `default`(alignment: HorizontalAlignment = .leading, fractionLength: Int = 2, spacing: CGFloat = 8) -> Self {
.init(alignment: alignment, fractionLength: fractionLength, spacing: spacing)
}
}
extension Flagged {
public var statusColor: Color { self.status.color }
public var flagImage: some View {
Image(systemName: "flag.fill")
.foregroundStyle(statusColor)
}
public var messageView: some View {
FlaggedMessageView(flagged: self)
}
}
extension View {
public func flaggedViewStyle(_ style: AnyFlaggedViewStyle) -> some View {
environment(\.flaggedViewStyle, style)
}
public func flaggedViewStyle<S: FlaggedViewStyle>(
_ style: S
) -> some View {
flaggedViewStyle(AnyFlaggedViewStyle(style: style))
}
}