Files
attendi/Packages/Features/Sources/Notifying/Styles/Labels/NotificationLabelStyle.swift
T

148 lines
4.1 KiB
Swift

import SwiftUI
/// The label style for the transient in-app notification banners.
///
/// The style renders the label's icon next to its title, over a padded, capsule Liquid Glass background. The icon is tinted with a color
/// matching the kind of notification given at initialization — green for an informational one, yellow for a warning, and red for an
/// error — and the title wears a medium-weight callout font.
public struct NotificationLabelStyle: LabelStyle {
// MARK: Properties
/// The kind of notification whose matching color tints the label's icon.
private let kind: AppNotification.Kind
// MARK: Initializers
/// Creates a notification label style for a given kind of notification.
///
/// - Parameter kind: The kind of notification whose matching color tints the label's icon.
public init(
kind: AppNotification.Kind
) {
self.kind = kind
}
// MARK: Methods
/// Creates the styled body of the label.
///
/// - Parameter configuration: The properties of the label being styled.
public func makeBody(
configuration: Configuration
) -> some View {
HStack(
spacing: Constant.Spacing.stack
) {
configuration.icon
.font(.title3)
.foregroundStyle(kind.imageStyle)
configuration.title
.font(.callout)
.fontWeight(.medium)
.foregroundStyle(.primary)
}
.padding(.vertical, Constant.Padding.vertical)
.padding(.horizontal, Constant.Padding.horizontal)
#if os(visionOS)
.glassBackgroundEffect(in: .capsule)
#else
.glassEffect(
.regular,
in: .capsule
)
#endif
}
}
// MARK: - Styles
public extension LabelStyle where Self == NotificationLabelStyle {
/// The label style for the transient in-app notification banners.
///
/// - Parameter kind: The kind of notification whose matching color tints the label's icon.
/// - Returns: A notification label style for the given kind of notification.
static func notification(
kind: AppNotification.Kind
) -> NotificationLabelStyle {
.init(kind: kind)
}
}
// MARK: - AppNotification.Kind+Properties
private extension AppNotification.Kind {
/// The color that tints the icon of a notification label: green for an informational notification, yellow for a warning, and red
/// for an error.
var imageStyle: Color {
switch self {
case .error: .red
case .info: .green
case .warning: .yellow
}
}
}
// MARK: - Constants
/// The constant values used across the label style.
private enum Constant {
/// The padding constants.
enum Padding {
/// The horizontal padding between a label's content and its background.
static let horizontal: CGFloat = 16
/// The vertical padding between a label's content and its background.
static let vertical: CGFloat = 8
}
/// The spacing constants.
enum Spacing {
/// The spacing between the elements of a stack.
static let stack: CGFloat = 16
}
}
// MARK: - Previews
#Preview(
"Notification label style"
) {
VStack(
alignment: .leading,
spacing: 16
) {
Label {
Text(verbatim: "Downloading the speech model for Dutch (Netherlands)…")
} icon: {
Image(systemName: "arrow.down.circle")
}
.labelStyle(.notification(
kind: .info
))
Label {
Text(verbatim: "The speech model download for Dutch (Netherlands) was cancelled.")
} icon: {
Image(systemName: "xmark.circle")
}
.labelStyle(.notification(
kind: .warning
))
Label {
Text(verbatim: "The speech model for German (Germany) could not be downloaded.")
} icon: {
Image(systemName: "exclamationmark.triangle")
}
.labelStyle(.notification(
kind: .error
))
}
}