168 lines
4.3 KiB
Swift
168 lines
4.3 KiB
Swift
import SharedModels
|
|
import Styleguide
|
|
import SwiftUI
|
|
|
|
/// Represents the status of a flagged value, which is stylable using the
|
|
/// `.flaggedStatusLabelStyle` modifier on a view.
|
|
///
|
|
/// By default the status label is colored using the default status color.
|
|
public struct FlaggedStatusLabel: View {
|
|
@Environment(\.flaggedStatusLabelStyle) private var style
|
|
let status: Flagged.CheckResult.Status
|
|
|
|
public init(status: Flagged.CheckResult.Status) {
|
|
self.status = status
|
|
}
|
|
|
|
public var body: some View {
|
|
style.makeBody(
|
|
configuration: FlaggedStatusLabelStyleConfiguration(
|
|
status: status
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
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)
|
|
.flaggedStatusLabelStyle(.textLabel(.heavyTitle2))
|
|
|
|
FlaggedStatusLabel(status: .warning)
|
|
.flaggedStatusLabelStyle(.pill)
|
|
|
|
// FlaggedStatusLabel(status: .warning
|
|
// .flaggedStatusLabelStyle(.pill(.heavyTitle2))
|
|
}
|
|
}
|