From 427f6dd98ae7bae2905b94e4dc111d04ab2da7e6 Mon Sep 17 00:00:00 2001 From: Alexandr Romanov Date: Tue, 6 Sep 2022 14:09:38 +0300 Subject: [PATCH] Small improvements for components and move modules in other packages --- .../xcschemes/OversizeUI.xcscheme | 2 +- Package.swift | 3 +- Sources/OversizeUI/Controls/Badge/Bage.swift | 4 +- .../OversizeUI/Controls/Button/Button.swift | 44 +-- .../Controls/Button/ButtonLegacy.swift | 8 +- .../Controls/GridSelect/GridSelect.swift | 10 +- Sources/OversizeUI/Controls/HUD/HUD.swift | 2 +- Sources/OversizeUI/Controls/Icon/Icon.swift | 13 +- .../Controls/IconPicker/IconPicker.swift | 6 +- .../LocationPicker/LocationPicker.swift | 4 +- .../NavigationBar/ModalNavigationBar.swift | 184 +++++++++++- .../Controls/PageView/PageView.swift | 217 +++++++++++--- .../Controls/Premium/PremiumLabel.swift | 66 ++++- Sources/OversizeUI/Controls/Row/Row.swift | 38 ++- .../Controls/ScrollView/SectionView.swift | 1 + .../SegmentedControl/SegmentedControl.swift | 8 +- .../OversizeUI/Controls/Select/Select.swift | 8 +- .../Shapes}/AnyShape.swift | 0 .../Controls/Shapes/ScrollArrow.swift | 30 ++ .../Controls/Surface/MaterialSurface.swift | 4 +- .../OversizeUI/Controls/Surface/Surface.swift | 58 ++-- .../Controls/Surface/SurfacePadding.swift | 39 --- .../OversizeUI/Controls/TextBox/TextBox.swift | 58 +++- .../Controls/TextField/TextField.swift | 12 +- .../TextField/TextFieldExtended.swift | 4 +- .../Appearance/Appearance.swift | 2 +- .../Appearance/Theme.swift | 0 .../Appearance/ThemeSettings.swift | 2 +- Sources/OversizeUI/Core/Colors.swift | 176 +++++++++++ .../EnvironmentKeys}/AccentEnvironment.swift | 0 .../BorderedEnvironment.swift | 0 .../ControlBorderShapeEnvironment.swift | 0 .../ControlPaddingEnvironment.swift | 2 +- .../ElevationEnvironment.swift | 0 .../IconStyleEnvironment.swift | 27 ++ .../EnvironmentKeys}/LoadingEnvironment.swift | 0 .../PortraitEnvironment.swift | 0 .../EnvironmentKeys}/PremiumEnvironment.swift | 0 .../EnvironmentKeys}/RadiusEnvironment.swift | 0 .../ScreenSizeEnvironment.swift | 0 .../EnvironmentKeys}/ThemeEnvironment.swift | 0 Sources/OversizeUI/Core/Palette.swift | 3 + .../PreferenceKeys}/ViewOffsetKey.swift | 0 Sources/OversizeUI/Core/Typography.swift | 72 ++++- .../RawRepresentable.swift} | 2 +- Sources/OversizeUI/Extensions/HalfSheet.swift | 213 -------------- .../Extensions/HalfSheet/HalfSheet.swift | 78 +++++ .../LibraryContent/LibraryContent.swift | 11 - .../Extensions/Loading/LoadingViews.swift | 66 ----- .../Extensions/Spacing/Spacing.swift | 20 +- Sources/OversizeUI/Extensions/Unwrap.swift | 11 - .../Extensions/View/View+NavigationView.swift | 12 +- .../View+Platform.swift} | 2 +- .../Extensions/View/View+SafeArea.swift | 31 -- .../Extensions/View/View+Snackbar.swift | 25 -- .../Activity/ActivityViewController.swift | 30 -- .../Apperance/AppearanceSettingView.swift | 220 -------------- .../Modules/Apperance/BorderSettongView.swift | 99 ------- .../Modules/Apperance/FontSettingView.swift | 174 ----------- .../Modules/Apperance/RadiusSettingView.swift | 63 ---- .../Modules/FieldScreen/FieldScreenView.swift | 100 ------- .../Modules/PINCode/PINCodeView.swift | 276 ------------------ 62 files changed, 975 insertions(+), 1565 deletions(-) rename Sources/OversizeUI/{Extensions => Controls/Shapes}/AnyShape.swift (100%) create mode 100644 Sources/OversizeUI/Controls/Shapes/ScrollArrow.swift delete mode 100644 Sources/OversizeUI/Controls/Surface/SurfacePadding.swift rename Sources/OversizeUI/{Extensions => Core}/Appearance/Appearance.swift (92%) rename Sources/OversizeUI/{Extensions => Core}/Appearance/Theme.swift (100%) rename Sources/OversizeUI/{Extensions => Core}/Appearance/ThemeSettings.swift (98%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/AccentEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/BorderedEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/ControlBorderShapeEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/ControlPaddingEnvironment.swift (91%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/ElevationEnvironment.swift (100%) create mode 100644 Sources/OversizeUI/Core/EnvironmentKeys/IconStyleEnvironment.swift rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/LoadingEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/PortraitEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/PremiumEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/RadiusEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/ScreenSizeEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/EnvironmentKey => Core/EnvironmentKeys}/ThemeEnvironment.swift (100%) rename Sources/OversizeUI/{Extensions/PreferenceKey => Core/PreferenceKeys}/ViewOffsetKey.swift (100%) rename Sources/OversizeUI/Extensions/{RawRepresentable/AppStorage.swift => AppStorage/RawRepresentable.swift} (97%) delete mode 100644 Sources/OversizeUI/Extensions/HalfSheet.swift create mode 100644 Sources/OversizeUI/Extensions/HalfSheet/HalfSheet.swift delete mode 100644 Sources/OversizeUI/Extensions/Loading/LoadingViews.swift delete mode 100644 Sources/OversizeUI/Extensions/Unwrap.swift rename Sources/OversizeUI/Extensions/{Platform.swift => View/View+Platform.swift} (97%) delete mode 100644 Sources/OversizeUI/Extensions/View/View+SafeArea.swift delete mode 100644 Sources/OversizeUI/Extensions/View/View+Snackbar.swift delete mode 100644 Sources/OversizeUI/Modules/Activity/ActivityViewController.swift delete mode 100644 Sources/OversizeUI/Modules/Apperance/AppearanceSettingView.swift delete mode 100644 Sources/OversizeUI/Modules/Apperance/BorderSettongView.swift delete mode 100644 Sources/OversizeUI/Modules/Apperance/FontSettingView.swift delete mode 100644 Sources/OversizeUI/Modules/Apperance/RadiusSettingView.swift delete mode 100644 Sources/OversizeUI/Modules/FieldScreen/FieldScreenView.swift delete mode 100644 Sources/OversizeUI/Modules/PINCode/PINCodeView.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/OversizeUI.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/OversizeUI.xcscheme index eab16bf..31c65c8 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/OversizeUI.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/OversizeUI.xcscheme @@ -1,6 +1,6 @@ : View { .padding(.vertical, .xxxSmall) .padding(.horizontal, 6) .background( - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .circular) .fill(color.opacity(0.1)) .overlay( - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .continuous) .stroke( theme.borderSurface diff --git a/Sources/OversizeUI/Controls/Button/Button.swift b/Sources/OversizeUI/Controls/Button/Button.swift index e7ed428..48ac83f 100644 --- a/Sources/OversizeUI/Controls/Button/Button.swift +++ b/Sources/OversizeUI/Controls/Button/Button.swift @@ -46,26 +46,28 @@ public struct OversizeButtonStyle: ButtonStyle { @ViewBuilder func background(for role: ButtonRole?) -> some View { - switch controlBorderShape { - case .capsule: - Capsule() - .fill(backgroundColor(for: role) - .opacity(backgroundOpacity)) - .overlay { - Capsule() - .strokeBorder(Color.onSurfaceHighEmphasis.opacity(0.15), lineWidth: 2) - .opacity(isBordered || theme.borderButtons ? 1 : 0) - } + if type != .tertiary { + switch controlBorderShape { + case .capsule: + Capsule() + .fill(backgroundColor(for: role) + .opacity(backgroundOpacity)) + .overlay { + Capsule() + .strokeBorder(Color.onSurfaceHighEmphasis.opacity(0.15), lineWidth: 2) + .opacity(isBordered || theme.borderButtons ? 1 : 0) + } - case let .roundedRectangle(radius): - RoundedRectangle(cornerRadius: radius != .medium ? radius.rawValue : theme.radius, style: .continuous) - .fill(backgroundColor(for: role) - .opacity(backgroundOpacity)) - .overlay { - RoundedRectangle(cornerRadius: radius != .medium ? radius.rawValue : theme.radius, style: .continuous) - .strokeBorder(Color.onSurfaceHighEmphasis.opacity(0.15), lineWidth: 2) - .opacity(isBordered || theme.borderButtons ? 1 : 0) - } + case let .roundedRectangle(radius): + RoundedRectangle(cornerRadius: radius != .medium ? radius.rawValue : theme.radius, style: .continuous) + .fill(backgroundColor(for: role) + .opacity(backgroundOpacity)) + .overlay { + RoundedRectangle(cornerRadius: radius != .medium ? radius.rawValue : theme.radius, style: .continuous) + .strokeBorder(Color.onSurfaceHighEmphasis.opacity(0.15), lineWidth: 2) + .opacity(isBordered || theme.borderButtons ? 1 : 0) + } + } } } @@ -104,7 +106,7 @@ public struct OversizeButtonStyle: ButtonStyle { if isAccent { return Color.accent } else { - return Color.primary + return Color.onSurfaceHighEmphasis } } case .tertiary: @@ -115,7 +117,7 @@ public struct OversizeButtonStyle: ButtonStyle { if isAccent { return Color.accent } else { - return Color.primary + return Color.onSurfaceHighEmphasis } } } diff --git a/Sources/OversizeUI/Controls/Button/ButtonLegacy.swift b/Sources/OversizeUI/Controls/Button/ButtonLegacy.swift index db5f127..0506e04 100644 --- a/Sources/OversizeUI/Controls/Button/ButtonLegacy.swift +++ b/Sources/OversizeUI/Controls/Button/ButtonLegacy.swift @@ -284,22 +284,22 @@ public struct ButtonStyleExtended: ButtonStyle { public extension Button { /// Changes the appearance of the button - @available(*, deprecated, message: "Use native buttonStyle") + // @available(*, deprecated, message: "Use native buttonStyle") func style(_ style: LegacyButtonType) -> some View { buttonStyle(ButtonStyleExtended(style: style)) } - @available(*, deprecated, message: "Use native buttonStyle") + // @available(*, deprecated, message: "Use native buttonStyle") func style(_ style: LegacyButtonType, size: ButtonSize) -> some View { buttonStyle(ButtonStyleExtended(style: style, size: size)) } - @available(*, deprecated, message: "Use native buttonStyle") + // @available(*, deprecated, message: "Use native buttonStyle") func style(_ style: LegacyButtonType, size: ButtonSize, shadow: Bool) -> some View { buttonStyle(ButtonStyleExtended(style: style, size: size, shadow: shadow)) } - @available(*, deprecated, message: "Use native buttonStyle") + // @available(*, deprecated, message: "Use native buttonStyle") func style(_ style: LegacyButtonType, size: ButtonSize, rounded: ButtonRounded, width: ButtonWidth = .standart, shadow: Bool) -> some View { buttonStyle(ButtonStyleExtended(style: style, size: size, rounded: rounded, width: width, shadow: shadow)) } diff --git a/Sources/OversizeUI/Controls/GridSelect/GridSelect.swift b/Sources/OversizeUI/Controls/GridSelect/GridSelect.swift index 1b0c814..bb0fc8a 100644 --- a/Sources/OversizeUI/Controls/GridSelect/GridSelect.swift +++ b/Sources/OversizeUI/Controls/GridSelect/GridSelect.swift @@ -106,11 +106,11 @@ public struct GridSelect: View private func getSelection(selectionStyle: GridSelectSeletionStyle) -> some View { switch selectionStyle { case .shadowSurface: - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: radius, style: .continuous) .fill(Color.surfacePrimary) .overlay( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: radius, style: .continuous) .stroke(theme.borderControls ? Color.border @@ -119,7 +119,7 @@ public struct GridSelect: View .shadowElevaton(.z2) case .graySurface: - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: radius, style: .continuous) .strokeBorder(Color.onSurfaceMediumEmphasis, lineWidth: 2) case .accentSurface: @@ -136,11 +136,11 @@ public struct GridSelect: View EmptyView() case .surface: - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: radius, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: radius.rawValue, + RoundedRectangle(cornerRadius: radius, style: .continuous) .stroke(theme.borderControls ? Color.border diff --git a/Sources/OversizeUI/Controls/HUD/HUD.swift b/Sources/OversizeUI/Controls/HUD/HUD.swift index 05cc9ea..efdfc47 100644 --- a/Sources/OversizeUI/Controls/HUD/HUD.swift +++ b/Sources/OversizeUI/Controls/HUD/HUD.swift @@ -142,7 +142,7 @@ public struct HUDSurfaceView: View { return AnyShape(Capsule()) case .alert: - return AnyShape(RoundedRectangle(cornerRadius: Radius.medium.rawValue, style: .continuous)) + return AnyShape(RoundedRectangle(cornerRadius: Radius.medium, style: .continuous)) } } diff --git a/Sources/OversizeUI/Controls/Icon/Icon.swift b/Sources/OversizeUI/Controls/Icon/Icon.swift index 829dd69..2e185fd 100644 --- a/Sources/OversizeUI/Controls/Icon/Icon.swift +++ b/Sources/OversizeUI/Controls/Icon/Icon.swift @@ -333,6 +333,7 @@ public struct Icon: View { public var body: some View { Image(name.rawValue, bundle: .module) + .renderingMode(.template) .resizable() .frame(width: iconSize, height: iconSize) .foregroundColor(color) @@ -367,12 +368,12 @@ struct IconAsset_Previews: PreviewProvider { .buttonStyle(.borderedProminent) .controlSize(.large) -// LazyVGrid(columns: grid) { -// ForEach(IconsNames.allCases, id: \.self) { icon in -// Icon(icon) -// .padding(.vertical) -// } -// } + LazyVGrid(columns: grid) { + ForEach(IconsNames.allCases, id: \.self) { icon in + Icon(icon) + .padding(.vertical) + } + } .padding() .previewLayout(.sizeThatFits) } diff --git a/Sources/OversizeUI/Controls/IconPicker/IconPicker.swift b/Sources/OversizeUI/Controls/IconPicker/IconPicker.swift index c9cbde3..6d3a675 100644 --- a/Sources/OversizeUI/Controls/IconPicker/IconPicker.swift +++ b/Sources/OversizeUI/Controls/IconPicker/IconPicker.swift @@ -56,11 +56,11 @@ import SwiftUI .frame(minWidth: 0, maxWidth: .infinity) .padding() .background( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .stroke(theme.borderTextFields ? Color.border @@ -90,7 +90,7 @@ import SwiftUI .frame(width: 24, height: 24, alignment: .center) } .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, style: .continuous) + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .strokeBorder(Color.border, lineWidth: 1) .frame(width: 48, height: 48, alignment: .center) ) diff --git a/Sources/OversizeUI/Controls/LocationPicker/LocationPicker.swift b/Sources/OversizeUI/Controls/LocationPicker/LocationPicker.swift index 4f13cc3..5410c4b 100644 --- a/Sources/OversizeUI/Controls/LocationPicker/LocationPicker.swift +++ b/Sources/OversizeUI/Controls/LocationPicker/LocationPicker.swift @@ -50,11 +50,11 @@ import SwiftUI .frame(minWidth: 0, maxWidth: .infinity) .padding() .background( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .stroke(theme.borderTextFields ? Color.border diff --git a/Sources/OversizeUI/Controls/NavigationBar/ModalNavigationBar.swift b/Sources/OversizeUI/Controls/NavigationBar/ModalNavigationBar.swift index 780ee3e..2988305 100644 --- a/Sources/OversizeUI/Controls/NavigationBar/ModalNavigationBar.swift +++ b/Sources/OversizeUI/Controls/NavigationBar/ModalNavigationBar.swift @@ -6,10 +6,11 @@ import SwiftUI @available(iOS 14.0, *) -public struct ModalNavigationBar: View { - public let leadingBar: () -> LeadingBar? - public let trailingBar: () -> TrailingBar? - public let bottomBar: () -> BottomBar? +public struct ModalNavigationBar: View { + private let leadingBar: () -> LeadingBar? + private let trailingBar: () -> TrailingBar? + private let bottomBar: () -> BottomBar? + private let titleLabel: () -> TitleLabel? @Environment(\.screenSize) var screenSize @@ -33,7 +34,8 @@ public struct ModalNavigationBar LeadingBar, @ViewBuilder trailingBar: @escaping () -> TrailingBar, - @ViewBuilder bottomBar: @escaping () -> BottomBar) + @ViewBuilder bottomBar: @escaping () -> BottomBar, + @ViewBuilder titleLabel: @escaping () -> TitleLabel) { self.title = title self.bigTitle = bigTitle @@ -41,6 +43,7 @@ public struct ModalNavigationBar = .constant(CGPoint(x: 0, y: 0)), + modalityPresent: Bool = true, + alwaysSlideSmallTile: Bool = false, + @ViewBuilder titleLabel: @escaping () -> TitleLabel) + { + self.title = title + self.bigTitle = bigTitle + self.background = background + _offset = offset + self.modalityPresent = modalityPresent + self.alwaysSlideSmallTile = alwaysSlideSmallTile + leadingBar = { nil } + trailingBar = { nil } + bottomBar = { nil } + self.titleLabel = titleLabel + } +} + +public extension ModalNavigationBar + where + TrailingBar == EmptyView +{ + init(title: String, + bigTitle: Bool = true, + background: Color = Color.backgroundPrimary, + offset: Binding = .constant(CGPoint(x: 0, y: 0)), + modalityPresent: Bool = true, + alwaysSlideSmallTile: Bool = false, + @ViewBuilder titleLabel: @escaping () -> TitleLabel, + @ViewBuilder bottomBar: @escaping () -> BottomBar, + @ViewBuilder leadingBar: @escaping () -> LeadingBar) + { + self.title = title + self.bigTitle = bigTitle + self.background = background + _offset = offset + self.modalityPresent = modalityPresent + self.alwaysSlideSmallTile = alwaysSlideSmallTile + self.leadingBar = leadingBar + trailingBar = { nil } + self.bottomBar = bottomBar + self.titleLabel = titleLabel + } +} + +public extension ModalNavigationBar + where + LeadingBar == EmptyView +{ + init(title: String, + bigTitle: Bool = true, + background: Color = Color.backgroundPrimary, + offset: Binding = .constant(CGPoint(x: 0, y: 0)), + modalityPresent: Bool = true, + alwaysSlideSmallTile: Bool = false, + @ViewBuilder titleLabel: @escaping () -> TitleLabel, + @ViewBuilder bottomBar: @escaping () -> BottomBar, + @ViewBuilder trailingBar: @escaping () -> TrailingBar) + { + self.title = title + self.bigTitle = bigTitle + self.background = background + _offset = offset + self.modalityPresent = modalityPresent + self.alwaysSlideSmallTile = alwaysSlideSmallTile + self.trailingBar = trailingBar + leadingBar = { nil } + self.bottomBar = bottomBar + self.titleLabel = titleLabel + } +} + +public extension ModalNavigationBar + where + TrailingBar == EmptyView, + BottomBar == EmptyView +{ + init(title: String, + bigTitle: Bool = true, + background: Color = Color.backgroundPrimary, + offset: Binding = .constant(CGPoint(x: 0, y: 0)), + modalityPresent: Bool = true, + alwaysSlideSmallTile: Bool = false, + @ViewBuilder titleLabel: @escaping () -> TitleLabel, + @ViewBuilder leadingBar: @escaping () -> LeadingBar) + { + self.title = title + self.bigTitle = bigTitle + self.background = background + _offset = offset + self.modalityPresent = modalityPresent + self.alwaysSlideSmallTile = alwaysSlideSmallTile + self.leadingBar = leadingBar + trailingBar = { nil } + bottomBar = { nil } + self.titleLabel = titleLabel + } +} + +public extension ModalNavigationBar + where + LeadingBar == EmptyView, + BottomBar == EmptyView +{ + init(title: String, + bigTitle: Bool = true, + background: Color = Color.backgroundPrimary, + offset: Binding = .constant(CGPoint(x: 0, y: 0)), + modalityPresent: Bool = true, + alwaysSlideSmallTile: Bool = false, + @ViewBuilder titleLabel: @escaping () -> TitleLabel, + @ViewBuilder trailingBar: @escaping () -> TrailingBar) + { + self.title = title + self.bigTitle = bigTitle + self.background = background + _offset = offset + self.modalityPresent = modalityPresent + self.alwaysSlideSmallTile = alwaysSlideSmallTile + self.trailingBar = trailingBar + leadingBar = { nil } + bottomBar = { nil } + self.titleLabel = titleLabel } } diff --git a/Sources/OversizeUI/Controls/PageView/PageView.swift b/Sources/OversizeUI/Controls/PageView/PageView.swift index d47f17c..2c2f364 100644 --- a/Sources/OversizeUI/Controls/PageView/PageView.swift +++ b/Sources/OversizeUI/Controls/PageView/PageView.swift @@ -6,11 +6,11 @@ import SwiftUI #if os(iOS) - public struct PageView: View where Label: View, LeadingBar: View, TrailingBar: View, TopToolbar: View { + public struct PageView: View where Content: View, LeadingBar: View, TrailingBar: View, TopToolbar: View, TitleLabel: View { @Environment(\.screenSize) var screenSize private let title: String? - private let label: Label + private let content: Content private var isModalable = false private var isLargeTitle = false private var isAlwaysSlideSmallTile = false @@ -19,23 +19,25 @@ import SwiftUI private var leadingBar: LeadingBar? private var trailingBar: TrailingBar? private var topToolbar: TopToolbar? + private var titleLabel: TitleLabel? private var backgroundColor: Color = .backgroundPrimary + private var backgroundLinerGradient: LinearGradient? + + private let onOffsetChanged: (CGFloat) -> Void public init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() } public var body: some View { - content - } - - private var content: some View { VStack(spacing: .zero) { - if title != nil || leadingBar != nil || trailingBar != nil || topToolbar != nil { + if title != nil || leadingBar != nil || trailingBar != nil || topToolbar != nil || titleLabel != nil { ModalNavigationBar(title: title ?? "", bigTitle: isLargeTitle, offset: $offset, @@ -43,15 +45,29 @@ import SwiftUI alwaysSlideSmallTile: isAlwaysSlideSmallTile, leadingBar: { leadingBar }, trailingBar: { trailingBar }, - bottomBar: { topToolbar }) + bottomBar: { topToolbar }, + titleLabel: { titleLabel }) .zIndex(999_999_999) } ScrollViewOffset(offset: $offset) { - label + content } } .ignoresSafeArea(edges: .top) - .background(backgroundColor.ignoresSafeArea()) + .background(background.ignoresSafeArea()) + .onChange(of: offset) { offset in + onOffsetChanged(offset.y) + } + } + + var background: some View { + Group { + if let backgroundLinerGradient = backgroundLinerGradient { + backgroundLinerGradient + } else { + backgroundColor + } + } } public func modalable(_ isModalable: Bool = true) -> PageView { @@ -90,6 +106,12 @@ import SwiftUI return control } + public func backgroundLinerGradient(_ gradient: LinearGradient) -> PageView { + var control = self + control.backgroundLinerGradient = gradient + return control + } + public func leadingBar(@ViewBuilder leadingBar: @escaping () -> LeadingBar) -> PageView { var control = self control.leadingBar = leadingBar() @@ -108,7 +130,13 @@ import SwiftUI return control } - public func bottomToolbar(style: PageViewBottomType = .shadow, @ViewBuilder bottomToolbar: @escaping () -> BottomToolbar) -> some View { + public func titleLabel(@ViewBuilder titleLabel: @escaping () -> TitleLabel) -> PageView { + var control = self + control.titleLabel = titleLabel() + return control + } + + public func bottomToolbar(style: PageViewBottomType = .shadow, ignoreSafeArea: Bool = true, @ViewBuilder bottomToolbar: @escaping () -> BottomToolbar) -> some View { VStack(spacing: .zero) { self .overlay( @@ -121,102 +149,203 @@ import SwiftUI endPoint: .bottom) .frame(height: 60) } - - } else { - EmptyView() + } + if style == .none { + VStack { + Spacer() + bottomToolbar() + } } }) - HStack { - Spacer() - bottomToolbar() - Spacer() + if style != .none { + HStack { + Spacer() + bottomToolbar() + Spacer() + } + .background(Color.surfacePrimary.shadowElevaton(style == .shadow ? .z2 : .z0)) } - .paddingContent() - .background(Color.surfacePrimary.shadowElevaton(style == .shadow ? .z2 : .z0)) } - - .ignoresSafeArea(edges: .bottom) + .ignoresSafeArea(edges: ignoreSafeArea ? .bottom : .top) } } public extension PageView { enum PageViewBottomType { - case shadow, gradient + case shadow, gradient, none } } - public extension PageView where LeadingBar == EmptyView { + public extension PageView where LeadingBar == EmptyView, TitleLabel == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() leadingBar = nil + titleLabel = nil } } - public extension PageView where TrailingBar == EmptyView { + public extension PageView where TrailingBar == EmptyView, TitleLabel == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() trailingBar = nil + titleLabel = nil } } - public extension PageView where TrailingBar == EmptyView, LeadingBar == EmptyView { + public extension PageView where TrailingBar == EmptyView, LeadingBar == EmptyView, TitleLabel == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() leadingBar = nil trailingBar = nil + titleLabel = nil } } - public extension PageView where TrailingBar == EmptyView, LeadingBar == EmptyView, TopToolbar == EmptyView { + public extension PageView where TrailingBar == EmptyView, LeadingBar == EmptyView, TopToolbar == EmptyView, TitleLabel == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() leadingBar = nil trailingBar = nil topToolbar = nil + titleLabel = nil } } - public extension PageView where LeadingBar == EmptyView, TopToolbar == EmptyView { + public extension PageView where LeadingBar == EmptyView, TopToolbar == EmptyView, TitleLabel == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() leadingBar = nil topToolbar = nil + titleLabel = nil + } + } + + public extension PageView where TrailingBar == EmptyView, TopToolbar == EmptyView, TitleLabel == EmptyView { + init(_ title: String? = nil, + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) + { + self.title = title + self.onOffsetChanged = onOffsetChanged + self.content = content() + trailingBar = nil + topToolbar = nil + titleLabel = nil + } + } + + public extension PageView where TopToolbar == EmptyView, TitleLabel == EmptyView { + init(_ title: String? = nil, + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) + { + self.title = title + self.onOffsetChanged = onOffsetChanged + self.content = content() + topToolbar = nil + titleLabel = nil + } + } + + public extension PageView where TrailingBar == EmptyView, LeadingBar == EmptyView, TopToolbar == EmptyView { + init(_ title: String? = nil, + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) + { + self.title = title + self.onOffsetChanged = onOffsetChanged + self.content = content() + leadingBar = nil + trailingBar = nil + topToolbar = nil } } public extension PageView where TrailingBar == EmptyView, TopToolbar == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() trailingBar = nil topToolbar = nil } } + public extension PageView where LeadingBar == EmptyView, TopToolbar == EmptyView { + init(_ title: String? = nil, + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) + { + self.title = title + self.onOffsetChanged = onOffsetChanged + self.content = content() + leadingBar = nil + topToolbar = nil + } + } + + public extension PageView where TrailingBar == EmptyView { + init(_ title: String? = nil, + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) + { + self.title = title + self.onOffsetChanged = onOffsetChanged + self.content = content() + trailingBar = nil + } + } + + public extension PageView where LeadingBar == EmptyView { + init(_ title: String? = nil, + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) + { + self.title = title + self.onOffsetChanged = onOffsetChanged + self.content = content() + leadingBar = nil + } + } + public extension PageView where TopToolbar == EmptyView { init(_ title: String? = nil, - @ViewBuilder label: () -> Label) + onOffsetChanged: @escaping (CGFloat) -> Void = { _ in }, + @ViewBuilder content: () -> Content) { self.title = title - self.label = label() + self.onOffsetChanged = onOffsetChanged + self.content = content() topToolbar = nil } } + #endif diff --git a/Sources/OversizeUI/Controls/Premium/PremiumLabel.swift b/Sources/OversizeUI/Controls/Premium/PremiumLabel.swift index ba69c1a..071e86e 100644 --- a/Sources/OversizeUI/Controls/Premium/PremiumLabel.swift +++ b/Sources/OversizeUI/Controls/Premium/PremiumLabel.swift @@ -10,33 +10,55 @@ public enum PrmiumLabelSize { } public struct PremiumLabel: View { - let text: String - let size: PrmiumLabelSize + private let image: Image? + private let text: String + private let size: PrmiumLabelSize + private var isMonohrom = false public init(text: String = "Pro", size: PrmiumLabelSize = .medium) { self.text = text self.size = size + image = nil + } + + public init(image: Image, text: String = "Pro", size: PrmiumLabelSize = .medium) { + self.text = text + self.size = size + self.image = image } public var body: some View { HStack { HStack(alignment: .center, spacing: Space.xxSmall) { + if let image = image { + image + .renderingMode(.template) + .foregroundColor(isMonohrom ? Color(hex: "B75375") : .onPrimaryHighEmphasis) + } Text(text) .font(.system(size: fontSize, weight: .heavy)) - .foregroundColor(.white) + .foregroundColor(isMonohrom ? Color(hex: "B75375") : .onPrimaryHighEmphasis) } - .padding(.horizontal, horizontalPadding) + .padding(.leading, leadingPadding) + .padding(.trailing, trailingPadding) .padding(.vertical, verticalPadding) } - .background( - RoundedRectangle(cornerRadius: radius.rawValue, style: .continuous) - .fill(LinearGradient(gradient: Gradient( - colors: [Color(hex: "EAAB44"), - Color(hex: "D24A44"), - Color(hex: "9C5BA2"), - Color(hex: "4B5B94")]), - startPoint: .topLeading, endPoint: .bottomTrailing)) - ) + .background { + Group { + if isMonohrom { + RoundedRectangle(cornerRadius: radius, style: .continuous) + .fill(Color.onPrimaryHighEmphasis) + } else { + RoundedRectangle(cornerRadius: radius, style: .continuous) + .fill(LinearGradient(gradient: Gradient( + colors: [Color(hex: "EAAB44"), + Color(hex: "D24A44"), + Color(hex: "9C5BA2"), + Color(hex: "4B5B94")]), + startPoint: .topLeading, endPoint: .bottomTrailing)) + } + } + } } var fontSize: CGFloat { @@ -48,7 +70,7 @@ public struct PremiumLabel: View { } } - var horizontalPadding: Space { + var leadingPadding: Space { switch size { case .small: return Space.xxSmall @@ -57,6 +79,15 @@ public struct PremiumLabel: View { } } + var trailingPadding: Space { + switch size { + case .small: + return image == .none ? .xxSmall : .xSmall + case .medium: + return image == .none ? .xSmall : .small + } + } + var verticalPadding: Space { switch size { case .small: @@ -74,13 +105,18 @@ public struct PremiumLabel: View { return Radius.medium } } + + public func monochrom(isMonohrom: Bool = true) -> PremiumLabel { + var control = self + control.isMonohrom = isMonohrom + return control + } } struct PrmiumLabel_Previews: PreviewProvider { static var previews: some View { VStack { PremiumLabel(size: .small) - PremiumLabel() } } diff --git a/Sources/OversizeUI/Controls/Row/Row.swift b/Sources/OversizeUI/Controls/Row/Row.swift index 5214363..44c9ce8 100644 --- a/Sources/OversizeUI/Controls/Row/Row.swift +++ b/Sources/OversizeUI/Controls/Row/Row.swift @@ -20,6 +20,7 @@ public enum RowLeadingType { case icon(_ name: IconsNames) case iconOnSurface(_ name: IconsNames) case image(_ image: Image) + case imageOnSurface(_ image: Image, color: Color? = nil) case systemImage(_ imageName: String) case avatar(_ avatar: AvatarView) case view(_ view: AnyView) @@ -31,6 +32,7 @@ public struct Row: View { @Environment(\.controlPadding) var controlPadding: ControlPadding @Environment(\.multilineTextAlignment) var multilineTextAlignment @Environment(\.isPremium) var premiumStatus + @Environment(\.isAccent) var isAccent private enum Constants { /// Spacing @@ -47,6 +49,8 @@ public struct Row: View { private var isPremiumOption: Bool = false + private var iconBackgroundColor: Color? + public init(_ title: String, subtitle: String? = nil, action: (() -> Void)? = nil) @@ -56,7 +60,7 @@ public struct Row: View { self.action = action } - @available(*, deprecated, message: "Use row modificators") + // @available(*, deprecated, message: "Use row modificators") public init(_ title: String, subtitle: String? = nil, leadingType: RowLeadingType? = nil, @@ -90,7 +94,7 @@ public struct Row: View { @ViewBuilder private func content(_ textAlignment: TextAlignment) -> some View { VStack(alignment: .leading) { - HStack(spacing: .xSmall) { + HStack(spacing: .small) { if let leadingType = leadingType { leading(leadingType) } @@ -138,6 +142,18 @@ public struct Row: View { Icon(icon) } .surfaceStyle(.secondary) + .surfaceBackgroundColor(iconBackgroundColor) + .padding(.trailing, Constants.spacingIconAndText) + .controlPadding(.xxSmall) + + case let .imageOnSurface(image, color): + Surface { + image + .renderingMode(.template) + .foregroundColor(color) + } + .surfaceStyle(.secondary) + .surfaceBackgroundColor(iconBackgroundColor) .padding(.trailing, Constants.spacingIconAndText) .controlPadding(.xxSmall) @@ -182,12 +198,12 @@ public struct Row: View { case let .checkbox(isOn: isOn): ZStack { - RoundedRectangle(cornerRadius: Radius.small.rawValue, style: .continuous) + RoundedRectangle(cornerRadius: Radius.small, style: .continuous) .stroke(Color.onSurfaceDisabled, lineWidth: 4) .frame(width: 24, height: 24) .opacity(isOn.wrappedValue ? 0 : 1) - RoundedRectangle(cornerRadius: Radius.small.rawValue, style: .continuous).fill(Color.accent) + RoundedRectangle(cornerRadius: Radius.small, style: .continuous).fill(Color.accent) .frame(width: 24, height: 24) .opacity(isOn.wrappedValue ? 1 : 0) @@ -231,9 +247,9 @@ public struct Row: View { } private var text: some View { - VStack(alignment: textAlignment) { + VStack(alignment: textAlignment, spacing: .xxxSmall) { Text(title) - .headline() + .headline(.semibold) .foregroundColor(.onSurfaceHighEmphasis) if let subtitle = subtitle { Text(subtitle) @@ -282,17 +298,23 @@ public struct Row: View { return control } - public func rowLeading(_ leading: RowLeadingType) -> Row { + public func rowLeading(_ leading: RowLeadingType?) -> Row { var control = self control.leadingType = leading return control } - public func rowTrailing(_ trailing: RowTrailingType) -> Row { + public func rowTrailing(_ trailing: RowTrailingType?) -> Row { var control = self control.trallingType = trailing return control } + + public func rowIconBackgroundColor(_ color: Color?) -> Row { + var control = self + control.iconBackgroundColor = color + return control + } } public extension View { diff --git a/Sources/OversizeUI/Controls/ScrollView/SectionView.swift b/Sources/OversizeUI/Controls/ScrollView/SectionView.swift index 1130d04..29634dc 100644 --- a/Sources/OversizeUI/Controls/ScrollView/SectionView.swift +++ b/Sources/OversizeUI/Controls/ScrollView/SectionView.swift @@ -34,6 +34,7 @@ public struct SectionView: View { Surface { content .padding(.vertical, verticalPadding) + .controlPadding(.medium) } .controlPadding(.zero) .clipShape( diff --git a/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift b/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift index 4c28222..632748b 100644 --- a/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift +++ b/Sources/OversizeUI/Controls/SegmentedControl/SegmentedControl.swift @@ -204,11 +204,11 @@ public struct SegmentedPickerSelector: V case .graySurface: if style.unseletionStyle == .clean { - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .continuous) .stroke(theme.borderControls ? Color.border @@ -236,11 +236,11 @@ public struct SegmentedPickerSelector: V EmptyView() case .surface: - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .continuous) .stroke(theme.borderControls ? Color.border diff --git a/Sources/OversizeUI/Controls/Select/Select.swift b/Sources/OversizeUI/Controls/Select/Select.swift index fe1d1ad..3970186 100644 --- a/Sources/OversizeUI/Controls/Select/Select.swift +++ b/Sources/OversizeUI/Controls/Select/Select.swift @@ -52,11 +52,11 @@ public struct Select: View .frame(minWidth: 0, maxWidth: .infinity) .padding() .background( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .stroke(theme.borderTextFields ? Color.border @@ -85,8 +85,8 @@ public struct Select: View label: { content(data[index], selectedIndex == index) - .fontStyle(.headline, - color: .onSurfaceHighEmphasis) + .headline() + .foregroundOnSurfaceHighEmphasis() }) } diff --git a/Sources/OversizeUI/Extensions/AnyShape.swift b/Sources/OversizeUI/Controls/Shapes/AnyShape.swift similarity index 100% rename from Sources/OversizeUI/Extensions/AnyShape.swift rename to Sources/OversizeUI/Controls/Shapes/AnyShape.swift diff --git a/Sources/OversizeUI/Controls/Shapes/ScrollArrow.swift b/Sources/OversizeUI/Controls/Shapes/ScrollArrow.swift new file mode 100644 index 0000000..da59be0 --- /dev/null +++ b/Sources/OversizeUI/Controls/Shapes/ScrollArrow.swift @@ -0,0 +1,30 @@ +// +// Copyright © 2022 Alexander Romanov +// ScrollArrow.swift +// + +import SwiftUI + +public struct ScrollArrow: Shape { + private var width: CGFloat + private var offset: CGFloat + + public var animatableData: CGFloat { + get { offset } + set { offset = newValue } + } + + public init(width: CGFloat, offset: CGFloat) { + self.width = width + self.offset = offset + } + + public func path(in _: CGRect) -> Path { + Path { path in + path.move(to: .zero) + path.addLine(to: CGPoint(x: width / 2, y: offset)) + path.move(to: CGPoint(x: width / 2, y: offset)) + path.addLine(to: CGPoint(x: width, y: 0)) + } + } +} diff --git a/Sources/OversizeUI/Controls/Surface/MaterialSurface.swift b/Sources/OversizeUI/Controls/Surface/MaterialSurface.swift index 2deb1db..33c4543 100644 --- a/Sources/OversizeUI/Controls/Surface/MaterialSurface.swift +++ b/Sources/OversizeUI/Controls/Surface/MaterialSurface.swift @@ -61,7 +61,7 @@ import SwiftUI .padding(.horizontal, controlPadding.horizontal) .padding(.vertical, controlPadding.vertical) .background(backgroundMaterial, - in: RoundedRectangle(cornerRadius: controlRadius.rawValue, style: .continuous)) + in: RoundedRectangle(cornerRadius: controlRadius, style: .continuous)) .overlay(overlayView) .shadowElevaton(elevation) } else { @@ -117,7 +117,7 @@ import SwiftUI } private var legacyBackgroundView: some View { - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .circular) .fill(legacyBackgroundViewColor) } diff --git a/Sources/OversizeUI/Controls/Surface/Surface.swift b/Sources/OversizeUI/Controls/Surface/Surface.swift index a45db24..f014278 100644 --- a/Sources/OversizeUI/Controls/Surface/Surface.swift +++ b/Sources/OversizeUI/Controls/Surface/Surface.swift @@ -18,6 +18,7 @@ public struct Surface: View { @Environment(\.theme) private var theme: ThemeSettings @Environment(\.controlRadius) var controlRadius: Radius @Environment(\.controlPadding) var controlPadding: ControlPadding + @Environment(\.isAccent) private var isAccent private enum Constants { /// Colors @@ -29,7 +30,9 @@ public struct Surface: View { private let label: Label private let action: (() -> Void)? private var background: SurfaceStyle = .primary + private var backgroundColor: Color? private var border: Color? + private var borderWidth: CGFloat? public init(action: (() -> Void)? = nil, @ViewBuilder label: () -> Label) @@ -60,33 +63,39 @@ public struct Surface: View { .padding(.horizontal, controlPadding.horizontal) .padding(.vertical, controlPadding.vertical) .background( - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .circular) - .fill(backgroundColor) + .fill(surfaceBackgroundColor) .overlay( - RoundedRectangle(cornerRadius: controlRadius.rawValue, + RoundedRectangle(cornerRadius: controlRadius, style: .continuous) .stroke( border != nil ? border ?? Color.clear : theme.borderSurface ? Color.border - : backgroundColor, lineWidth: CGFloat(theme.borderSize) + : surfaceBackgroundColor, lineWidth: borderWidth != nil ? borderWidth ?? 0 : CGFloat(theme.borderSize) ) ) .shadowElevaton(elevation) ) } - private var backgroundColor: Color { - switch background { - case .primary: - return Constants.colorPrimary - case .secondary: - return Constants.colorSecondary - case .tertiary: - return Constants.colorTertiary - case .clear: - return Color.clear + private var surfaceBackgroundColor: Color { + if let backgroundColor = backgroundColor { + return backgroundColor + } else if isAccent { + return Color.accent + } else { + switch background { + case .primary: + return Constants.colorPrimary + case .secondary: + return Constants.colorSecondary + case .tertiary: + return Constants.colorTertiary + case .clear: + return Color.clear + } } } @@ -96,9 +105,16 @@ public struct Surface: View { return control } - public func surfaceBorderColor(_ border: Color? = Color.border) -> Surface { + public func surfaceBorderColor(_ border: Color? = Color.border, width: CGFloat? = nil) -> Surface { var control = self control.border = border + control.borderWidth = width + return control + } + + public func surfaceBackgroundColor(_ color: Color?) -> Surface { + var control = self + control.backgroundColor = color return control } } @@ -131,18 +147,6 @@ struct Surface_Previews: PreviewProvider { .preferredColorScheme(.dark) .previewLayout(.fixed(width: 414, height: 200)) - Text("Text") - .surface(elevation: .z4) - .previewLayout(.fixed(width: 414, height: 200)) - - HStack { - Text("Text") - - Spacer() - } - .surface(elevation: .z4) - .previewLayout(.fixed(width: 414, height: 200)) - Surface { HStack { Spacer() Text("Text") diff --git a/Sources/OversizeUI/Controls/Surface/SurfacePadding.swift b/Sources/OversizeUI/Controls/Surface/SurfacePadding.swift deleted file mode 100644 index bacf1a9..0000000 --- a/Sources/OversizeUI/Controls/Surface/SurfacePadding.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// SurfacePadding.swift -// - -// import SwiftUI -// -// public struct SurfacePaddingModifier: ViewModifier { -// -// private struct Constants { -// -// /// Size -// static var paddingMedium: CGFloat { return Space.medium } -// static var paddingSmall: CGFloat { return Space.small } -// static var paddingXXXSmall: CGFloat { return Space.xxxSmall } -// static var paddingXXSmall: CGFloat { return Space.xxSmall } -// static var paddingZero: CGFloat { return .zero } -// } -// -// public var padding: SurfacePadding = .xxxSmall -// -// public func body(content: Content) -> some View { -// content -// .padding(.all, -// padding == .xxxSmall ? Constants.paddingXXXSmall -// : padding == .xxSmall ? Constants.paddingXXSmall -// : padding == .small ? Constants.paddingSmall -// : padding == .medium ? Constants.paddingMedium -// : Constants.paddingZero -// ) -// -// } -// } -// -// public extension Surface { -// func paddingContent(_ padding: SurfacePadding) -> some View { -// modifier(SurfacePaddingModifier(padding: padding)) -// } -// } diff --git a/Sources/OversizeUI/Controls/TextBox/TextBox.swift b/Sources/OversizeUI/Controls/TextBox/TextBox.swift index 70acd26..aa26dcb 100644 --- a/Sources/OversizeUI/Controls/TextBox/TextBox.swift +++ b/Sources/OversizeUI/Controls/TextBox/TextBox.swift @@ -10,31 +10,54 @@ public struct TextBox: View { let title: String let subtitle: String? + let spacing: Space? + var size: TextBoxSize = .medium - public init(title: String, subtitle: String?) { + public enum TextBoxSize { + case small, medium, large + } + + public init(title: String, subtitle: String?, spacing: Space? = nil) { self.title = title self.subtitle = subtitle + self.spacing = spacing } public init(title: String) { self.title = title subtitle = nil + spacing = .medium } public var body: some View { - VStack(alignment: vStackAlignment, spacing: .medium) { - Text(title) - .fontStyle(.title3, color: .onSurfaceHighEmphasis) + VStack(alignment: textStackAlignment, spacing: textSpacing) { + titleText if let subtitle = subtitle { Text(subtitle) - .fontStyle(.body, color: .onSurfaceHighEmphasis) + .body() + .foregroundColor(.onSurfaceHighEmphasis) } } .multilineTextAlignment(multilineTextAlignment) } - var vStackAlignment: HorizontalAlignment { + var textSpacing: Space { + if let spacing = spacing { + return spacing + } else { + switch size { + case .small: + return .xxxSmall + case .medium: + return .small + case .large: + return .medium + } + } + } + + private var textStackAlignment: HorizontalAlignment { switch multilineTextAlignment { case .leading: return .leading @@ -44,4 +67,27 @@ public struct TextBox: View { return .trailing } } + + var titleText: some View { + Group { + switch size { + case .small: + Text(title) + .headline(true) + case .medium: + Text(title) + .title2(true) + case .large: + Text(title) + .title(true) + } + } + .foregroundOnSurfaceHighEmphasis() + } + + public func textBoxSize(_ size: TextBoxSize) -> TextBox { + var control = self + control.size = size + return control + } } diff --git a/Sources/OversizeUI/Controls/TextField/TextField.swift b/Sources/OversizeUI/Controls/TextField/TextField.swift index dbc970b..3ddcbfa 100644 --- a/Sources/OversizeUI/Controls/TextField/TextField.swift +++ b/Sources/OversizeUI/Controls/TextField/TextField.swift @@ -25,11 +25,11 @@ public struct DefaultPlaceholderTextFieldStyle: TextFieldStyle { } .padding() .background( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .stroke(theme.borderTextFields ? Color.border @@ -65,11 +65,11 @@ public struct OverPlaceholderTextFieldStyle: TextFieldStyle { } .padding() .background( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .stroke(theme.borderTextFields ? Color.border @@ -106,11 +106,11 @@ public struct InsidePlaceholderTextFieldStyle: TextFieldStyle { } .padding() .background( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .fill(Color.surfaceSecondary) .overlay( - RoundedRectangle(cornerRadius: Radius.medium.rawValue, + RoundedRectangle(cornerRadius: Radius.medium, style: .continuous) .stroke(theme.borderTextFields ? Color.border diff --git a/Sources/OversizeUI/Controls/TextField/TextFieldExtended.swift b/Sources/OversizeUI/Controls/TextField/TextFieldExtended.swift index 727f0ce..a430704 100644 --- a/Sources/OversizeUI/Controls/TextField/TextFieldExtended.swift +++ b/Sources/OversizeUI/Controls/TextField/TextFieldExtended.swift @@ -106,10 +106,10 @@ public struct TextFieldExtended: View { }.padding() .overlay( - RoundedRectangle(cornerRadius: 12, style: .continuous) + RoundedRectangle(cornerRadius: .medium, style: .continuous) .stroke(focused ? Color.accent : Color.surfacePrimary, lineWidth: 4) - ).background(RoundedRectangle(cornerRadius: 12, style: .continuous) + ).background(RoundedRectangle(cornerRadius: .medium, style: .continuous) .fill(focused ? Color.surfacePrimary : Color.surfaceSecondary)) .cornerRadius(Radius.medium) diff --git a/Sources/OversizeUI/Extensions/Appearance/Appearance.swift b/Sources/OversizeUI/Core/Appearance/Appearance.swift similarity index 92% rename from Sources/OversizeUI/Extensions/Appearance/Appearance.swift rename to Sources/OversizeUI/Core/Appearance/Appearance.swift index f0ce0a4..09724b2 100644 --- a/Sources/OversizeUI/Extensions/Appearance/Appearance.swift +++ b/Sources/OversizeUI/Core/Appearance/Appearance.swift @@ -43,5 +43,5 @@ public enum Appearance: Int { } } - static var allCases: [Appearance] = [.system, .light, .dark] + public static var allCases: [Appearance] = [.system, .light, .dark] } diff --git a/Sources/OversizeUI/Extensions/Appearance/Theme.swift b/Sources/OversizeUI/Core/Appearance/Theme.swift similarity index 100% rename from Sources/OversizeUI/Extensions/Appearance/Theme.swift rename to Sources/OversizeUI/Core/Appearance/Theme.swift diff --git a/Sources/OversizeUI/Extensions/Appearance/ThemeSettings.swift b/Sources/OversizeUI/Core/Appearance/ThemeSettings.swift similarity index 98% rename from Sources/OversizeUI/Extensions/Appearance/ThemeSettings.swift rename to Sources/OversizeUI/Core/Appearance/ThemeSettings.swift index 3b27aa4..7cc6d0a 100644 --- a/Sources/OversizeUI/Extensions/Appearance/ThemeSettings.swift +++ b/Sources/OversizeUI/Core/Appearance/ThemeSettings.swift @@ -22,7 +22,7 @@ public enum ThemeSettingsNames { public static var radius = "Settings.Radius" } -public class ThemeSettings { +public class ThemeSettings: ObservableObject { public init() {} @AppStorage(ThemeSettingsNames.appearance) public var appearance: Appearance = .light diff --git a/Sources/OversizeUI/Core/Colors.swift b/Sources/OversizeUI/Core/Colors.swift index e51c668..75c6688 100644 --- a/Sources/OversizeUI/Core/Colors.swift +++ b/Sources/OversizeUI/Core/Colors.swift @@ -118,6 +118,182 @@ public extension Color { } } +// MARK: - Foreground Color Extension + +public extension View { + func foregroundOnPrimaryHighEmphasis() -> some View { + foregroundColor(Color.onPrimaryHighEmphasis) + } + + func foregroundOnPrimaryMediumEmphasis() -> some View { + foregroundColor(Color.onPrimaryMediumEmphasis) + } + + func foregroundOnPrimaryDisabled() -> some View { + foregroundColor(Color.onPrimaryDisabled) + } + + func foregroundAccent() -> some View { + foregroundColor(Color.accent) + } + + func foregroundBackgroundPrimary() -> some View { + foregroundColor(Color.backgroundPrimary) + } + + func foregroundBackgroundSecondary() -> some View { + foregroundColor(Color.backgroundSecondary) + } + + func foregroundBackgroundTertiary() -> some View { + foregroundColor(Color.backgroundTertiary) + } + + func foregroundOnBackgroundHighEmphasis() -> some View { + foregroundColor(Color.onBackgroundHighEmphasis) + } + + func foregroundOnBackgroundMediumEmphasis() -> some View { + foregroundColor(Color.onBackgroundMediumEmphasis) + } + + func foregroundOnBackgroundDisabled() -> some View { + foregroundColor(Color.onBackgroundDisabled) + } + + func foregroundSurfacePrimary() -> some View { + foregroundColor(Color.surfacePrimary) + } + + func foregroundSurfaceSecondary() -> some View { + foregroundColor(Color.surfaceSecondary) + } + + func foregroundSurfaceTertiary() -> some View { + foregroundColor(Color.surfaceTertiary) + } + + func foregroundOnSurfaceHighEmphasis() -> some View { + foregroundColor(Color.onSurfaceHighEmphasis) + } + + func foregroundOnSurfaceMediumEmphasis() -> some View { + foregroundColor(Color.onSurfaceMediumEmphasis) + } + + func foregroundOnSurfaceDisabled() -> some View { + foregroundColor(Color.onSurfaceDisabled) + } + + func foregroundError() -> some View { + foregroundColor(Color.error) + } + + func foregroundSuccess() -> some View { + foregroundColor(Color.success) + } + + func foregroundWarning() -> some View { + foregroundColor(Color.warning) + } + + func foregroundLink() -> some View { + foregroundColor(Color.link) + } + + func foregroundBorder() -> some View { + foregroundColor(Color.border) + } +} + +// MARK: - Fill Color Extension + +public extension Shape { + func fillOnPrimaryHighEmphasis() -> some View { + fill(Color.onPrimaryHighEmphasis) + } + + func fillOnPrimaryMediumEmphasis() -> some View { + fill(Color.onPrimaryMediumEmphasis) + } + + func fillOnPrimaryDisabled() -> some View { + fill(Color.onPrimaryDisabled) + } + + func fillAccent() -> some View { + fill(Color.accent) + } + + func fillBackgroundPrimary() -> some View { + fill(Color.backgroundPrimary) + } + + func fillBackgroundSecondary() -> some View { + fill(Color.backgroundSecondary) + } + + func fillBackgroundTertiary() -> some View { + fill(Color.backgroundTertiary) + } + + func fillOnBackgroundHighEmphasis() -> some View { + fill(Color.onBackgroundHighEmphasis) + } + + func fillOnBackgroundMediumEmphasis() -> some View { + fill(Color.onBackgroundMediumEmphasis) + } + + func fillOnBackgroundDisabled() -> some View { + fill(Color.onBackgroundDisabled) + } + + func fillSurfacePrimary() -> some View { + fill(Color.surfacePrimary) + } + + func fillSurfaceSecondary() -> some View { + fill(Color.surfaceSecondary) + } + + func fillSurfaceTertiary() -> some View { + fill(Color.surfaceTertiary) + } + + func fillOnSurfaceHighEmphasis() -> some View { + fill(Color.onSurfaceHighEmphasis) + } + + func fillOnSurfaceMediumEmphasis() -> some View { + fill(Color.onSurfaceMediumEmphasis) + } + + func fillOnSurfaceDisabled() -> some View { + fill(Color.onSurfaceDisabled) + } + + func fillError() -> some View { + fill(Color.error) + } + + func fillSuccess() -> some View { + fill(Color.success) + } + + func fillWarning() -> some View { + fill(Color.warning) + } + + func fillLink() -> some View { + fill(Color.link) + } + + func fillBorder() -> some View { + fill(Color.border) + } +} + struct Color_Previews: PreviewProvider { static var previews: some View { VStack(alignment: .leading, spacing: 10) { diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/AccentEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/AccentEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/AccentEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/AccentEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/BorderedEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/BorderedEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/BorderedEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/BorderedEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ControlBorderShapeEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/ControlBorderShapeEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/ControlBorderShapeEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/ControlBorderShapeEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ControlPaddingEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/ControlPaddingEnvironment.swift similarity index 91% rename from Sources/OversizeUI/Extensions/EnvironmentKey/ControlPaddingEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/ControlPaddingEnvironment.swift index 339bcf0..6bde063 100644 --- a/Sources/OversizeUI/Extensions/EnvironmentKey/ControlPaddingEnvironment.swift +++ b/Sources/OversizeUI/Core/EnvironmentKeys/ControlPaddingEnvironment.swift @@ -36,7 +36,7 @@ public extension View { environment(\.controlPadding, ControlPadding(all)) } - func controlPadding(horizontal: Space, vertical: Space) -> some View { + func controlPadding(horizontal: Space = .medium, vertical: Space = .medium) -> some View { environment(\.controlPadding, ControlPadding(horizontal: horizontal, vertical: vertical)) } } diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ElevationEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/ElevationEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/ElevationEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/ElevationEnvironment.swift diff --git a/Sources/OversizeUI/Core/EnvironmentKeys/IconStyleEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/IconStyleEnvironment.swift new file mode 100644 index 0000000..59dd4ca --- /dev/null +++ b/Sources/OversizeUI/Core/EnvironmentKeys/IconStyleEnvironment.swift @@ -0,0 +1,27 @@ +// +// Copyright © 2022 Alexander Romanov +// IconStyleEnvironment.swift +// + +import SwiftUI + +public enum IconStyle { + case line, solid, duotone +} + +private struct IconStyleKey: EnvironmentKey { + public static var defaultValue: IconStyle = .line +} + +public extension EnvironmentValues { + var iconStyle: IconStyle { + get { self[IconStyleKey.self] } + set { self[IconStyleKey.self] = newValue } + } +} + +public extension View { + func iconStyle(_ iconStyle: IconStyle) -> some View { + environment(\.iconStyle, iconStyle) + } +} diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/LoadingEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/LoadingEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/LoadingEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/LoadingEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/PortraitEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/PortraitEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/PortraitEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/PortraitEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/PremiumEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/PremiumEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/PremiumEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/PremiumEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/RadiusEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/RadiusEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/RadiusEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/RadiusEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ScreenSizeEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/ScreenSizeEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/ScreenSizeEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/ScreenSizeEnvironment.swift diff --git a/Sources/OversizeUI/Extensions/EnvironmentKey/ThemeEnvironment.swift b/Sources/OversizeUI/Core/EnvironmentKeys/ThemeEnvironment.swift similarity index 100% rename from Sources/OversizeUI/Extensions/EnvironmentKey/ThemeEnvironment.swift rename to Sources/OversizeUI/Core/EnvironmentKeys/ThemeEnvironment.swift diff --git a/Sources/OversizeUI/Core/Palette.swift b/Sources/OversizeUI/Core/Palette.swift index 6e551a5..ec7bcbc 100644 --- a/Sources/OversizeUI/Core/Palette.swift +++ b/Sources/OversizeUI/Core/Palette.swift @@ -13,6 +13,7 @@ public enum Palette: String { case blue case pink case gray + case violet case black public var color: Color { @@ -31,6 +32,8 @@ public enum Palette: String { return Color.pink case .gray: return Color.gray + case .violet: + return Color.purple case .black: return Color.black } diff --git a/Sources/OversizeUI/Extensions/PreferenceKey/ViewOffsetKey.swift b/Sources/OversizeUI/Core/PreferenceKeys/ViewOffsetKey.swift similarity index 100% rename from Sources/OversizeUI/Extensions/PreferenceKey/ViewOffsetKey.swift rename to Sources/OversizeUI/Core/PreferenceKeys/ViewOffsetKey.swift diff --git a/Sources/OversizeUI/Core/Typography.swift b/Sources/OversizeUI/Core/Typography.swift index e6cee94..b8eee1b 100644 --- a/Sources/OversizeUI/Core/Typography.swift +++ b/Sources/OversizeUI/Core/Typography.swift @@ -26,8 +26,9 @@ public struct Typography: ViewModifier { @Environment(\.theme) private var theme: ThemeSettings @Environment(\.isLoading) var isLoading - public let fontStyle: Font.TextStyle - public let isBold: Bool? + private let fontStyle: Font.TextStyle + private let isBold: Bool? + private let weight: Font.Weight? private var fontDesign: Font.Design { switch fontStyle { @@ -43,19 +44,24 @@ public struct Typography: ViewModifier { } private var fontWeight: Font.Weight { - switch fontStyle { - case .largeTitle, .title: - return isBold ?? true ? .heavy : .regular - case .headline: - return isBold ?? true ? .bold : .semibold - default: - return isBold ?? false ? .bold : .regular + if let weight = weight { + return weight + } else { + switch fontStyle { + case .largeTitle, .title: + return isBold ?? true ? .heavy : .regular + case .headline: + return isBold ?? true ? .bold : .semibold + default: + return isBold ?? false ? .bold : .regular + } } } - public init(fontStyle: Font.TextStyle, isBold: Bool? = nil) { + public init(fontStyle: Font.TextStyle, isBold: Bool? = nil, weight: Font.Weight? = nil) { self.fontStyle = fontStyle self.isBold = isBold + self.weight = weight } public func body(content: Content) -> some View { @@ -108,6 +114,50 @@ public extension View { func caption2(_ bold: Bool = false) -> some View { modifier(Typography(fontStyle: .caption2, isBold: bold)) } + + func largeTitle(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .largeTitle, weight: weight)) + } + + func title(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .title, weight: weight)) + } + + func title2(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .title2, weight: weight)) + } + + func title3(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .title3, weight: weight)) + } + + func headline(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .headline, weight: weight)) + } + + func subheadline(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .subheadline, weight: weight)) + } + + func body(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .body, weight: weight)) + } + + func callout(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .callout, weight: weight)) + } + + func footnote(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .footnote, weight: weight)) + } + + func caption(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .caption, weight: weight)) + } + + func caption2(_ weight: Font.Weight) -> some View { + modifier(Typography(fontStyle: .caption2, weight: weight)) + } } public extension View { @@ -115,7 +165,7 @@ public extension View { modifier(Typography(fontStyle: style)) } - @available(*, deprecated, message: "Use native color modificator") + // @available(*, deprecated, message: "Use native color modificator") func fontStyle(_ style: Font.TextStyle, color: Color) -> some View { modifier(Typography(fontStyle: style)) .foregroundColor(color) diff --git a/Sources/OversizeUI/Extensions/RawRepresentable/AppStorage.swift b/Sources/OversizeUI/Extensions/AppStorage/RawRepresentable.swift similarity index 97% rename from Sources/OversizeUI/Extensions/RawRepresentable/AppStorage.swift rename to Sources/OversizeUI/Extensions/AppStorage/RawRepresentable.swift index ccca3ff..54fe9ad 100644 --- a/Sources/OversizeUI/Extensions/RawRepresentable/AppStorage.swift +++ b/Sources/OversizeUI/Extensions/AppStorage/RawRepresentable.swift @@ -1,6 +1,6 @@ // // Copyright © 2022 Alexander Romanov -// AppStorage.swift +// RawRepresentable.swift // import SwiftUI diff --git a/Sources/OversizeUI/Extensions/HalfSheet.swift b/Sources/OversizeUI/Extensions/HalfSheet.swift deleted file mode 100644 index 88cd815..0000000 --- a/Sources/OversizeUI/Extensions/HalfSheet.swift +++ /dev/null @@ -1,213 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// HalfSheet.swift -// - -import SwiftUI - -public enum SheetSize { - case medium, large -} - -public extension View { - @_disfavoredOverload - @ViewBuilder func sheet(isPresented: Binding, - detents: [SheetSize] = [.medium, .large], - smallestUndimmedDetentIdentifier: SheetSize = .medium, - prefersScrollingExpandsWhenScrolledToEdge: Bool = false, - prefersEdgeAttachedInCompactHeight: Bool = true, - @ViewBuilder content: @escaping () -> T) -> some View - { - #if os(iOS) - if #available(iOS 15, *) { - modifier(HalfSheet(isPresented: isPresented, - detents: detents, - smallestUndimmedDetentIdentifier: smallestUndimmedDetentIdentifier, - prefersScrollingExpandsWhenScrolledToEdge: prefersScrollingExpandsWhenScrolledToEdge, - prefersEdgeAttachedInCompactHeight: prefersEdgeAttachedInCompactHeight, - content: content)) - } else { - sheet(isPresented: isPresented, content: content) - } - #else - sheet(isPresented: isPresented, content: content) - #endif - } -} - -// swiftlint:disable line_length -#if os(iOS) - @available(iOS 15.0, *) - public struct HalfSheet: ViewModifier { - let sheetContent: T - @Binding var isPresented: Bool - let detents: [UISheetPresentationController.Detent] - let smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? - let prefersScrollingExpandsWhenScrolledToEdge: Bool - let prefersEdgeAttachedInCompactHeight: Bool - - public init(isPresented: Binding, detents: [SheetSize] = [.medium, .large], smallestUndimmedDetentIdentifier: SheetSize = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> T) { - sheetContent = content() - var detentsTemp: [UISheetPresentationController.Detent] = [] - for detent in detents { - if detent == .medium { - detentsTemp.append(.medium()) - } - if detent == .large { - detentsTemp.append(.large()) - } - } - self.detents = detentsTemp - switch smallestUndimmedDetentIdentifier { - case .medium: - self.smallestUndimmedDetentIdentifier = .medium - case .large: - self.smallestUndimmedDetentIdentifier = .large - } - self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight - self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge - _isPresented = isPresented - } - - public func body(content: Content) -> some View { - ZStack { - content - HalfSheetUI(isPresented: $isPresented, detents: detents, smallestUndimmedDetentIdentifier: smallestUndimmedDetentIdentifier, prefersScrollingExpandsWhenScrolledToEdge: prefersScrollingExpandsWhenScrolledToEdge, prefersEdgeAttachedInCompactHeight: prefersEdgeAttachedInCompactHeight, content: { sheetContent }).frame(width: 0, height: 0) - } - } - } - - // swiftlint:disable type_name superfluous_disable_command - @available(iOS 15.0, *) - public struct HalfSheetUI: UIViewControllerRepresentable { - let content: Content - @Binding var isPresented: Bool - let detents: [UISheetPresentationController.Detent] - let smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? - let prefersScrollingExpandsWhenScrolledToEdge: Bool - let prefersEdgeAttachedInCompactHeight: Bool - - public init(isPresented: Binding, detents: [UISheetPresentationController.Detent] = [.medium(), .large()], smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> Content) { - self.content = content() - self.detents = detents - self.smallestUndimmedDetentIdentifier = smallestUndimmedDetentIdentifier - self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight - self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge - _isPresented = isPresented - } - - public func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - public func makeUIViewController(context: Context) -> HalfSheetViewController { - let vc = HalfSheetViewController(coordinator: context.coordinator, detents: detents, smallestUndimmedDetentIdentifier: smallestUndimmedDetentIdentifier, prefersScrollingExpandsWhenScrolledToEdge: prefersScrollingExpandsWhenScrolledToEdge, prefersEdgeAttachedInCompactHeight: prefersEdgeAttachedInCompactHeight, content: { content }) - return vc - } - - public func updateUIViewController(_ uiViewController: HalfSheetViewController, context _: Context) { - if isPresented { - uiViewController.presentModalView() - } else { - uiViewController.dismissModalView() - } - } - - public class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate { - var parent: HalfSheetUI - init(_ parent: HalfSheetUI) { - self.parent = parent - } - - public func presentationControllerDidDismiss(_: UIPresentationController) { - if parent.isPresented { - parent.isPresented = false - } - } - } - } - - @available(iOS 15.0, *) - public class HalfSheetViewController: UIViewController { - let content: Content - let coordinator: HalfSheetUI.Coordinator - let detents: [UISheetPresentationController.Detent] - let smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? - let prefersScrollingExpandsWhenScrolledToEdge: Bool - let prefersEdgeAttachedInCompactHeight: Bool - private var isLandscape: Bool = UIDevice.current.orientation.isLandscape - public init(coordinator: HalfSheetUI.Coordinator, detents: [UISheetPresentationController.Detent] = [.medium(), .large()], smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> Content) { - self.content = content() - self.coordinator = coordinator - self.detents = detents - self.smallestUndimmedDetentIdentifier = smallestUndimmedDetentIdentifier - self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight - self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge - super.init(nibName: nil, bundle: .main) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func dismissModalView() { - dismiss(animated: true, completion: nil) - } - - func presentModalView() { - let hostingController = UIHostingController(rootView: content) - - hostingController.modalPresentationStyle = .popover - hostingController.presentationController?.delegate = coordinator as UIAdaptivePresentationControllerDelegate - hostingController.modalTransitionStyle = .coverVertical - if let hostPopover = hostingController.popoverPresentationController { - hostPopover.sourceView = super.view - let sheet = hostPopover.adaptiveSheetPresentationController - sheet.detents = (isLandscape ? [.large()] : detents) - sheet.largestUndimmedDetentIdentifier = - smallestUndimmedDetentIdentifier - sheet.prefersScrollingExpandsWhenScrolledToEdge = - prefersScrollingExpandsWhenScrolledToEdge - sheet.prefersEdgeAttachedInCompactHeight = - prefersEdgeAttachedInCompactHeight - sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true - } - if presentedViewController == nil { - present(hostingController, animated: true, completion: nil) - } - } - - override public func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - if UIDevice.current.orientation.isLandscape { - isLandscape = true - presentedViewController?.popoverPresentationController?.adaptiveSheetPresentationController.detents = [.large()] - } else { - isLandscape = false - presentedViewController?.popoverPresentationController?.adaptiveSheetPresentationController.detents = detents - } - } - } -#endif - -struct HalfSheetView_Previews: PreviewProvider { - struct HalfSheetDemo: View { - @State private var isPresented = false - var body: some View { - VStack { - Button("Present sheet", action: { - isPresented.toggle() - }).sheet(isPresented: $isPresented, - detents: [.medium, .large], - smallestUndimmedDetentIdentifier: .large) { - Text("Sheet content") - } - } - } - } - - static var previews: some View { - HalfSheetDemo() - } -} diff --git a/Sources/OversizeUI/Extensions/HalfSheet/HalfSheet.swift b/Sources/OversizeUI/Extensions/HalfSheet/HalfSheet.swift new file mode 100644 index 0000000..df97465 --- /dev/null +++ b/Sources/OversizeUI/Extensions/HalfSheet/HalfSheet.swift @@ -0,0 +1,78 @@ +// +// Copyright © 2022 Alexander Romanov +// HalfSheet.swift +// + +import SwiftUI + +#if os(iOS) + import UIKit + + public enum Detents { + case large + case medium + + public var uiViewDetents: UISheetPresentationController.Detent { + switch self { + case .large: + return .large() + case .medium: + return .medium() + } + } + } +#endif +// swiftlint:disable line_length +#if os(iOS) + + @available(iOS 15, *) + public struct SheetModifier: ViewModifier { + public let detents: [Detents] + public func body(content: Content) -> some View { + SheetView(detents: detents) { + content + } + } + } + + public extension View { + @_disfavoredOverload + func presentationDetents(_ detents: [Detents]) -> some View { + modifier(SheetModifier(detents: detents)) + } + } + + public struct SheetView: UIViewControllerRepresentable { + private let content: Content + private let detents: [Detents] + + public init(detents: [Detents], @ViewBuilder content: () -> Content) { + self.content = content() + self.detents = detents + } + + public func makeUIViewController(context _: Context) -> SheetHostingController { + SheetHostingController(rootView: content, detents: detents.map { $0.uiViewDetents }) + } + + public func updateUIViewController(_: SheetHostingController, context _: Context) {} + } + + public final class SheetHostingController: UIHostingController { + var detents: [UISheetPresentationController.Detent] = [] + + override public func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + if let controller = sheetPresentationController { + controller.detents = detents + } + } + } + + public extension SheetHostingController { + convenience init(rootView: Content, detents: [UISheetPresentationController.Detent]) { + self.init(rootView: rootView) + self.detents = detents + } + } +#endif diff --git a/Sources/OversizeUI/Extensions/LibraryContent/LibraryContent.swift b/Sources/OversizeUI/Extensions/LibraryContent/LibraryContent.swift index b74382f..dc7ebae 100644 --- a/Sources/OversizeUI/Extensions/LibraryContent/LibraryContent.swift +++ b/Sources/OversizeUI/Extensions/LibraryContent/LibraryContent.swift @@ -12,10 +12,6 @@ public struct LibraryContent: LibraryContentProvider { Surface { Text("Surface") }, category: .control ) -// LibraryItem( -// TextFieldExtended("Text", text: .constant("Text")), -// category: .control -// ) LibraryItem( Icon(.airplay), category: .control @@ -28,11 +24,4 @@ public struct LibraryContent: LibraryContentProvider { base.fontStyle(.body, color: .onBackgroundHighEmphasis) ) } - -// @LibraryContentBuilder -// public func modifiers(base: Image) -> [LibraryItem] { -// LibraryItem( -// base.resizeToFill(width: 150, height: 150) -// ) -// } } diff --git a/Sources/OversizeUI/Extensions/Loading/LoadingViews.swift b/Sources/OversizeUI/Extensions/Loading/LoadingViews.swift deleted file mode 100644 index 8553200..0000000 --- a/Sources/OversizeUI/Extensions/Loading/LoadingViews.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// LoadingViews.swift -// - -import SwiftUI - -// public extension ScrollView { -// func loading(_ isLoading: Bool) -> some View { -// Group { -// if isLoading { -// self.overlay(LoaderOverlayView(.spiner)) -// } else { -// self -// } -// } -// } -// } -// -// public extension List { -// func loading(_ isLoading: Bool) -> some View { -// Group { -// if isLoading { -// self.overlay(LoaderOverlayView(.spiner)) -// } else { -// self -// } -// } -// } -// } -// -// public extension HStack { -// func loading(_ isLoading: Bool) -> some View { -// Group { -// if isLoading { -// self.overlay(LoaderOverlayView(.spiner)) -// } else { -// self -// } -// } -// } -// } -// -// public extension VStack { -// func loading(_ isLoading: Bool) -> some View { -// Group { -// if isLoading { -// self.overlay(LoaderOverlayView(.spiner)) -// } else { -// self -// } -// } -// } -// } -// -// public extension ZStack { -// func loading(_ isLoading: Bool) -> some View { -// Group { -// if isLoading { -// self.overlay(LoaderOverlayView(.spiner)) -// } else { -// self -// } -// } -// } -// } diff --git a/Sources/OversizeUI/Extensions/Spacing/Spacing.swift b/Sources/OversizeUI/Extensions/Spacing/Spacing.swift index 85f0954..ba51987 100644 --- a/Sources/OversizeUI/Extensions/Spacing/Spacing.swift +++ b/Sources/OversizeUI/Extensions/Spacing/Spacing.swift @@ -7,43 +7,49 @@ import SwiftUI // swiftlint:disable line_length public extension HStack { - init(alignment: VerticalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { + @inlinable init(alignment: VerticalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { self = .init(alignment: alignment, spacing: spacing.rawValue, content: content) } } public extension VStack { - init(alignment: HorizontalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { + @inlinable init(alignment: HorizontalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { self = .init(alignment: alignment, spacing: spacing.rawValue, content: content) } } public extension LazyHStack { - init(alignment: VerticalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { + @inlinable init(alignment: VerticalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { self = .init(alignment: alignment, spacing: spacing.rawValue, content: content) } } public extension LazyVStack { - init(alignment: HorizontalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { + @inlinable init(alignment: HorizontalAlignment = .center, spacing: Space, @ViewBuilder content: () -> Content) { self = .init(alignment: alignment, spacing: spacing.rawValue, content: content) } } public extension LazyVGrid { - init(columns: [GridItem], alignment: HorizontalAlignment = .center, spacing: Space, pinnedViews: PinnedScrollableViews = .init(), @ViewBuilder content: () -> Content) { + @inlinable init(columns: [GridItem], alignment: HorizontalAlignment = .center, spacing: Space, pinnedViews: PinnedScrollableViews = .init(), @ViewBuilder content: () -> Content) { self = .init(columns: columns, alignment: alignment, spacing: spacing.rawValue, pinnedViews: pinnedViews, content: content) } } public extension Spacer { - init(minLength: Space) { + @inlinable init(minLength: Space) { self = .init(minLength: minLength.rawValue) } } public extension GridItem { - init(_ size: GridItem.Size = .flexible(), spacing: Space, alignment: Alignment? = nil) { + @inlinable init(_ size: GridItem.Size = .flexible(), spacing: Space, alignment: Alignment? = nil) { self = .init(size, spacing: spacing.rawValue, alignment: alignment) } } + +public extension RoundedRectangle { + @inlinable init(cornerRadius: Radius, style: RoundedCornerStyle = .circular) { + self = .init(cornerRadius: cornerRadius.rawValue, style: style) + } +} diff --git a/Sources/OversizeUI/Extensions/Unwrap.swift b/Sources/OversizeUI/Extensions/Unwrap.swift deleted file mode 100644 index be9284d..0000000 --- a/Sources/OversizeUI/Extensions/Unwrap.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// Unwrap.swift -// - -// -// File.swift -// -// -// Created by alexander on 06.10.2021. -// diff --git a/Sources/OversizeUI/Extensions/View/View+NavigationView.swift b/Sources/OversizeUI/Extensions/View/View+NavigationView.swift index 42f66b7..b6d4a14 100644 --- a/Sources/OversizeUI/Extensions/View/View+NavigationView.swift +++ b/Sources/OversizeUI/Extensions/View/View+NavigationView.swift @@ -34,7 +34,7 @@ public extension View { case let .scroll(offset): #if os(iOS) VStack(spacing: .zero) { - ModalNavigationBar(title: title, bigTitle: true, offset: offset, leadingBar: {}, trailingBar: {}, bottomBar: {}) + ModalNavigationBar(title: title, bigTitle: true, offset: offset, leadingBar: {}, trailingBar: {}, bottomBar: {}, titleLabel: {}) self } #else @@ -69,7 +69,7 @@ public extension View { case let .fixed(offset): #if os(iOS) VStack(spacing: .zero) { - ModalNavigationBar(title: title, bigTitle: false, offset: offset, leadingBar: leadingBar, trailingBar: trailingBar, bottomBar: bottomBar) + ModalNavigationBar(title: title, bigTitle: false, offset: offset, leadingBar: leadingBar, trailingBar: trailingBar, bottomBar: bottomBar, titleLabel: {}) self } #else @@ -88,7 +88,7 @@ public extension View { case let .scroll(offset): #if os(iOS) VStack(spacing: .zero) { - ModalNavigationBar(title: title, bigTitle: true, offset: offset, leadingBar: leadingBar, trailingBar: leadingBar, bottomBar: bottomBar) + ModalNavigationBar(title: title, bigTitle: true, offset: offset, leadingBar: leadingBar, trailingBar: leadingBar, bottomBar: bottomBar, titleLabel: {}) self } #else @@ -306,7 +306,8 @@ public extension View { background: background, leadingBar: leadingBar, trailingBar: trailingBar, - bottomBar: bottomBar + bottomBar: bottomBar, + titleLabel: {} ) .zIndex(99_999_999) ScrollViewOffset(offset: offset) { @@ -340,7 +341,8 @@ public extension View { background: background, leadingBar: leadingBar, trailingBar: trailingBar, - bottomBar: bottomBar + bottomBar: bottomBar, + titleLabel: {} ) ScrollViewOffset(offset: offset) { self diff --git a/Sources/OversizeUI/Extensions/Platform.swift b/Sources/OversizeUI/Extensions/View/View+Platform.swift similarity index 97% rename from Sources/OversizeUI/Extensions/Platform.swift rename to Sources/OversizeUI/Extensions/View/View+Platform.swift index 2c5ba33..18359f5 100644 --- a/Sources/OversizeUI/Extensions/Platform.swift +++ b/Sources/OversizeUI/Extensions/View/View+Platform.swift @@ -1,6 +1,6 @@ // // Copyright © 2022 Alexander Romanov -// Platform.swift +// View+Platform.swift // import SwiftUI diff --git a/Sources/OversizeUI/Extensions/View/View+SafeArea.swift b/Sources/OversizeUI/Extensions/View/View+SafeArea.swift deleted file mode 100644 index b03a775..0000000 --- a/Sources/OversizeUI/Extensions/View/View+SafeArea.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// View+SafeArea.swift -// - -import SwiftUI - -public enum EdgeInsetsType { - case top, leading, tralling, bottom -} - -/* - public extension View { - func getSafeArea() -> UIEdgeInsets { - UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) - } - - func getSafeArea(_ edge: EdgeInsetsType) -> CGFloat { - switch edge { - case .top: - return UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0 - case .leading: - return UIApplication.shared.windows.first?.safeAreaInsets.left ?? 0 - case .tralling: - return UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0 - case .bottom: - return UIApplication.shared.windows.first?.safeAreaInsets.right ?? 0 - } - } - } - */ diff --git a/Sources/OversizeUI/Extensions/View/View+Snackbar.swift b/Sources/OversizeUI/Extensions/View/View+Snackbar.swift deleted file mode 100644 index 41e2f1a..0000000 --- a/Sources/OversizeUI/Extensions/View/View+Snackbar.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// View+Snackbar.swift -// - -/* - import SwiftUI - - public extension View { - func embedInSnackbar(text: String, showSnackbar: Bool) -> some View { - self - .overlay( - VStack { - Spacer() - - Snackbar { - Text(text) - } - .offset(y: showSnackbar ? -100 : 100) - .animation(.spring()) - } - ) - } - } - */ diff --git a/Sources/OversizeUI/Modules/Activity/ActivityViewController.swift b/Sources/OversizeUI/Modules/Activity/ActivityViewController.swift deleted file mode 100644 index c8ec587..0000000 --- a/Sources/OversizeUI/Modules/Activity/ActivityViewController.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// ActivityViewController.swift -// - -#if os(iOS) - import SwiftUI - import UIKit - - public struct ActivityViewController: UIViewControllerRepresentable { - public init(activityItems: [Any], applicationActivities: [UIActivity]? = nil) { - self.activityItems = activityItems - self.applicationActivities = applicationActivities - } - - var activityItems: [Any] - var applicationActivities: [UIActivity]? - - public func makeUIViewController(context _: UIViewControllerRepresentableContext) - -> UIActivityViewController - { - let controller = UIActivityViewController(activityItems: activityItems, - applicationActivities: applicationActivities) - return controller - } - - public func updateUIViewController(_: UIActivityViewController, - context _: UIViewControllerRepresentableContext) {} - } -#endif diff --git a/Sources/OversizeUI/Modules/Apperance/AppearanceSettingView.swift b/Sources/OversizeUI/Modules/Apperance/AppearanceSettingView.swift deleted file mode 100644 index d5243a7..0000000 --- a/Sources/OversizeUI/Modules/Apperance/AppearanceSettingView.swift +++ /dev/null @@ -1,220 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// AppearanceSettingView.swift -// - -import SwiftUI - -#if os(iOS) - public struct AppearanceSettingView: View { - @Environment(\.verticalSizeClass) private var verticalSizeClass - @Environment(\.presentationMode) var presentationMode - @Environment(\.theme) private var theme: ThemeSettings - @Environment(\.isPortrait) var isPortrait - - public init() {} - - #if os(iOS) - @StateObject var iconSettings = AppIconSettings() - #endif - - // swiftlint:disable trailing_comma - private let columns = [ - GridItem(.adaptive(minimum: 78)), - ] - - @State var offset = CGPoint(x: 0, y: 0) - - enum Destenation { - case font - case border - case radius - } - - @State var pageDestenation: Destenation? - - public var body: some View { - #if os(iOS) - PageView("App") { - iOSSettings - } - .leadingBar { - if !isPortrait, verticalSizeClass == .regular { - EmptyView() - } else { - BarButton(type: .back) - } - } - .backgroundSecondary() - - #else - macSettings - #endif - } - - #if os(iOS) - private var iOSSettings: some View { - VStack(alignment: .center, spacing: 0) { - apperance - - accentColor - - advanded - - if iconSettings.iconNames.count > 1 { - appIcon - } - } - .preferredColorScheme(theme.appearance.colorScheme) - .accentColor(theme.accentColor) - } - #endif - - private var macSettings: some View { - VStack(alignment: .center, spacing: 0) { - advanded - } - .frame(width: 400, height: 300) - // swiftlint:disable multiple_closures_with_trailing_closure superfluous_disable_command - - .navigationTitle("Appearance") - - .preferredColorScheme(theme.appearance.colorScheme) - } - - #if os(iOS) - private var apperance: some View { - SectionView { - HStack { - ForEach(Appearance.allCases, id: \.self) { appearance in - - HStack { - Spacer() - - VStack(spacing: .zero) { - Text(appearance.name) - .foregroundColor(.onSurfaceHighEmphasis) - .font(.subheadline) - .bold() - - appearance.image - .padding(.vertical, .medium) - - if appearance == theme.appearance { - Icon(.checkCircle, color: Color.accent) - } else { - Icon(.circle, color: .onSurfaceMediumEmphasis) - } - } - Spacer() - } - .onTapGesture { - theme.appearance = appearance - } - } - }.padding(.vertical, .xSmall) - } - } - #endif - - #if os(iOS) - private var accentColor: some View { - SectionView("Accent color") { - ColorSelector(selection: theme.$accentColor) - } - } - - #endif - - #if os(iOS) - private var appIcon: some View { - SectionView("App icon") { - LazyVGrid(columns: columns, spacing: 24) { - ForEach(0 ..< iconSettings.iconNames.count) { index in - HStack { - Image(uiImage: UIImage(named: iconSettings.iconNames[index] - ?? "DefaultAppIcon") ?? UIImage()) - .renderingMode(.original) - .resizable() - .scaledToFit() - .frame(width: 78, height: 78) - .cornerRadius(18) - .overlay( - RoundedRectangle(cornerRadius: 20) - .stroke(Color.accent, - lineWidth: index == iconSettings.currentIndex ? 3 : 0) - ) - .onTapGesture { - let defaultIconIndex = self.iconSettings.iconNames - .firstIndex(of: UIApplication.shared.alternateIconName) ?? 0 - if defaultIconIndex != index { - // swiftlint:disable line_length - UIApplication.shared.setAlternateIconName(self.iconSettings.iconNames[index]) { error in - if let error = error { - print(error.localizedDescription) - } else { - print("Success! You have changed the app icon.") - } - } - } - } - } - .padding(3) - } - } - .padding() - } - } - #endif - - private var advanded: some View { - SectionView("Advanced settings") { - ZStack { - NavigationLink(destination: FontSettingView(), - tag: .font, - selection: $pageDestenation) { EmptyView() } - - NavigationLink(destination: BorderSettingView(), - tag: .border, - selection: $pageDestenation) { EmptyView() } - - NavigationLink(destination: RadiusSettingView(), - tag: .radius, - selection: $pageDestenation) { EmptyView() } - - VStack(spacing: .zero) { - Row("Fonts", leadingType: .icon(.type), trallingType: .arrowIcon) { - pageDestenation = .font - } - .premium() - - Row("Borders", leadingType: .icon(.layout), trallingType: .toggleWithArrowButton(isOn: theme.$borderApp, action: { - pageDestenation = .border - })) { - pageDestenation = .border - } - .premium() - .onChange(of: theme.borderApp) { value in - theme.borderSurface = value - theme.borderButtons = value - theme.borderControls = value - theme.borderTextFields = value - } - - Row("Radius", leadingType: .icon(.circle), trallingType: .arrowIcon) { - pageDestenation = .radius - } - .premium() - } - } - } - } - } - - struct SettingsThemeView_Previews: PreviewProvider { - static var previews: some View { - AppearanceSettingView() - .previewPhones() - } - } -#endif diff --git a/Sources/OversizeUI/Modules/Apperance/BorderSettongView.swift b/Sources/OversizeUI/Modules/Apperance/BorderSettongView.swift deleted file mode 100644 index 604758b..0000000 --- a/Sources/OversizeUI/Modules/Apperance/BorderSettongView.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// BorderSettongView.swift -// - -import SwiftUI - -public struct BorderSettingView: View { - @Environment(\.theme) private var theme: ThemeSettings - @State var offset = CGPoint(x: 0, y: 0) - - public init() {} - - public var body: some View { - settings - } - - private var settings: some View { - VStack(alignment: .center, spacing: 0) { - SectionView { - VStack(spacing: .zero) { - Toggle("Borders in app", isOn: theme.$borderApp) - .onChange(of: theme.borderApp) { value in - theme.borderSurface = value - theme.borderButtons = value - theme.borderControls = value - theme.borderTextFields = value - } - .fontStyle(.headline) - .foregroundColor(.onSurfaceHighEmphasis) - .padding(.horizontal, .medium) - .padding(.vertical, .small) - - if theme.borderApp { - VStack(spacing: Space.small.rawValue) { - #if os(iOS) || os(macOS) - VStack(spacing: Space.xxSmall.rawValue) { - HStack { - Text("Size") - .subheadline() - .foregroundColor(.onSurfaceHighEmphasis) - - Spacer() - - Text(String(format: "%.1f", theme.borderSize) + " px") - .fontStyle(.subheadline) - .foregroundColor(.onSurfaceHighEmphasis) - } - - Slider(value: theme.$borderSize, in: 0.5 ... 2, step: 0.5) - - }.surface(background: .secondary, padding: .small) - .padding(.horizontal, Space.medium) - .padding(.bottom, Space.xxSmall) - - #endif - - Rectangle() - .frame(height: 1) - .foregroundColor(Color.border) - .padding(.horizontal, theme.borderSurface ? 0 : Space.medium.rawValue) - - VStack(spacing: .zero) { - Row("Surface", - trallingType: .toggle(isOn: theme.$borderSurface), - paddingVertical: .xSmall) - Row("Buttons", - trallingType: .toggle(isOn: theme.$borderSurface), - paddingVertical: .xSmall) - Row("Text fields", - trallingType: .toggle(isOn: theme.$borderSurface), - paddingVertical: .xSmall) - Row("Other controls", - trallingType: .toggle(isOn: theme.$borderSurface), - paddingVertical: .xSmall) - }.padding(.top, .xxxSmall) - .padding(.vertical, .xxxSmall) - } - } - } - } - - Spacer() - } - .navigationBar("Border", style: .fixed($offset)) { - BarButton(type: .back) - } trailingBar: {} bottomBar: {} - .background(Color.backgroundSecondary.ignoresSafeArea(.all)) - .preferredColorScheme(theme.appearance.colorScheme) - .animation(.easeIn(duration: 0.2)) - } -} - -struct BorderSettongView_Previews: PreviewProvider { - static var previews: some View { - BorderSettingView() - .previewPhones() - } -} diff --git a/Sources/OversizeUI/Modules/Apperance/FontSettingView.swift b/Sources/OversizeUI/Modules/Apperance/FontSettingView.swift deleted file mode 100644 index d3fde0e..0000000 --- a/Sources/OversizeUI/Modules/Apperance/FontSettingView.swift +++ /dev/null @@ -1,174 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// FontSettingView.swift -// - -import SwiftUI - -public struct FontSettingView: View { - private enum FontSetting: String, CaseIterable { - case title, paragraph, other - } - - @Environment(\.theme) private var theme: ThemeSettings - - @State private var activeTab: FontSetting = .title - @State var offset = CGPoint(x: 0, y: 0) - - public init() {} - - public var body: some View { - VStack(spacing: 0) { - previewText - - SegmentedPickerSelector(FontSetting.allCases, selection: $activeTab) { item, _ in - Text(item.rawValue.capitalizingFirstLetter()) - } selectionView: {} - .animation(.default, value: activeTab) - - getActiveTabContent(tab: activeTab) - .padding(.top, .small) - } - .padding(.horizontal) - .padding(.bottom) - - .navigationBar("Fonts", style: .fixed($offset)) { - BarButton(type: .back) - } trailingBar: {} bottomBar: {} - } - - @ViewBuilder - private func getActiveTabContent(tab: FontSetting) -> some View { - switch tab { - case .title: - titleSelector - case .paragraph: - paragraphSelector - case .other: - otherSelector - } - } - - private var titleSelector: some View { - GridSelect(FontDesignType.allCases, selection: theme.$fontTitle, - content: { fontStyle, _ in - HStack { - VStack(alignment: .leading, spacing: 8) { - Text("Aa") - .font(.system(size: 34, weight: .heavy, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - - Text(fontStyle.rawValue.capitalizingFirstLetter()) - .font(.system(size: 16, weight: .medium, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - } - Spacer() - }.padding() - }).gridSelectStyle(.default(selected: .graySurface)) - } - - private var paragraphSelector: some View { - GridSelect(FontDesignType.allCases, selection: theme.$fontParagraph, - content: { fontStyle, _ in - HStack { - VStack(alignment: .leading, spacing: 8) { - Text("Aa") - .font(.system(size: 34, weight: .heavy, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - - Text(fontStyle.rawValue.capitalizingFirstLetter()) - .font(.system(size: 16, weight: .medium, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - } - Spacer() - }.padding() - }).gridSelectStyle(.default(selected: .graySurface)) - } - - private var otherSelector: some View { - VStack(alignment: .leading, spacing: Space.medium.rawValue) { - VStack(alignment: .leading, spacing: Space.small.rawValue) { - Text("Button".uppercased()) - .bold() - .fontStyle(.caption, color: .onBackgroundMediumEmphasis) - SegmentedPickerSelector(FontDesignType.allCases, selection: theme.$fontButton) { fontStyle, _ in - VStack(alignment: .center, spacing: 8) { - Text("Aa") - .font(.system(size: 28, weight: .heavy, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - - Text(fontStyle.rawValue.capitalizingFirstLetter()) - .font(.system(size: 12, weight: .medium, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - } - } - .segmentedControlStyle(.island(selected: .graySurface)) - } - - VStack(alignment: .leading, spacing: Space.small.rawValue) { - Text("Overline & caption".uppercased()) - .bold() - .fontStyle(.caption, color: .onBackgroundMediumEmphasis) - SegmentedPickerSelector(FontDesignType.allCases, selection: theme.$fontOverline) { fontStyle, _ in - VStack(alignment: .center, spacing: 8) { - Text("Aa") - .font(.system(size: 28, weight: .heavy, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - - Text(fontStyle.rawValue.capitalizingFirstLetter()) - .font(.system(size: 12, weight: .medium, design: fontStyle.system)) - .foregroundColor(.onSurfaceHighEmphasis) - } - } - .segmentedControlStyle(.island(selected: .graySurface)) - } - } - } -} - -// swiftlint:disable all -extension FontSettingView { - private var previewText: some View { - ScrollViewOffset(offset: $offset) { - HStack { - VStack(alignment: .leading, spacing: Space.medium.rawValue) { - VStack(alignment: .leading, spacing: Space.xxSmall.rawValue) { - Text("Overline".uppercased()) - .bold() - .fontStyle(.caption, color: .onBackgroundMediumEmphasis) - - Text("Large title") - .fontStyle(.largeTitle, color: .onBackgroundHighEmphasis) - - Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") - .fontStyle(.body, color: .onBackgroundHighEmphasis) - } - - VStack(alignment: .leading, spacing: Space.xxSmall.rawValue) { - Text("Title") - .fontStyle(.title3, color: .onBackgroundHighEmphasis) - - Text("Subtitle") - .fontStyle(.headline, color: .onBackgroundHighEmphasis) - - Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") - .bold() - .fontStyle(.subheadline, color: .onBackgroundHighEmphasis) - - Text("Button") - .fontStyle(.body, color: .onBackgroundHighEmphasis) - .padding(.top, .xxxSmall) - } - } - Spacer() - } - .padding(.vertical) - } - } -} - -struct FontSettingView_Previews: PreviewProvider { - static var previews: some View { - FontSettingView() - } -} diff --git a/Sources/OversizeUI/Modules/Apperance/RadiusSettingView.swift b/Sources/OversizeUI/Modules/Apperance/RadiusSettingView.swift deleted file mode 100644 index a7812ab..0000000 --- a/Sources/OversizeUI/Modules/Apperance/RadiusSettingView.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// RadiusSettingView.swift -// - -import SwiftUI - -struct RadiusSettingView: View { - @Environment(\.theme) private var theme: ThemeSettings - - @State var offset = CGPoint(x: 0, y: 0) - - public var body: some View { - settings - } - - private var settings: some View { - VStack(alignment: .center, spacing: 0) { - SectionView { - VStack(spacing: .zero) { - VStack(spacing: Space.small.rawValue) { - #if os(iOS) || os(macOS) - VStack(spacing: Space.xxSmall.rawValue) { - HStack { - Text("Size") - .fontStyle(.subheadline) - .foregroundColor(.onSurfaceHighEmphasis) - - Spacer() - - Text(String(format: "%.0f", theme.radius) + " px") - .fontStyle(.subheadline) - .foregroundColor(.onSurfaceHighEmphasis) - } - - Slider(value: theme.$radius, in: 0 ... 12, step: 4) - } - .padding(.horizontal, Space.medium) - .padding(.bottom, Space.xxSmall) - - #endif - } - } - } - - Spacer() - } - - .navigationBar("Radius", style: .fixed($offset)) { - BarButton(type: .back) - } trailingBar: {} bottomBar: {} - - .background(Color.backgroundSecondary.ignoresSafeArea(.all)) - .preferredColorScheme(theme.appearance.colorScheme) - .animation(.easeIn(duration: 0.2)) - } -} - -struct RadiusSettingView_Previews: PreviewProvider { - static var previews: some View { - RadiusSettingView() - } -} diff --git a/Sources/OversizeUI/Modules/FieldScreen/FieldScreenView.swift b/Sources/OversizeUI/Modules/FieldScreen/FieldScreenView.swift deleted file mode 100644 index 55670e8..0000000 --- a/Sources/OversizeUI/Modules/FieldScreen/FieldScreenView.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// FieldScreenView.swift -// - -import SwiftUI - -public struct FieldScreenView: View { - public let label: String - public var placeholder: String - @Binding public var text: String - @Binding public var helperText: String - @Binding public var showHelper: Bool - @State var offset = CGPoint(x: 0, y: 0) - - public var leadingImage: IconsNames - public var trallingImage: IconsNames - - public var buttonText: LocalizedStringKey - public var action: () -> Void - - @Environment(\.presentationMode) var presentationMode - - @State private var focused: Bool = false - - public init(_ label: String, - placeholder: String, - text: Binding, - helperText: Binding = .constant(""), - showHelper: Binding = .constant(false), - leadingImage: IconsNames = .none, - trallingImage: IconsNames = .none, - buttonText: LocalizedStringKey = "", - buttonAction: @escaping () -> Void) - { - self.label = label - self.placeholder = placeholder - _text = text - _helperText = helperText - _showHelper = showHelper - self.leadingImage = leadingImage - self.trallingImage = trallingImage - self.buttonText = buttonText - action = buttonAction - } - - public var body: some View { - VStack(alignment: .leading) { - Spacer() - - VStack(spacing: 0) { - HStack { - if leadingImage != .none { - Icon(leadingImage) - } - - TextField(placeholder, text: $text, onEditingChanged: { focused in - self.focused = focused - }) - .largeTitle() - .foregroundColor(.onSurfaceHighEmphasis) - .multilineTextAlignment(.center) - - if trallingImage != .none { - Icon(trallingImage) - } - } - - }.padding() - - if helperText != "" { - Text(helperText) - .subheadline() - .foregroundColor(.onSurfaceMediumEmphasis) - } - - Spacer() - - Button(action: buttonAction, label: { - Text(buttonText, bundle: .module) - }) - .buttonStyle(.primary) - .padding() - } - .navigationBar("App", style: .fixed($offset)) { - BarButton(type: .close) - } trailingBar: {} bottomBar: {} - } - - func buttonAction() { - action() - presentationMode.wrappedValue.dismiss() - } -} - -struct FieldScreenView_Previews: PreviewProvider { - static var previews: some View { - FieldScreenView("Your name", placeholder: "Alexander", text: .constant("Alexander"), buttonAction: {}) - } -} diff --git a/Sources/OversizeUI/Modules/PINCode/PINCodeView.swift b/Sources/OversizeUI/Modules/PINCode/PINCodeView.swift deleted file mode 100644 index 23344b2..0000000 --- a/Sources/OversizeUI/Modules/PINCode/PINCodeView.swift +++ /dev/null @@ -1,276 +0,0 @@ -// -// Copyright © 2022 Alexander Romanov -// PINCodeView.swift -// - -import SwiftUI - -public enum PINCodeViewState { - case locked, loading, error, unlocked -} - -public enum BiometricType: String { - case none = "" - case touchID = "Touch ID" - case faceID = "Face ID" -} - -public struct PINCodeView: View { - @Binding private var pinCode: String - - @Binding private var state: PINCodeViewState - - @State private var shouldAnimate = false - - let timer = Timer.publish(every: 0.3, on: .main, in: .common).autoconnect() - - @State var leftOffset: CGFloat = 0 - @State var rightOffset: CGFloat = 50 - - private var maxCount: Int - - private var gridItemLayout = Array(repeating: GridItem(.flexible(), spacing: 0), count: 3) - - private let action: (() -> Void)? - private let biometricAction: (() -> Void)? - - private let title: String? - - private let errorText: String? - - private let pinCodeEnabled: Bool - private let biometricEnabled: Bool - private let biometricType: BiometricType - - public init(pinCode: Binding, - state: Binding = .constant(.locked), - maxCount: Int = 4, - title: String? = nil, - errorText: String? = nil, - pinCodeEnabled: Bool = true, - biometricEnabled: Bool = false, - biometricType: BiometricType = .faceID, - action: (() -> Void)? = nil, - biometricAction: (() -> Void)? = nil) - { - _pinCode = pinCode - _state = state - self.maxCount = maxCount - self.title = title - self.errorText = errorText - self.pinCodeEnabled = pinCodeEnabled - self.biometricEnabled = biometricEnabled - self.biometricType = biometricType - self.action = action - self.biometricAction = biometricAction - } - - public var body: some View { - content() - .background(Color.surfacePrimary.ignoresSafeArea(.all)) - } - - @ViewBuilder - func content() -> some View { - switch pinCodeEnabled { - case true: - pinCodeView - case false: - biometricView - } - } - - var biometricView: some View { - VStack { - Spacer() - - Text(biometricType.rawValue) - .fontStyle(.title2, color: .onBackgroundHighEmphasis) - - Spacer() - - #if os(iOS) - biometricImage() - .onTapGesture { - biometricAction?() - } - #endif - - Spacer() - } - } - - var pinCodeView: some View { - VStack { - Spacer() - - Text(title ?? "") - .fontStyle(.title2, color: .onBackgroundHighEmphasis) - .opacity(title != nil ? 1 : 0) - - Spacer() - - pinCounter(state: state) - - Spacer() - - Text(errorText ?? "") - .fontStyle(.subheadline, color: .error) - .opacity(state == .error ? 1 : 0) - - Spacer() - - numpad - } - } - - var numpad: some View { - LazyVGrid(columns: gridItemLayout, spacing: 20) { - ForEach(1 ... 9, id: \.self) { number in - - let stringNumber = String(number) - - Button { - appendNumber(number: Character(stringNumber)) - - } label: { - Text(stringNumber) - } - .buttonStyle(NumpadButtonStyle()) - .disabled(state == .loading) - } - - Button {} label: { - Text("...") - }.opacity(0) - - Button { - appendNumber(number: Character("0")) - } label: { - Text("0") - } - .buttonStyle(NumpadButtonStyle()) - .disabled(state == .loading) - - Button { - if pinCode.isEmpty, biometricEnabled { - biometricAction?() - } else if pinCode.isEmpty, !biometricEnabled { - } else { - deleteLastNumber() - } - } label: { - if pinCode.isEmpty, biometricEnabled { - biometricImage() - } else if pinCode.isEmpty, !biometricEnabled { - EmptyView() - } else { - Icon(.delete) - } - } // .opacity(pinCode.isEmpty && biometricEnabled ? 1 : 0) - } - .paddingContent() - .padding(.bottom, .xLarge) - } - - @ViewBuilder - private func biometricImage() -> some View { - switch biometricType { - case .none: - EmptyView() - case .touchID: - Image(systemName: "touchid") - .foregroundColor(Color.onBackgroundHighEmphasis) - .font(.system(size: 32)) - .frame(width: 24, height: 24, alignment: .center) - case .faceID: - Image(systemName: "faceid") - .font(.system(size: 32)) - .foregroundColor(Color.onBackgroundHighEmphasis) - .frame(width: 24, height: 24, alignment: .center) - } - } - - @ViewBuilder - private func pinCounter(state: PINCodeViewState) -> some View { - switch state { - case .locked, .error, .unlocked: - HStack(spacing: .xSmall) { - ForEach(0 ..< maxCount, id: \.self) { number in - Circle() - .fill(pinCode.count <= number ? Color.surfaceTertiary - : Color.accent) - .frame(width: 12, height: 12) - } - } - case .loading: - HStack(spacing: .xSmall) { - ForEach(0 ..< maxCount, id: \.self) { number in - Circle() - .fill(pinCode.count <= number ? Color.surfaceTertiary - : Color.accent) - .frame(width: 12, height: 12) - .offset(x: leftOffset) - // .animation(Animation.easeInOut(duration: 1).delay(0.2 * Double(number))) - - .scaleEffect(shouldAnimate ? 0.5 : 1) - .animation(Animation.easeInOut(duration: 0.5) - .repeatForever() - .delay(number == 0 ? 0 : 0.5 * Double(number))) - } - } - .onReceive(timer) { _ in - shouldAnimate.toggle() - } - } - } - - func appendNumber(number: Character) { - state = .locked - - if pinCode.count > (maxCount - 1) { - print("return") - return - } - - if pinCode.count >= (maxCount - 1) { - pinCode.append(number) - enterAction() - } else { - pinCode.append(number) - } - } - - func deleteLastNumber() { - state = .locked - - if pinCode.count <= maxCount { - // isDisabledNumpad = false - } - pinCode.removeLast() - print(pinCode) - } - - func enterAction() { - action?() - } -} - -public struct NumpadButtonStyle: ButtonStyle { - public func makeBody(configuration: Self.Configuration) -> some View { - configuration.label - .title2() - .foregroundColor(.onSurfaceHighEmphasis) - .frame(width: 72, height: 72, alignment: .center) - .background( - Circle() - .fill(configuration.isPressed ? Color.surfaceTertiary : Color.surfaceSecondary) - ) - } -} - -struct PINCodeView_Previews: PreviewProvider { - static var previews: some View { - PINCodeView(pinCode: .constant("123"), state: .constant(.locked)) - } -}