From e8a227017dde5babc50faf34da4e01b5ef8f3418 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Sat, 26 Feb 2022 12:37:08 +0300 Subject: [PATCH] Refactor components sizing, radius and more --- .../Controls/Avatar/AvatarView.swift | 42 +++---- .../Controls/Background/Background.swift | 25 ++-- Sources/OversizeUI/Controls/Badge/Bage.swift | 11 +- Sources/OversizeUI/Controls/Icon/Icon.swift | 18 +-- .../Controls/Loader/LoaderOverlayView.swift | 3 +- Sources/OversizeUI/Controls/Row/Row.swift | 9 +- .../OversizeUI/Controls/Row/RowButton.swift | 4 +- .../Controls/ScrollView/SectionView.swift | 7 +- .../SegmentedControl/SegmentedControl.swift | 26 ++-- .../Support/SegmentedControlPreview.swift | 9 +- .../OversizeUI/Controls/Select/Select.swift | 4 +- .../OversizeUI/Controls/Surface/Surface.swift | 117 ++++++++---------- .../Controls/Surface/View+Surface.swift | 34 ++--- .../ControlSizeEnvironment.swift | 2 +- .../EnvironmentKey/ElevationEnvironment.swift | 3 +- .../EnvironmentKey/LoadingEnvironment.swift | 3 +- .../EnvironmentKey/PaddingEnvironment.swift | 23 ++++ .../EnvironmentKey/PremiumEnvironment.swift | 3 +- .../EnvironmentKey/RadiusEnvironment.swift | 23 ++++ .../ScreenSizeEnvironment.swift | 67 ++++++++++ .../EnvironmentKey/ThemeEnvironment.swift | 2 +- 21 files changed, 262 insertions(+), 173 deletions(-) create mode 100644 Sources/OversizeUI/Extensions/EnvironmentKey/PaddingEnvironment.swift create mode 100644 Sources/OversizeUI/Extensions/EnvironmentKey/RadiusEnvironment.swift create mode 100644 Sources/OversizeUI/Extensions/EnvironmentKey/ScreenSizeEnvironment.swift diff --git a/Sources/OversizeUI/Controls/Avatar/AvatarView.swift b/Sources/OversizeUI/Controls/Avatar/AvatarView.swift index f4d3727..0909148 100644 --- a/Sources/OversizeUI/Controls/Avatar/AvatarView.swift +++ b/Sources/OversizeUI/Controls/Avatar/AvatarView.swift @@ -7,8 +7,8 @@ import SwiftUI public enum AvatarSize: Int, CaseIterable { case small - case m - case l + case medium + case large } public struct AvatarView: View { @@ -28,13 +28,13 @@ public struct AvatarView: View { let firstName: String let lastName: String let size: AvatarSize - let avatar: Image + let avatar: Image? let stroke: Bool public init(firstName: String = "", lastName: String = "", - size: AvatarSize = .m, - avatar: Image = Image(""), + size: AvatarSize = .medium, + avatar: Image? = nil, stroke: Bool = false) { self.firstName = firstName @@ -45,11 +45,11 @@ public struct AvatarView: View { } public var body: some View { - if avatar != Image("") { + if let avatar = avatar { avatar .resizable() - .frame(width: size == .small ? Constants.sizeS : size == .m ? Constants.sizeM : Constants.sizeL, - height: size == .small ? Constants.sizeS : size == .m ? Constants.sizeM : Constants.sizeL) + .frame(width: size == .small ? Constants.sizeS : size == .medium ? Constants.sizeM : Constants.sizeL, + height: size == .small ? Constants.sizeS : size == .medium ? Constants.sizeM : Constants.sizeL) .clipShape(Circle()) .overlay(stroke ? Circle().stroke(Constants.borderColor, lineWidth: Constants.borderLineWidth) : nil) @@ -58,19 +58,19 @@ public struct AvatarView: View { Circle() .fill(LinearGradient(gradient: Gradient(colors: [Color.warning, Color.success]), startPoint: .topLeading, endPoint: .bottom)) - .frame(width: size == .small ? Constants.sizeS : size == .m ? Constants.sizeM : Constants.sizeL, - height: size == .small ? Constants.sizeS : size == .m ? Constants.sizeM : Constants.sizeL) + .frame(width: size == .small ? Constants.sizeS : size == .medium ? Constants.sizeM : Constants.sizeL, + height: size == .small ? Constants.sizeS : size == .medium ? Constants.sizeM : Constants.sizeL) .overlay(stroke ? Circle().stroke(Constants.borderColor, lineWidth: Constants.borderLineWidth) : nil) HStack(spacing: size == .small ? Constants.avatarTextSpaceS - : size == .m ? Constants.avatarTextSpaceM + : size == .medium ? Constants.avatarTextSpaceM : Constants.avatarTextSpaceL) { if firstName != "" { Text(String(firstName.dropLast(firstName.count - 1))) - .fontStyle(size == .small ? .caption : size == .m + .fontStyle(size == .small ? .caption : size == .medium ? .title3 : .largeTitle, color: .onPrimaryHighEmphasis) @@ -80,7 +80,7 @@ public struct AvatarView: View { Text(String(lastName.dropLast(lastName.count - 1))) .fontStyle(size == .small ? .caption - : size == .m + : size == .medium ? .title3 : .largeTitle, color: .onPrimaryHighEmphasis) @@ -111,32 +111,32 @@ struct M7AvatarView_Previews: PreviewProvider { .background(Color.surfaceTertiary) Group { - AvatarView(firstName: "Jhon", size: .m) + AvatarView(firstName: "Jhon", size: .medium) .previewDisplayName("Only firsy name") - AvatarView(firstName: "Jhon", lastName: "Smith", size: .m, stroke: true) + AvatarView(firstName: "Jhon", lastName: "Smith", size: .medium, stroke: true) .previewDisplayName("First name, last name and storke") - AvatarView(size: .m, avatar: Image("empty", bundle: .module)) + AvatarView(size: .medium, avatar: Image("empty", bundle: .module)) .previewDisplayName("Only avatar") - AvatarView(firstName: "Jhon", lastName: "Smith", size: .m, avatar: Image("empty", bundle: .module), stroke: true) + AvatarView(firstName: "Jhon", lastName: "Smith", size: .medium, avatar: Image("empty", bundle: .module), stroke: true) .previewDisplayName("All data") }.previewLayout(.fixed(width: 48, height: 48)) .background(Color.surfaceTertiary) Group { - AvatarView(firstName: "Jhon", size: .l) + AvatarView(firstName: "Jhon", size: .large) .previewDisplayName("Only firsy name") - AvatarView(firstName: "Jhon", lastName: "Smith", size: .l, stroke: true) + AvatarView(firstName: "Jhon", lastName: "Smith", size: .large, stroke: true) .previewDisplayName("First name, last name and storke") - AvatarView(size: .l, avatar: Image("empty", bundle: .module)) + AvatarView(size: .large, avatar: Image("empty", bundle: .module)) .previewDisplayName("Only avatar") - AvatarView(firstName: "Jhon", lastName: "Smith", size: .l, avatar: Image("empty", bundle: .module), stroke: true) + AvatarView(firstName: "Jhon", lastName: "Smith", size: .large, avatar: Image("empty", bundle: .module), stroke: true) .previewDisplayName("All data") }.previewLayout(.fixed(width: 96, height: 96)) diff --git a/Sources/OversizeUI/Controls/Background/Background.swift b/Sources/OversizeUI/Controls/Background/Background.swift index af2efc6..92c67fd 100644 --- a/Sources/OversizeUI/Controls/Background/Background.swift +++ b/Sources/OversizeUI/Controls/Background/Background.swift @@ -34,15 +34,9 @@ public struct Background: View { } private let content: Content - - public var backgroundColor: Color = Constants.colorPrimary - - public var background: BackgroundColor - + private let background: BackgroundColor public var padding: BackgroundPadding - public var paddingSize: CGFloat = 0 - public init(background: BackgroundColor = .primary, padding: BackgroundPadding = .medium, @ViewBuilder content: () -> Content) @@ -50,9 +44,6 @@ public struct Background: View { self.content = content() self.padding = padding self.background = background - - setBackground(background) - setPadding(padding) } public var body: some View { @@ -63,23 +54,23 @@ public struct Background: View { .cornerRadius(Radius.medium) } - private mutating func setPadding(_ padding: BackgroundPadding) { + private var paddingSize: CGFloat { switch padding { case .medium: - paddingSize = Constants.paddingM + return Constants.paddingM case .small: - paddingSize = Constants.paddingS + return Constants.paddingS } } - private mutating func setBackground(_ background: BackgroundColor) { + private var backgroundColor: Color { switch background { case .primary: - backgroundColor = Constants.colorPrimary + return Constants.colorPrimary case .secondary: - backgroundColor = Constants.colorSecondary + return Constants.colorSecondary case .tertiary: - backgroundColor = Constants.colorTertiary + return Constants.colorTertiary } } } diff --git a/Sources/OversizeUI/Controls/Badge/Bage.swift b/Sources/OversizeUI/Controls/Badge/Bage.swift index 21db0d1..2230743 100644 --- a/Sources/OversizeUI/Controls/Badge/Bage.swift +++ b/Sources/OversizeUI/Controls/Badge/Bage.swift @@ -7,14 +7,13 @@ import SwiftUI public struct Bage: View { @Environment(\.theme) private var theme: ThemeSettings + @Environment(\.controlRadius) private var controlRadius: Radius private let label: Label - private var color: Color - private var radius: Radius + private let color: Color - public init(color: Color = .accentColor, radius: Radius = .small, @ViewBuilder label: () -> Label) { + public init(color: Color = .accentColor, @ViewBuilder label: () -> Label) { self.color = color - self.radius = radius self.label = label() } @@ -27,11 +26,11 @@ public struct Bage: View { .padding(.vertical, .xxxSmall) .padding(.horizontal, 6) .background( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .circular) .fill(color.opacity(0.1)) .overlay( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous) .stroke( theme.borderSurface diff --git a/Sources/OversizeUI/Controls/Icon/Icon.swift b/Sources/OversizeUI/Controls/Icon/Icon.swift index c2a77b6..a53c587 100644 --- a/Sources/OversizeUI/Controls/Icon/Icon.swift +++ b/Sources/OversizeUI/Controls/Icon/Icon.swift @@ -316,42 +316,42 @@ public struct Icon: View { } let name: Icons - var size: CGFloat = Constants.medium + let size: IconSizes var color: Color public init(_ name: Icons = .menu) { self.name = name + size = .medium color = Color.onBackgroundHighEmphasis - setTextStyle(IconSizes.medium) } public init(_ name: Icons = .menu, size: IconSizes = .medium, color: Color = .onBackgroundHighEmphasis) { self.name = name self.color = color - setTextStyle(size) + self.size = size } public var body: some View { if name != .none { Image(name.rawValue, bundle: .module) .resizable() - .frame(width: size, height: size) + .frame(width: iconSize, height: iconSize) .foregroundColor(color) } else { EmptyView() } } - private mutating func setTextStyle(_ size: IconSizes) { + var iconSize: CGFloat { switch size { case .medium: - break + return Constants.medium case .small: - self.size = Constants.small + return Constants.small case .large: - self.size = Constants.large + return Constants.large case .xLarge: - self.size = Constants.xLarge + return Constants.xLarge } } } diff --git a/Sources/OversizeUI/Controls/Loader/LoaderOverlayView.swift b/Sources/OversizeUI/Controls/Loader/LoaderOverlayView.swift index 8e8653a..a6c463e 100644 --- a/Sources/OversizeUI/Controls/Loader/LoaderOverlayView.swift +++ b/Sources/OversizeUI/Controls/Loader/LoaderOverlayView.swift @@ -50,7 +50,7 @@ public struct LoaderOverlayView: View { Color.surfaceSecondary.opacity(0.5) #endif - Surface(background: .primary) { + Surface { VStack(spacing: 20) { containedView() @@ -62,6 +62,7 @@ public struct LoaderOverlayView: View { } .padding() } + .surfaceStyle(.primary) .elevation(.z4) } .ignoresSafeArea() diff --git a/Sources/OversizeUI/Controls/Row/Row.swift b/Sources/OversizeUI/Controls/Row/Row.swift index e57522c..ea8df4e 100644 --- a/Sources/OversizeUI/Controls/Row/Row.swift +++ b/Sources/OversizeUI/Controls/Row/Row.swift @@ -155,9 +155,12 @@ public struct Row: View { case let .avatar(avatar): avatar case let .iconOnSurface(icon): - Surface(background: .secondary, padding: .xxSmall) { + Surface { Icon(icon) - }.padding(.trailing, Constants.spacingIconAndText) + } + .surfaceStyle(.secondary) + .padding(.trailing, Constants.spacingIconAndText) + .controlPadding(.xxSmall) case let .systemImage(systemImage): Image(systemName: systemImage) .foregroundColor(Color.onBackgroundHighEmphasis) @@ -171,9 +174,7 @@ public struct Row: View { private func tralling() -> some View { switch trallingType { case .none: - EmptyView() - case let .toggle(isOn): Toggle(isOn: isOn) {} .labelsHidden() diff --git a/Sources/OversizeUI/Controls/Row/RowButton.swift b/Sources/OversizeUI/Controls/Row/RowButton.swift index 363769f..8bfd68b 100644 --- a/Sources/OversizeUI/Controls/Row/RowButton.swift +++ b/Sources/OversizeUI/Controls/Row/RowButton.swift @@ -33,9 +33,11 @@ public struct RowButton: View { Button(action: self.tapAction) { HStack { if icon != .none { - Surface(background: .secondary, padding: .xxSmall) { + Surface { Icon(icon) } + .surfaceStyle(.secondary) + .controlPadding(.xxSmall) } Text(text) diff --git a/Sources/OversizeUI/Controls/ScrollView/SectionView.swift b/Sources/OversizeUI/Controls/ScrollView/SectionView.swift index 8cfe532..116a5c9 100644 --- a/Sources/OversizeUI/Controls/ScrollView/SectionView.swift +++ b/Sources/OversizeUI/Controls/ScrollView/SectionView.swift @@ -28,12 +28,15 @@ public struct SectionView: View { Text(title) .fontStyle(.subtitle1) .foregroundColor(.onBackgroundHighEmphasis) + .padding(.leading, .xxxSmall) } - Surface(padding: .zero) { + Surface { content .padding(.vertical, verticalPadding) - }.clipShape( + } + .controlPadding(.zero) + .clipShape( RoundedRectangle(cornerRadius: Constants.radiusMedium, style: .circular) ) diff --git a/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift b/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift index 694e9ab..ba8ea4e 100644 --- a/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift +++ b/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift @@ -11,13 +11,13 @@ public struct SegmentedPickerSelector: V Selection: View { @Environment(\.theme) private var theme: ThemeSettings - @Environment(\.segmentedControlStyle) private var style + @Environment(\.controlRadius) var controlRadius: Radius + public typealias Data = [Element] @State private var frames: [CGRect] @State private var selectedIndex: Data.Index? = 0 - private let radius: Radius @Binding private var selection: Data.Element private let data: Data @@ -27,14 +27,12 @@ public struct SegmentedPickerSelector: V public init(_ data: Data, selection: Binding, - radius: Radius = .medium, @ViewBuilder content: @escaping (Data.Element, Bool) -> Content, @ViewBuilder selectionView: @escaping () -> Selection? = { nil }, action: (() -> Void)? = nil) { self.data = data self.content = content - self.radius = radius self.selectionView = selectionView self.action = action _selection = selection @@ -50,7 +48,7 @@ public struct SegmentedPickerSelector: V ) ) ) - .clipBackground(style.isShowBackground, radius: radius.rawValue) + .clipBackground(style.isShowBackground, radius: controlRadius.rawValue) .onAppear { let selctedValue = self.selection var index = 0 @@ -186,11 +184,11 @@ public struct SegmentedPickerSelector: V switch selectionStyle { case .shadowSurface: - RoundedRectangle(cornerRadius: style.isShowBackground ? radius.rawValue - 4 : radius.rawValue, + RoundedRectangle(cornerRadius: style.isShowBackground ? controlRadius.rawValue - 4 : controlRadius.rawValue, style: .continuous) .fill(Color.surfacePrimary) .overlay( - RoundedRectangle(cornerRadius: style.isShowBackground ? radius.rawValue - 4 : radius.rawValue, + RoundedRectangle(cornerRadius: style.isShowBackground ? controlRadius.rawValue - 4 : controlRadius.rawValue, style: .continuous) .stroke(theme.borderControls ? Color.border @@ -200,11 +198,11 @@ public struct SegmentedPickerSelector: V case .graySurface: if style.unseletionStyle == .clean { - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous) .stroke(theme.borderControls ? Color.border @@ -212,12 +210,12 @@ public struct SegmentedPickerSelector: V ) } else { - RoundedRectangle(cornerRadius: style.isShowBackground ? radius.rawValue - 4 : radius.rawValue, + RoundedRectangle(cornerRadius: style.isShowBackground ? controlRadius.rawValue - 4 : controlRadius.rawValue, style: .continuous) .strokeBorder(Color.onSurfaceMediumEmphasis, lineWidth: 2) } case .accentSurface: - RoundedRectangle(cornerRadius: style.isShowBackground ? radius.rawValue - 4 : radius.rawValue, + RoundedRectangle(cornerRadius: style.isShowBackground ? controlRadius.rawValue - 4 : controlRadius.rawValue, style: .continuous) .strokeBorder(Color.blue, lineWidth: 2) } @@ -230,11 +228,11 @@ public struct SegmentedPickerSelector: V EmptyView() case .surface: - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous) .stroke(theme.borderControls ? Color.border @@ -247,13 +245,11 @@ public struct SegmentedPickerSelector: V public extension SegmentedPickerSelector where Selection == EmptyView { init(_ data: Data, selection: Binding, - radius: Radius = .medium, @ViewBuilder content: @escaping (Data.Element, Bool) -> Content, action: (() -> Void)? = nil) { self.data = data self.content = content - self.radius = radius self.action = action selectionView = { nil } _selection = selection diff --git a/Sources/OversizeUI/Controls/SegmentedControl/Support/SegmentedControlPreview.swift b/Sources/OversizeUI/Controls/SegmentedControl/Support/SegmentedControlPreview.swift index a338cb8..bd666f9 100644 --- a/Sources/OversizeUI/Controls/SegmentedControl/Support/SegmentedControlPreview.swift +++ b/Sources/OversizeUI/Controls/SegmentedControl/Support/SegmentedControlPreview.swift @@ -77,21 +77,24 @@ struct SegmentedControlPreview: View { .previewDisplayName("Icon and subtitle") VStack { - SegmentedPickerSelector(items, selection: $selection, radius: .small) { item, _ in + SegmentedPickerSelector(items, selection: $selection) { item, _ in Text(item) } + .controlRadius(.small) SegmentedPickerSelector(items, selection: $selection) { item, _ in Text(item) } - SegmentedPickerSelector(items, selection: $selection, radius: .large) { item, _ in + SegmentedPickerSelector(items, selection: $selection) { item, _ in Text(item) } + .controlRadius(.large) - SegmentedPickerSelector(items, selection: $selection, radius: .xLarge) { item, _ in + SegmentedPickerSelector(items, selection: $selection) { item, _ in Text(item) } + .controlRadius(.xLarge) }.previewDisplayName("Radius styles") } .previewLayout(.sizeThatFits) diff --git a/Sources/OversizeUI/Controls/Select/Select.swift b/Sources/OversizeUI/Controls/Select/Select.swift index 364e632..401c7b7 100644 --- a/Sources/OversizeUI/Controls/Select/Select.swift +++ b/Sources/OversizeUI/Controls/Select/Select.swift @@ -20,8 +20,8 @@ public struct Select: View private let content: (Data.Element, Bool) -> Content @State private var selectedIndex: Data.Index? = 0 private let selectionView: (Data.Element) -> Selection - @State var showModal = false - @State var isSelected = false + @State private var showModal = false + @State private var isSelected = false public init(_ label: String, _ data: Data, diff --git a/Sources/OversizeUI/Controls/Surface/Surface.swift b/Sources/OversizeUI/Controls/Surface/Surface.swift index 2974d06..f31ff0b 100644 --- a/Sources/OversizeUI/Controls/Surface/Surface.swift +++ b/Sources/OversizeUI/Controls/Surface/Surface.swift @@ -5,16 +5,19 @@ import SwiftUI -public enum SurfaceColor: Int, CaseIterable { +public enum SurfaceStyle: Int, CaseIterable { case primary case secondary case tertiary + case clear } // swiftlint:disable opening_brace public struct Surface: View { @Environment(\.elevation) private var elevation: Elevation @Environment(\.theme) private var theme: ThemeSettings + @Environment(\.controlRadius) var controlRadius: Radius + @Environment(\.controlPadding) var controlPadding: Space private enum Constants { /// Colors @@ -23,87 +26,44 @@ public struct Surface: View { static var colorTertiary: Color { Color.surfaceTertiary } } - public var padding: Space - private let label: Label - - public var backgroundColor: Color = Constants.colorPrimary - - public var background: SurfaceColor - - public var radius: Radius - - public var border: Color? - private let action: (() -> Void)? + private var background: SurfaceStyle = .primary + private var border: Color? - public init(background: SurfaceColor = .primary, - padding: Space = .medium, - radius: Radius = .medium, - border: Color? = nil, - action: (() -> Void)? = nil, - @ViewBuilder label: () -> Label) - { - self.label = label() - self.padding = padding - self.background = background - self.radius = radius - self.border = border - self.action = action - setBackground(background) - } - - public init(background: SurfaceColor = .primary, - action: (() -> Void)? = nil, + public init(action: (() -> Void)? = nil, @ViewBuilder label: () -> Label) { self.label = label() - padding = .medium - self.background = background - radius = .medium - self.action = action - setBackground(background) - } - - public init( - action: (() -> Void)? = nil, - @ViewBuilder label: () -> Label - ) { - self.label = label() - padding = .medium - background = .primary - radius = .medium self.action = action - setBackground(background) } public var body: some View { - actionableSurface() - } - - @ViewBuilder - private func actionableSurface() -> some View { if action != nil { - Button { - action?() - } label: { - surface - } - .buttonStyle(SurfaceButtonStyle()) + actionableSurface } else { surface } } - public var surface: some View { + private var actionableSurface: some View { + Button { + action?() + } label: { + surface + } + .buttonStyle(SurfaceButtonStyle()) + } + + private var surface: some View { label - .padding(.all, padding.rawValue) + .padding(.all, controlPadding.rawValue) .background( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .circular) .fill(backgroundColor) .overlay( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous) .stroke( border != nil ? border ?? Color.clear @@ -116,16 +76,30 @@ public struct Surface: View { ) } - private mutating func setBackground(_ background: SurfaceColor) { + private var backgroundColor: Color { switch background { case .primary: - backgroundColor = Constants.colorPrimary + return Constants.colorPrimary case .secondary: - backgroundColor = Constants.colorSecondary + return Constants.colorSecondary case .tertiary: - backgroundColor = Constants.colorTertiary + return Constants.colorTertiary + case .clear: + return Color.clear } } + + public func surfaceStyle(_ style: SurfaceStyle) -> Surface { + var control = self + control.background = style + return control + } + + public func surfaceBorderColor(_ border: Color?) -> Surface { + var control = self + control.border = border + return control + } } public struct SurfaceButtonStyle: ButtonStyle { @@ -140,16 +114,19 @@ public struct SurfaceButtonStyle: ButtonStyle { struct Surface_Previews: PreviewProvider { static var previews: some View { Group { - Surface(background: .secondary) { + Surface { Text("Text") .fontStyle(.title3, color: .onSurfaceHighEmphasis) } + .surfaceStyle(.secondary) .previewLayout(.fixed(width: 414, height: 200)) - Surface(background: .primary, border: .surfaceSecondary) { + Surface { Text("Text") .fontStyle(.title3, color: .onSurfaceHighEmphasis) } + .surfaceStyle(.primary) + .surfaceBorderColor(.surfaceSecondary) .preferredColorScheme(.dark) .previewLayout(.fixed(width: 414, height: 200)) @@ -165,12 +142,15 @@ struct Surface_Previews: PreviewProvider { .surface(elevation: .z4) .previewLayout(.fixed(width: 414, height: 200)) - Surface(background: .primary, padding: .zero, radius: .zero) { HStack { + Surface { HStack { Spacer() Text("Text") Spacer() }} + .surfaceStyle(.primary) .elevation(.z2) + .controlRadius(.zero) + .controlPadding(.zero) .previewLayout(.fixed(width: 375, height: 200)) Surface { HStack { @@ -178,6 +158,7 @@ struct Surface_Previews: PreviewProvider { Spacer() }} .elevation(.z1) + .controlPadding(.large) .preferredColorScheme(.dark) .previewLayout(.fixed(width: 320, height: 200)) } diff --git a/Sources/OversizeUI/Controls/Surface/View+Surface.swift b/Sources/OversizeUI/Controls/Surface/View+Surface.swift index eaf00bb..9d3da10 100644 --- a/Sources/OversizeUI/Controls/Surface/View+Surface.swift +++ b/Sources/OversizeUI/Controls/Surface/View+Surface.swift @@ -7,28 +7,30 @@ import SwiftUI // swiftlint:disable opening_brace public extension View { - func surface(elevation: Elevation = .z0, - background: SurfaceColor = .primary, - padding: Space = .medium, - radius: Radius = .medium) -> some View - { - Surface(background: background, - padding: padding, - radius: radius) { self } - .elevation(elevation) + func surface() -> some View { + Surface { self } } func surface(elevation: Elevation) -> some View { - Surface(background: .primary, - padding: .medium, - radius: .medium) { self } + Surface { self } + .elevation(elevation) + } + + func surface(elevation: Elevation, background: SurfaceStyle) -> some View { + Surface { self } + .surfaceStyle(background) .elevation(elevation) } - func surface(elevation: Elevation, background: SurfaceColor) -> some View { - Surface(background: background, - padding: .medium, - radius: .medium) { self } + func surface(elevation: Elevation = .z0, + background: SurfaceStyle = .primary, + padding: Space = .medium, + radius: Radius = .medium) -> some View + { + Surface { self } + .surfaceStyle(background) + .controlPadding(padding) + .controlRadius(radius) .elevation(elevation) } } diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ControlSizeEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/ControlSizeEnvironment.swift index e5aeac6..053d8cc 100644 --- a/Sources/OversizeUI/Extensions/EnvironmentKey/ControlSizeEnvironment.swift +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/ControlSizeEnvironment.swift @@ -13,7 +13,7 @@ public enum ControlSize { case large } -struct ControlSizeKey: EnvironmentKey { +private struct ControlSizeKey: EnvironmentKey { public static var defaultValue: ControlSize = .regular } diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ElevationEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/ElevationEnvironment.swift index 4137fa2..f38217d 100644 --- a/Sources/OversizeUI/Extensions/EnvironmentKey/ElevationEnvironment.swift +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/ElevationEnvironment.swift @@ -5,7 +5,7 @@ import SwiftUI -struct ElevationStateKey: EnvironmentKey { +private struct ElevationStateKey: EnvironmentKey { public static var defaultValue: Elevation = .z0 } @@ -17,7 +17,6 @@ public extension EnvironmentValues { } public extension View { - @ViewBuilder func elevation(_ elevation: Elevation = .z0) -> some View { environment(\.elevation, elevation) } diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/LoadingEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/LoadingEnvironment.swift index 2505458..be41bd8 100644 --- a/Sources/OversizeUI/Extensions/EnvironmentKey/LoadingEnvironment.swift +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/LoadingEnvironment.swift @@ -5,7 +5,7 @@ import SwiftUI -struct LoadingStateKey: EnvironmentKey { +private struct LoadingStateKey: EnvironmentKey { public static var defaultValue: Bool = false } @@ -17,7 +17,6 @@ public extension EnvironmentValues { } public extension View { - @ViewBuilder func loading(_ isLoading: Bool) -> some View { environment(\.isLoading, isLoading) } diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/PaddingEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/PaddingEnvironment.swift new file mode 100644 index 0000000..525ae54 --- /dev/null +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/PaddingEnvironment.swift @@ -0,0 +1,23 @@ +// +// Copyright © 2022 Alexander Romanov +// PaddingEnvironment.swift +// + +import SwiftUI + +private struct ControlPaddingKey: EnvironmentKey { + public static var defaultValue: Space = .medium +} + +public extension EnvironmentValues { + var controlPadding: Space { + get { self[ControlPaddingKey.self] } + set { self[ControlPaddingKey.self] = newValue } + } +} + +public extension View { + func controlPadding(_ space: Space) -> some View { + environment(\.controlPadding, space) + } +} diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/PremiumEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/PremiumEnvironment.swift index 1d5d496..e9b766d 100644 --- a/Sources/OversizeUI/Extensions/EnvironmentKey/PremiumEnvironment.swift +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/PremiumEnvironment.swift @@ -5,7 +5,7 @@ import SwiftUI -struct PremiumStateKey: EnvironmentKey { +private struct PremiumStateKey: EnvironmentKey { public static var defaultValue: Bool = false } @@ -17,7 +17,6 @@ public extension EnvironmentValues { } public extension View { - @ViewBuilder func premiumStatus(_ isPremium: Bool) -> some View { environment(\.isPremium, isPremium) } diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/RadiusEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/RadiusEnvironment.swift new file mode 100644 index 0000000..36ee59d --- /dev/null +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/RadiusEnvironment.swift @@ -0,0 +1,23 @@ +// +// Copyright © 2022 Alexander Romanov +// RadiusEnvironment.swift +// + +import SwiftUI + +private struct ControlRadiusKey: EnvironmentKey { + public static var defaultValue: Radius = .medium +} + +public extension EnvironmentValues { + var controlRadius: Radius { + get { self[ControlRadiusKey.self] } + set { self[ControlRadiusKey.self] = newValue } + } +} + +public extension View { + func controlRadius(_ radius: Radius) -> some View { + environment(\.controlRadius, radius) + } +} diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ScreenSizeEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/ScreenSizeEnvironment.swift new file mode 100644 index 0000000..b65f861 --- /dev/null +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/ScreenSizeEnvironment.swift @@ -0,0 +1,67 @@ +// +// Copyright © 2022 Alexander Romanov +// ScreenSizeEnvironment.swift +// + +import SwiftUI + +public struct ScreenSize { + public let safeAreaWidth: CGFloat + public let safeAreaHeight: CGFloat + public let safeAreaTop: CGFloat + public let safeAreaBottom: CGFloat + public let safeAreaLeading: CGFloat + public let safeAreaTrailing: CGFloat + + public var width: CGFloat { + safeAreaLeading + safeAreaWidth + safeAreaTrailing + } + + public var height: CGFloat { + safeAreaTop + safeAreaHeight + safeAreaBottom + } + + public init(width: CGFloat, height: CGFloat) { + safeAreaWidth = width + safeAreaHeight = height + safeAreaTop = 0 + safeAreaBottom = 0 + safeAreaLeading = 0 + safeAreaTrailing = 0 + } + + public init(width: CGFloat, height: CGFloat, safeAreaTop: CGFloat, safeAreaBottom: CGFloat, safeAreaLeading: CGFloat, safeAreaTrailing: CGFloat) { + safeAreaWidth = width + safeAreaHeight = height + self.safeAreaTop = safeAreaTop + self.safeAreaBottom = safeAreaBottom + self.safeAreaLeading = safeAreaLeading + self.safeAreaTrailing = safeAreaTrailing + } + + public init(geometry: GeometryProxy) { + self.init(width: geometry.size.width, + height: geometry.size.height, + safeAreaTop: geometry.safeAreaInsets.top, + safeAreaBottom: geometry.safeAreaInsets.bottom, + safeAreaLeading: geometry.safeAreaInsets.leading, + safeAreaTrailing: geometry.safeAreaInsets.trailing) + } +} + +private struct ScreenSizeKey: EnvironmentKey { + static let defaultValue = ScreenSize(width: 375, height: 667) +} + +public extension EnvironmentValues { + var screenSize: ScreenSize { + get { self[ScreenSizeKey.self] } + set { self[ScreenSizeKey.self] = newValue } + } +} + +public extension View { + func screenSize(_ geometry: GeometryProxy) -> some View { + environment(\.screenSize, ScreenSize(geometry: geometry)) + } +} diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ThemeEnvironment.swift b/Sources/OversizeUI/Extensions/EnvironmentKey/ThemeEnvironment.swift index 04b359d..e647794 100644 --- a/Sources/OversizeUI/Extensions/EnvironmentKey/ThemeEnvironment.swift +++ b/Sources/OversizeUI/Extensions/EnvironmentKey/ThemeEnvironment.swift @@ -5,7 +5,7 @@ import SwiftUI -struct ThemeStateKey: EnvironmentKey { +private struct ThemeStateKey: EnvironmentKey { public static var defaultValue = ThemeSettings() }