feat: Moves flagged views into their own module.

This commit is contained in:
2024-06-07 09:02:22 -04:00
parent 425b1d0c8f
commit 75fa3b55ae
10 changed files with 172 additions and 35 deletions

View File

@@ -13,6 +13,7 @@ let package = Package(
products: [
.library(name: "CalculateAtFeature", targets: ["CalculateAtFeature"]),
.library(name: "EstimatedPressureDependency", targets: ["EstimatedPressureDependency"]),
.library(name: "FlaggedViews", targets: ["FlaggedViews"]),
.library(name: "PressureEstimationsFeature", targets: ["PressureEstimationsFeature"]),
.library(name: "SharedModels", targets: ["SharedModels"]),
.library(name: "Styleguide", targets: ["Styleguide"]),
@@ -55,6 +56,13 @@ let package = Package(
.product(name: "DependenciesMacros", package: "swift-dependencies")
]
),
.target(
name: "FlaggedViews",
dependencies: [
"SharedModels",
"Styleguide"
]
),
.target(name: "SharedModels"),
.target(
name: "Styleguide",
@@ -74,6 +82,7 @@ let package = Package(
name: "PressureEstimationsFeature",
dependencies: [
"EstimatedPressureDependency",
"FlaggedViews",
"SharedModels",
"Styleguide",
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),

View File

@@ -0,0 +1,32 @@
import SharedModels
import SwiftUI
public struct FlaggedMessageView: View {
@Environment(\.flaggedMessageViewStyle) private var style
let message: String?
let status: Flagged.CheckResult.Status
public init(message: String?, status: Flagged.CheckResult.Status) {
self.message = message
self.status = status
}
public var body: some View {
style.makeBody(
configuration: .init(message: message, status: status)
)
}
}
extension FlaggedMessageView {
public init(flagged: Flagged) {
self.init(message: flagged.message, status: flagged.status)
}
}
//#Preview {
// SwiftUIView()
//}

View File

@@ -0,0 +1,115 @@
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 DefaultFlaggedMessageViewStyle: FlaggedMessageViewStyle {
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if let message = configuration.message {
HStack {
Text(configuration.status.title)
.bold()
.foregroundStyle(configuration.status.flagColor)
TextLabel(message)
}
.font(.caption)
}
}
}
public struct VerticalFlaggedMessageViewStyle: FlaggedMessageViewStyle {
@ViewBuilder
public func makeBody(configuration: Configuration) -> some View {
if let message = configuration.message {
VStack(alignment: .leading) {
Text(configuration.status.title)
.bold()
.foregroundStyle(configuration.status.flagColor)
TextLabel(message)
}
.font(.caption)
}
}
}
extension FlaggedMessageViewStyle where Self == VerticalFlaggedMessageViewStyle {
public static var vertical: Self { .init() }
}
extension FlaggedMessageViewStyle where Self == DefaultFlaggedMessageViewStyle {
public static var horizontal: Self { .init() }
public static var `default`: Self { .init() }
}
private struct FlaggedMessageViewStyleKey: EnvironmentKey {
static var defaultValue = AnyFlaggedMessageViewStyle(DefaultFlaggedMessageViewStyle())
}
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 {
var flagColor: Color {
switch self {
case .good:
return .green
case .warning:
return .yellow
case .error:
return .red
}
}
}

View File

@@ -68,7 +68,7 @@ public struct DefaultFlagViewStyle: FlaggedViewStyle {
)
configuration.flagged.flagImage
}
flaggedMessageView(flagged: configuration.flagged)
FlaggedMessageView(flagged: configuration.flagged)
}
}
}
@@ -87,13 +87,13 @@ public struct FlagAndMessageOnlyStyle: FlaggedViewStyle {
switch stackStyle {
case .horizontal:
HStack {
flaggedMessageView(flagged: configuration.flagged)
FlaggedMessageView(flagged: configuration.flagged)
configuration.flagged.flagImage
}
case .vertical:
VStack {
configuration.flagged.flagImage
flaggedMessageView(flagged: configuration.flagged)
FlaggedMessageView(flagged: configuration.flagged)
}
}
}
@@ -114,7 +114,7 @@ public struct FlaggedGridRowStyle: FlaggedViewStyle {
VStack(alignment: .leading, spacing: 8) {
configuration.label
.foregroundStyle(Color.secondary)
flaggedMessageView(flagged: configuration.flagged)
FlaggedMessageView(flagged: configuration.flagged)
}
Text(
configuration.flagged.wrappedValue,
@@ -149,23 +149,9 @@ extension FlaggedViewStyle where Self == DefaultFlagViewStyle {
}
}
fileprivate extension Flagged.CheckResult.Key {
var flagColor: Color {
switch self {
case .good:
return .green
case .warning:
return .yellow
case .error:
return .red
}
}
}
extension Flagged {
var flagColor: Color { projectedValue.key.flagColor }
var flagColor: Color { self.status.flagColor }
public var flagImage: some View {
Image(systemName: "flag.fill")
@@ -173,20 +159,7 @@ extension Flagged {
}
public var messageView: some View {
flaggedMessageView(flagged: self)
}
}
@ViewBuilder
fileprivate func flaggedMessageView(flagged: Flagged) -> some View {
if let message = flagged.message {
HStack {
Text(flagged.projectedValue.key.title)
.bold()
.foregroundStyle(flagged.projectedValue.key.flagColor)
TextLabel(message)
}
.font(.caption)
FlaggedMessageView(flagged: self)
}
}

View File

@@ -1,4 +1,5 @@
import ComposableArchitecture
import FlaggedViews
import SharedModels
import Styleguide
import SwiftUI

View File

@@ -1,6 +1,7 @@
import ComposableArchitecture
import DependenciesAdditions
import EstimatedPressureDependency
import FlaggedViews
import SharedModels
import Styleguide
import SwiftUI
@@ -205,6 +206,7 @@ public struct FlaggedMeasurementsList {
@ViewAction(for: FlaggedMeasurementsList.self)
public struct FlaggedMeasurementListView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Bindable public var store: StoreOf<FlaggedMeasurementsList>
public init(store: StoreOf<FlaggedMeasurementsList>) {
@@ -265,6 +267,11 @@ public struct FlaggedMeasurementListView: View {
}
}
.onAppear { send(.onAppear) }
.flaggedMessageViewStyle(
horizontalSizeClass == .compact
? AnyFlaggedMessageViewStyle(.vertical)
: AnyFlaggedMessageViewStyle(.horizontal)
)
}
}

View File

@@ -70,7 +70,7 @@ public struct Flagged: Equatable {
case good(String? = nil)
case error(String)
public var key: Key {
public var status: Status {
switch self {
case .aboveMaximum(_):
return .error
@@ -110,7 +110,7 @@ public struct Flagged: Equatable {
}
}
public enum Key: String, Equatable, CaseIterable {
public enum Status: String, Equatable, CaseIterable {
case good, warning, error
public var title: String {