diff --git a/Sources/OversizeKit/RouterKit/HUDRouter.swift b/Sources/OversizeKit/RouterKit/HUDRouter.swift index 935f304..3f2d987 100644 --- a/Sources/OversizeKit/RouterKit/HUDRouter.swift +++ b/Sources/OversizeKit/RouterKit/HUDRouter.swift @@ -4,17 +4,20 @@ // import Foundation +import OversizeModels public class HUDRouter: ObservableObject { @Published public var isShowHud: Bool = false @Published public var hudText: String = "" + @Published public var type: HUDMessageType = .default public init() {} } public extension HUDRouter { - func present(_ text: String) { + func present(_ text: String, type: HUDMessageType = .default) { hudText = text + self.type = type isShowHud = true } } diff --git a/Sources/OversizeKit/RouterKit/MenuRouter.swift b/Sources/OversizeKit/RouterKit/MenuRouter.swift new file mode 100644 index 0000000..699ce38 --- /dev/null +++ b/Sources/OversizeKit/RouterKit/MenuRouter.swift @@ -0,0 +1,23 @@ +// +// Copyright © 2024 Alexander Romanov +// File.swift, created on 06.05.2024 +// + +import Foundation + +public class MenuRouter: ObservableObject { + @Published public var menu: Menu? + @Published public var subMenu: Menu? + + public init(menu: Menu) { + self.menu = menu + } + + public func changeMenu(_ menu: Menu) { + self.menu = menu + } + + public func changeSubMenu(_ menu: Menu) { + self.menu = menu + } +} diff --git a/Sources/OversizeKit/RouterKit/PresentationRouter.swift b/Sources/OversizeKit/RouterKit/PresentationRouter.swift new file mode 100644 index 0000000..931793e --- /dev/null +++ b/Sources/OversizeKit/RouterKit/PresentationRouter.swift @@ -0,0 +1,42 @@ +// +// Copyright © 2024 Alexander Romanov +// PresentationRouter.swift, created on 16.05.2024 +// + +import Foundation + +public enum HUDMessageType { + case `default` + case success + case destructive + case deleted + case archived +} + +public class PresentationRouter: ObservableObject { + // Alert + @Published public var alert: RootAlert? = nil + @Published public var isShowHud: Bool = false + @Published public var hudText: String = "" + @Published public var type: HUDMessageType = .default + + public init() {} +} + +public extension PresentationRouter { + func present(_ alert: RootAlert) { + self.alert = alert + } + + func dismiss() { + alert = nil + } +} + +public extension PresentationRouter { + func present(_ text: String, type: HUDMessageType = .default) { + hudText = text + self.type = type + isShowHud = true + } +} diff --git a/Sources/OversizeKit/RouterKit/Protocols/Alertable.swift b/Sources/OversizeKit/RouterKit/Protocols/Alertable.swift index 0c7a2a9..77ea23c 100644 --- a/Sources/OversizeKit/RouterKit/Protocols/Alertable.swift +++ b/Sources/OversizeKit/RouterKit/Protocols/Alertable.swift @@ -8,12 +8,6 @@ import Foundation public protocol Alertable: Equatable, Hashable, Identifiable {} public extension Alertable { - var id: Self { self } - - func hash(into hasher: inout Hasher) { - hasher.combine(id) - } - static func == (lhs: Self, rhs: Self) -> Bool { if lhs.id == rhs.id { true @@ -21,4 +15,8 @@ public extension Alertable { false } } + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + } } diff --git a/Sources/OversizeKit/RouterKit/Protocols/Menuble.swift b/Sources/OversizeKit/RouterKit/Protocols/Menuble.swift new file mode 100644 index 0000000..3cf68f3 --- /dev/null +++ b/Sources/OversizeKit/RouterKit/Protocols/Menuble.swift @@ -0,0 +1,12 @@ +// +// Copyright © 2024 Alexander Romanov +// File.swift, created on 06.05.2024 +// + +public protocol Menuble: CaseIterable, Equatable, Identifiable {} + +public extension Menuble { + func hash(into hasher: inout Hasher) { + hasher.combine(id) + } +} diff --git a/Sources/OversizeKit/RouterKit/Protocols/Routable.swift b/Sources/OversizeKit/RouterKit/Protocols/Routable.swift index 92a5f43..a54f673 100644 --- a/Sources/OversizeKit/RouterKit/Protocols/Routable.swift +++ b/Sources/OversizeKit/RouterKit/Protocols/Routable.swift @@ -8,9 +8,15 @@ import SwiftUI public protocol Routable: Equatable, Hashable, Identifiable {} public extension Routable { - var id: Self { self } - func hash(into hasher: inout Hasher) { hasher.combine(id) } + + static func == (lhs: Self, rhs: Self) -> Bool { + if lhs.id == rhs.id { + true + } else { + false + } + } } diff --git a/Sources/OversizeKit/RouterKit/Router.swift b/Sources/OversizeKit/RouterKit/Router.swift index 4690af0..98cd61f 100644 --- a/Sources/OversizeKit/RouterKit/Router.swift +++ b/Sources/OversizeKit/RouterKit/Router.swift @@ -15,6 +15,7 @@ public final class Router: ObservableObject { // Sheets @Published public var sheet: Destination? @Published public var fullScreenCover: Destination? + @Published public var menu: Destination? @Published public var sheetDetents: Set = [] @Published public var dragIndicator: Visibility = .hidden @Published public var dismissDisabled: Bool = false @@ -22,6 +23,13 @@ public final class Router: ObservableObject { public init() {} } +@available(iOS 16.0, *) +public extension Router { + func changeMenu(_ screen: Destination) { + menu = screen + } +} + @available(iOS 16.0, *) public extension Router { func move(_ screen: Destination) { @@ -64,6 +72,15 @@ public extension Router { self.sheet = sheet } + func backOrDismiss() { + if sheet != nil || fullScreenCover != nil { + sheet = nil + fullScreenCover = nil + } else { + back() + } + } + func dismiss() { sheet = nil fullScreenCover = nil diff --git a/Sources/OversizeKit/SettingsKit/Views/About/About/AboutView.swift b/Sources/OversizeKit/SettingsKit/Views/About/About/AboutView.swift index d3d62bd..be4a46e 100644 --- a/Sources/OversizeKit/SettingsKit/Views/About/About/AboutView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/About/About/AboutView.swift @@ -13,203 +13,207 @@ import OversizeUI import SwiftUI // swiftlint:disable all -#if os(iOS) +#if canImport(MessageUI) import MessageUI +#endif - public struct AboutView: View { - @Environment(\.settingsNavigate) var settingsNavigate - @Environment(\.screenSize) var screenSize - @Environment(\.iconStyle) var iconStyle: IconStyle +public struct AboutView: View { + @Environment(\.settingsNavigate) var settingsNavigate + @Environment(\.screenSize) var screenSize + @Environment(\.iconStyle) var iconStyle: IconStyle - @StateObject var viewModel: AboutViewModel + @StateObject var viewModel: AboutViewModel - public init() { - _viewModel = StateObject(wrappedValue: AboutViewModel()) - } + public init() { + _viewModel = StateObject(wrappedValue: AboutViewModel()) + } - @State var offset: CGFloat = 0 + @State var offset: CGFloat = 0 - @State var isSharePresented = false - @State private var isShowMail = false + @State var isSharePresented = false + @State private var isShowMail = false - @State private var isPresentStoreProduct: Bool = false + @State private var isPresentStoreProduct: Bool = false - var isLargeScreen: Bool { - screenSize.width < 500 ? false : true - } + var isLargeScreen: Bool { + screenSize.width < 500 ? false : true + } - var oppacity: CGFloat { - if offset < 0 { - return 1 - } else if offset > 500 { - return 0 - } else { - return Double(1 / (offset * 0.01)) - } + var oppacity: CGFloat { + if offset < 0 { + return 1 + } else if offset > 500 { + return 0 + } else { + return Double(1 / (offset * 0.01)) } + } - var blur: CGFloat { - if offset < 0 { - return 0 - } else { - return Double(offset * 0.05) - } + var blur: CGFloat { + if offset < 0 { + return 0 + } else { + return Double(offset * 0.05) } + } + + #if os(iOS) + let scale = UIScreen.main.scale + #else + let scale: CGFloat = 2 + #endif + public var body: some View { #if os(iOS) - let scale = UIScreen.main.scale + Page(L10n.Settings.about) { + list + .surfaceContentRowMargins() + .task { + await viewModel.fetchApps() + } + } + .backgroundSecondary() + #else - let scale: CGFloat = 2 + list + .navigationTitle(L10n.Settings.about) #endif + } - public var body: some View { - #if os(iOS) - Page(L10n.Settings.about) { - list - .surfaceContentRowMargins() - .task { - await viewModel.fetchApps() - } - } - .backgroundSecondary() - - #else - list - .navigationTitle(L10n.Settings.about) - #endif - } + private func appLinks() -> some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack(alignment: .top, spacing: Space.small) { + switch viewModel.state { + case .initial, .loading: + ForEach(0 ... 6, id: \.self) { _ in + RoundedRectangle(cornerRadius: .large, style: .continuous) + .fillSurfaceSecondary() + .frame(width: 74, height: 74) + } + case let .result(apps, _): + ForEach(apps, id: \.appStoreId) { app in + Button { + isPresentStoreProduct = true + } label: { + VStack(spacing: .xSmall) { + CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/apps/" + app.address + "/icon.png"), urlCache: .imageCache, content: { + $0 + .resizable() + .frame(width: 74, height: 74) + .mask(RoundedRectangle(cornerRadius: .large, + style: .continuous)) + .overlay( + RoundedRectangle(cornerRadius: 16, + style: .continuous) + .stroke(lineWidth: 1) + .opacity(0.15) + ) + + }, placeholder: { + RoundedRectangle(cornerRadius: .large, style: .continuous) + .fillSurfaceSecondary() + .frame(width: 74, height: 74) + }) - private func appLinks() -> some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack(alignment: .top, spacing: Space.small) { - switch viewModel.state { - case .initial, .loading: - ForEach(0 ... 6, id: \.self) { _ in - RoundedRectangle(cornerRadius: .large, style: .continuous) - .fillSurfaceSecondary() - .frame(width: 74, height: 74) - } - case let .result(apps, _): - ForEach(apps, id: \.appStoreId) { app in - Button { - isPresentStoreProduct = true - } label: { - VStack(spacing: .xSmall) { - CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/apps/" + app.address + "/icon.png"), urlCache: .imageCache, content: { - $0 - .resizable() - .frame(width: 74, height: 74) - .mask(RoundedRectangle(cornerRadius: .large, - style: .continuous)) - .overlay( - RoundedRectangle(cornerRadius: 16, - style: .continuous) - .stroke(lineWidth: 1) - .opacity(0.15) - ) - - }, placeholder: { - RoundedRectangle(cornerRadius: .large, style: .continuous) - .fillSurfaceSecondary() - .frame(width: 74, height: 74) - }) - - Text(app.name) - .caption(.medium) - .multilineTextAlignment(.center) - .foregroundColor(.onSurfaceMediumEmphasis) - .frame(width: 74) - } + Text(app.name) + .caption(.medium) + .multilineTextAlignment(.center) + .foregroundColor(.onSurfaceMediumEmphasis) + .frame(width: 74) } - .buttonStyle(.scale) - .appStoreOverlay(isPresent: $isPresentStoreProduct, appId: app.appStoreId) } - case .error: - EmptyView() + .buttonStyle(.scale) + #if os(iOS) + .appStoreOverlay(isPresent: $isPresentStoreProduct, appId: app.appStoreId) + #endif } + case .error: + EmptyView() + } - if let authorAllApps = Info.url.developerAllApps { - VStack(spacing: .xSmall) { - Link(destination: authorAllApps) { - ZStack { - RoundedRectangle(cornerRadius: 16, style: .continuous) - .foregroundColor(.surfaceSecondary) - .frame(width: 74, height: 74) + if let authorAllApps = Info.url.developerAllApps { + VStack(spacing: .xSmall) { + Link(destination: authorAllApps) { + ZStack { + RoundedRectangle(cornerRadius: 16, style: .continuous) + .foregroundColor(.surfaceSecondary) + .frame(width: 74, height: 74) - IconDeprecated(.externalLink) - } + IconDeprecated(.externalLink) } - - Text("All apps") - .caption(.medium) - .multilineTextAlignment(.center) - .foregroundColor(.onSurfaceMediumEmphasis) - .frame(width: 74) } + + Text("All apps") + .caption(.medium) + .multilineTextAlignment(.center) + .foregroundColor(.onSurfaceMediumEmphasis) + .frame(width: 74) } + } - }.padding(.horizontal, .medium) - } - .padding(.bottom, 16) + }.padding(.horizontal, .medium) } + .padding(.bottom, 16) + } - var list: some View { - VStack(spacing: .zero) { - image - .padding(.top, isLargeScreen ? -70 : 0) - - if isLargeScreen { - HStack(spacing: .xxSmall) { - Image.Brands.Oversize.fill - .resizable() - .renderingMode(.template) - .foregroundColor(Color.onSurfaceHighEmphasis) - .frame(width: 32, height: 32) - - Resource.overszieTextLogo - .renderingMode(.template) - .foregroundColor(Color.onSurfaceHighEmphasis) - } - .padding(.top, -40) - .padding(.bottom, .xSmall) - - } else { - VStack(spacing: .xxSmall) { - Image.Brands.Oversize.fill - .resizable() - .renderingMode(.template) - .foregroundColor(Color.onSurfaceHighEmphasis) - .frame(width: 48, height: 48) + var list: some View { + VStack(spacing: .zero) { + image + .padding(.top, isLargeScreen ? -70 : 0) + + if isLargeScreen { + HStack(spacing: .xxSmall) { + Image.Brands.Oversize.fill + .resizable() + .renderingMode(.template) + .foregroundColor(Color.onSurfaceHighEmphasis) + .frame(width: 32, height: 32) + + Resource.overszieTextLogo + .renderingMode(.template) + .foregroundColor(Color.onSurfaceHighEmphasis) + } + .padding(.top, -40) + .padding(.bottom, .xSmall) - Resource.overszieTextLogo - .renderingMode(.template) - .foregroundColor(Color.onSurfaceHighEmphasis) - } - .padding(.top, 42) - .padding(.bottom, .medium) + } else { + VStack(spacing: .xxSmall) { + Image.Brands.Oversize.fill + .resizable() + .renderingMode(.template) + .foregroundColor(Color.onSurfaceHighEmphasis) + .frame(width: 48, height: 48) + + Resource.overszieTextLogo + .renderingMode(.template) + .foregroundColor(Color.onSurfaceHighEmphasis) } + .padding(.top, 42) + .padding(.bottom, .medium) + } - Text("The Oversize project is made with love and attention to the design of the forces of only one person") - .title3(.semibold) - .foregroundColor(.onBackgroundHighEmphasis) - .padding(.horizontal, isLargeScreen ? 72 : 52) - .padding(.bottom, .large) - .multilineTextAlignment(.center) - - soclal - .padding(.bottom, .small) - - SectionView { - VStack(spacing: .zero) { - if let reviewUrl = Info.url.appStoreReview, let id = Info.app.appStoreID, !id.isEmpty, let appName = Info.app.name { - Link(destination: reviewUrl) { - Row("Rate \(appName) on App Store") { - rateSettingsIcon.icon() - } + Text("The Oversize project is made with love and attention to the design of the forces of only one person") + .title3(.semibold) + .foregroundColor(.onBackgroundHighEmphasis) + .padding(.horizontal, isLargeScreen ? 72 : 52) + .padding(.bottom, .large) + .multilineTextAlignment(.center) + + soclal + .padding(.bottom, .small) + + SectionView { + VStack(spacing: .zero) { + if let reviewUrl = Info.url.appStoreReview, let id = Info.app.appStoreID, !id.isEmpty, let appName = Info.app.name { + Link(destination: reviewUrl) { + Row("Rate \(appName) on App Store") { + rateSettingsIcon.icon() } - .buttonStyle(.row) } + .buttonStyle(.row) + } + #if os(iOS) if MFMailComposeViewController.canSendMail(), let mail = Info.links?.company.email, let appVersion = Info.app.verstion, @@ -232,66 +236,67 @@ import SwiftUI MailView(to: mail, subject: subject, content: contentPreText) } } + #endif - #if os(iOS) - if let shareUrl = Info.url.appInstallShare, let id = Info.app.appStoreID, !id.isEmpty { - Row(L10n.Settings.shareApplication) { - isSharePresented.toggle() - } leading: { - shareSettingsIcon.icon() - } - .sheet(isPresented: $isSharePresented) { - ActivityViewController(activityItems: [shareUrl]) - .presentationDetents([.medium, .large]) - } + #if os(iOS) + if let shareUrl = Info.url.appInstallShare, let id = Info.app.appStoreID, !id.isEmpty { + Row(L10n.Settings.shareApplication) { + isSharePresented.toggle() + } leading: { + shareSettingsIcon.icon() + } + .sheet(isPresented: $isSharePresented) { + ActivityViewController(activityItems: [shareUrl]) + .presentationDetents([.medium, .large]) } - #endif - } - } - - SectionView { - VStack(spacing: .zero) { - HStack { - Text(L10n.About.otherApplications.uppercased()) - .caption(true) - .foregroundColor(.onSurfaceMediumEmphasis) - .padding(.top, 12) - .padding(.leading, 26) - .padding(.bottom, 18) - Spacer() } + #endif + } + } - appLinks() + SectionView { + VStack(spacing: .zero) { + HStack { + Text(L10n.About.otherApplications.uppercased()) + .caption(true) + .foregroundColor(.onSurfaceMediumEmphasis) + .padding(.top, 12) + .padding(.leading, 26) + .padding(.bottom, 18) + Spacer() } + + appLinks() } + } - SectionView { - VStack(spacing: .zero) { - Row("Our open resources") { - settingsNavigate(.move(.ourResorses)) - } - .rowArrow() + SectionView { + VStack(spacing: .zero) { + Row("Our open resources") { + settingsNavigate(.move(.ourResorses)) + } + .rowArrow() - if let privacyUrl = Info.url.appPrivacyPolicyUrl { - Row(L10n.Store.privacyPolicy) { - settingsNavigate(.present(.webView(url: privacyUrl))) - } + if let privacyUrl = Info.url.appPrivacyPolicyUrl { + Row(L10n.Store.privacyPolicy) { + settingsNavigate(.present(.webView(url: privacyUrl))) } + } - if let termsOfUde = Info.url.appTermsOfUseUrl { - Row(L10n.Store.termsOfUse) { - settingsNavigate(.present(.webView(url: termsOfUde))) - } + if let termsOfUde = Info.url.appTermsOfUseUrl { + Row(L10n.Store.termsOfUse) { + settingsNavigate(.present(.webView(url: termsOfUde))) } } } - - footer } + + footer } + } - private var soclal: some View { - HStack(spacing: .small) { + private var soclal: some View { + HStack(spacing: .small) { // switch viewModel.state { // case .initial, .loading: // ForEach(0...6, id: \.self) { _ in @@ -327,203 +332,202 @@ import SwiftUI // EmptyView() // } - if let facebook = Info.url.companyFacebook { - Link(destination: facebook) { - // Surface { - HStack { - Spacer() - Image.Brands.Facebook.Circle.fill - .renderingMode(.template) - .foregroundColor(Color.onSurfaceMediumEmphasis) - Spacer() - } - // } + if let facebook = Info.url.companyFacebook { + Link(destination: facebook) { + // Surface { + HStack { + Spacer() + Image.Brands.Facebook.Circle.fill + .renderingMode(.template) + .foregroundColor(Color.onSurfaceMediumEmphasis) + Spacer() } + // } } + } - if let instagram = Info.url.companyInstagram { - Link(destination: instagram) { - // Surface { - HStack { - Spacer() - Image.Brands.Instagram.fill - .renderingMode(.template) - .foregroundColor(Color.onSurfaceMediumEmphasis) - Spacer() - } - // } + if let instagram = Info.url.companyInstagram { + Link(destination: instagram) { + // Surface { + HStack { + Spacer() + Image.Brands.Instagram.fill + .renderingMode(.template) + .foregroundColor(Color.onSurfaceMediumEmphasis) + Spacer() } + // } } + } - if let twitter = Info.url.companyTwitter { - Link(destination: twitter) { - // Surface { - HStack { - Spacer() - Image.Brands.xCom - .renderingMode(.template) - .foregroundColor(Color.onSurfaceMediumEmphasis) - Spacer() - } - // } + if let twitter = Info.url.companyTwitter { + Link(destination: twitter) { + // Surface { + HStack { + Spacer() + Image.Brands.xCom + .renderingMode(.template) + .foregroundColor(Color.onSurfaceMediumEmphasis) + Spacer() } + // } } + } - if let telegramUrl = Info.url.companyTelegram { - Link(destination: telegramUrl) { - // Surface { - HStack { - Spacer() - Image.Brands.Telegram.fill - .renderingMode(.template) - .foregroundColor(Color.onSurfaceMediumEmphasis) - Spacer() - } - // } + if let telegramUrl = Info.url.companyTelegram { + Link(destination: telegramUrl) { + // Surface { + HStack { + Spacer() + Image.Brands.Telegram.fill + .renderingMode(.template) + .foregroundColor(Color.onSurfaceMediumEmphasis) + Spacer() } + // } } + } - if let dribbble = Info.url.companyDribbble { - Link(destination: dribbble) { - // Surface { - HStack { - Spacer() - Image.Brands.Dribbble.fill - .renderingMode(.template) - .foregroundColor(Color.onSurfaceMediumEmphasis) - Spacer() - } - // } + if let dribbble = Info.url.companyDribbble { + Link(destination: dribbble) { + // Surface { + HStack { + Spacer() + Image.Brands.Dribbble.fill + .renderingMode(.template) + .foregroundColor(Color.onSurfaceMediumEmphasis) + Spacer() } + // } } } - .buttonStyle(.scale) - .frame(maxWidth: 300) - .controlMargin(.xSmall) - .paddingContent(.horizontal) } + .buttonStyle(.scale) + .frame(maxWidth: 300) + .controlMargin(.xSmall) + .paddingContent(.horizontal) + } - private var image: some View { - HStack { - VStack(alignment: .center) { - ZStack(alignment: .top) { - CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/illustrations/scenes/about-layer3.png"), urlCache: .imageCache, scale: scale) { - $0 - .resizable() - .scaledToFit() - .blur(radius: blur) - } placeholder: { - Rectangle() - .fillSurfaceTertiary() - .rotationEffect(.degrees(45)) - .opacity(0) - .frame(height: screenSize.width / 1.16) - } - .offset(y: -offset * 0.1) - - CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/illustrations/scenes/about-layer2.png"), urlCache: .imageCache, scale: scale) { - $0 - .resizable() - .scaledToFit() - .blur(radius: blur) - } placeholder: { - Rectangle() - .fillSurfaceTertiary() - .rotationEffect(.degrees(45)) - .padding(200) - .frame(height: screenSize.width / 1.16) - .overlay { - ProgressView() - } - } + private var image: some View { + HStack { + VStack(alignment: .center) { + ZStack(alignment: .top) { + CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/illustrations/scenes/about-layer3.png"), urlCache: .imageCache, scale: scale) { + $0 + .resizable() + .scaledToFit() + .blur(radius: blur) + } placeholder: { + Rectangle() + .fillSurfaceTertiary() + .rotationEffect(.degrees(45)) + .opacity(0) + .frame(height: screenSize.width / 1.16) + } + .offset(y: -offset * 0.1) - CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/illustrations/scenes/about-layer1.png"), urlCache: .imageCache, scale: scale) { - $0 - .resizable() - .scaledToFit() - .blur(radius: blur) - } placeholder: { - Rectangle() - .fillSurfaceTertiary() - .rotationEffect(.degrees(45)) - .opacity(0) - .frame(height: screenSize.width / 1.16) - } - .offset(y: -(offset * -0.04)) + CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/illustrations/scenes/about-layer2.png"), urlCache: .imageCache, scale: scale) { + $0 + .resizable() + .scaledToFit() + .blur(radius: blur) + } placeholder: { + Rectangle() + .fillSurfaceTertiary() + .rotationEffect(.degrees(45)) + .padding(200) + .frame(height: screenSize.width / 1.16) + .overlay { + ProgressView() + } } - .scaleEffect(screenSize.width < 500 ? 1.4 : 0.9) - .opacity(screenSize.width < 500 ? oppacity : 1) + + CachedAsyncImage(url: URL(string: "https://cdn.oversize.design/assets/illustrations/scenes/about-layer1.png"), urlCache: .imageCache, scale: scale) { + $0 + .resizable() + .scaledToFit() + .blur(radius: blur) + } placeholder: { + Rectangle() + .fillSurfaceTertiary() + .rotationEffect(.degrees(45)) + .opacity(0) + .frame(height: screenSize.width / 1.16) + } + .offset(y: -(offset * -0.04)) } + .scaleEffect(screenSize.width < 500 ? 1.4 : 0.9) + .opacity(screenSize.width < 500 ? oppacity : 1) } } + } - private var footer: some View { - HStack { - Spacer() - - VStack(alignment: .center) { - if let authorLink = Info.links?.company.url { - Link(destination: authorLink) { - if let developerName = Info.developer.name, - let appVersion = Info.app.verstion, - let appName = Info.app.name, - let appBuild = Info.app.build - { - Text("© 2024 \(developerName). \(appName) \(appVersion) (\(appBuild))") - .footnote() - .foregroundColor(.onBackgroundDisabled) - } else { - Text("Developer") - .footnote() - .foregroundColor(.onBackgroundDisabled) - } + private var footer: some View { + HStack { + Spacer() + + VStack(alignment: .center) { + if let authorLink = Info.links?.company.url { + Link(destination: authorLink) { + if let developerName = Info.developer.name, + let appVersion = Info.app.verstion, + let appName = Info.app.name, + let appBuild = Info.app.build + { + Text("© 2024 \(developerName). \(appName) \(appVersion) (\(appBuild))") + .footnote() + .foregroundColor(.onBackgroundDisabled) + } else { + Text("Developer") + .footnote() + .foregroundColor(.onBackgroundDisabled) } } } - - Spacer() } - .padding(.top, Space.small) - .padding(.bottom, 40) - } - var rateSettingsIcon: Image { - switch iconStyle { - case .line: - return Image.Base.heart - case .fill: - return Image.Base.Heart.fill - case .twoTone: - return Image.Base.Heart.TwoTone.fill - } + Spacer() } + .padding(.top, Space.small) + .padding(.bottom, 40) + } - var ideaSettingsIcon: Image { - switch iconStyle { - case .line: - return Image.Electricity.lamp - case .fill: - return Image.Electricity.Lamp.fill - case .twoTone: - return Image.Electricity.Lamp.TwoTone.fill - } + var rateSettingsIcon: Image { + switch iconStyle { + case .line: + return Image.Base.heart + case .fill: + return Image.Base.Heart.fill + case .twoTone: + return Image.Base.Heart.TwoTone.fill } + } - var shareSettingsIcon: Image { - switch iconStyle { - case .line: - return Image.Base.send - case .fill: - return Image.Base.Send.fill - case .twoTone: - return Image.Base.Send.TwoTone.fill - } + var ideaSettingsIcon: Image { + switch iconStyle { + case .line: + return Image.Electricity.lamp + case .fill: + return Image.Electricity.Lamp.fill + case .twoTone: + return Image.Electricity.Lamp.TwoTone.fill } } - struct AboutView_Previews: PreviewProvider { - static var previews: some View { - AboutView() + var shareSettingsIcon: Image { + switch iconStyle { + case .line: + return Image.Base.send + case .fill: + return Image.Base.Send.fill + case .twoTone: + return Image.Base.Send.TwoTone.fill } } -#endif +} + +struct AboutView_Previews: PreviewProvider { + static var previews: some View { + AboutView() + } +} diff --git a/Sources/OversizeKit/SettingsKit/Views/Apperance/AppearanceSettingView.swift b/Sources/OversizeKit/SettingsKit/Views/Apperance/AppearanceSettingView.swift index a4520a7..6a4e4be 100644 --- a/Sources/OversizeKit/SettingsKit/Views/Apperance/AppearanceSettingView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/Apperance/AppearanceSettingView.swift @@ -9,228 +9,224 @@ import OversizeServices import OversizeUI import SwiftUI -#if os(iOS) - public struct AppearanceSettingView: View { - @Environment(\.settingsNavigate) var settingsNavigate - @Environment(\.theme) private var theme: ThemeSettings - @Environment(\.iconStyle) var iconStyle: IconStyle - @Environment(\.isPremium) var isPremium: Bool +public struct AppearanceSettingView: View { + @Environment(\.settingsNavigate) var settingsNavigate + @Environment(\.theme) private var theme: ThemeSettings + @Environment(\.iconStyle) var iconStyle: IconStyle + @Environment(\.isPremium) var isPremium: Bool - #if os(iOS) - @StateObject var iconSettings = AppIconSettings() - #endif + #if os(iOS) + @StateObject var iconSettings = AppIconSettings() + #endif - private let columns = [ - GridItem(.adaptive(minimum: 78)), - ] + private let columns = [ + GridItem(.adaptive(minimum: 78)), + ] - public init() {} - - public var body: some View { - #if os(iOS) - Page(L10n.Settings.apperance) { - iOSSettings - .surfaceContentRowMargins() - } - .backgroundSecondary() - - #else - macSettings - #endif - } + public init() {} + public var body: some View { #if os(iOS) - private var iOSSettings: some View { - LazyVStack(alignment: .leading, spacing: 0) { - apperance + Page(L10n.Settings.apperance) { + iOSSettings + .surfaceContentRowMargins() + } + .backgroundSecondary() - accentColor + #else + macSettings + #endif + } - advanded + #if os(iOS) + private var iOSSettings: some View { + LazyVStack(alignment: .leading, spacing: 0) { + apperance - if iconSettings.iconNames.count > 1 { - appIcon - } - } - .preferredColorScheme(theme.appearance.colorScheme) - .accentColor(theme.accentColor) - } - #endif + accentColor - 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") + if iconSettings.iconNames.count > 1 { + appIcon + } + } .preferredColorScheme(theme.appearance.colorScheme) + .accentColor(theme.accentColor) } + #endif - #if os(iOS) - private var apperance: some View { - SectionView { - HStack { - ForEach(Appearance.allCases, id: \.self) { appearance in + 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 - HStack { - Spacer() + .navigationTitle("Appearance") + .preferredColorScheme(theme.appearance.colorScheme) + } - VStack(spacing: .zero) { - Text(appearance.name) - .foregroundColor(.onSurfaceHighEmphasis) - .font(.subheadline) - .bold() + private var apperance: some View { + SectionView { + HStack { + ForEach(Appearance.allCases, id: \.self) { appearance in - appearance.image - .padding(.vertical, .medium) + HStack { + Spacer() - if appearance == theme.appearance { - IconDeprecated(.checkCircle, color: Color.accent) - } else { - IconDeprecated(.circle, color: .onSurfaceMediumEmphasis) - } - } - Spacer() - } - .onTapGesture { - theme.appearance = appearance + VStack(spacing: .zero) { + Text(appearance.name) + .foregroundColor(.onSurfaceHighEmphasis) + .font(.subheadline) + .bold() + + appearance.image + .padding(.vertical, .medium) + + if appearance == theme.appearance { + IconDeprecated(.checkCircle, color: Color.accent) + } else { + IconDeprecated(.circle, color: .onSurfaceMediumEmphasis) } } - }.padding(.vertical, .xSmall) + Spacer() + } + .onTapGesture { + theme.appearance = appearance + } } - } - #endif + }.padding(.vertical, .xSmall) + } + } - #if os(iOS) - private var accentColor: some View { - SectionView("Accent color") { - ColorSelector(selection: theme.$accentColor) - } + #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, id: \.self) { index in - HStack { - Image(uiImage: UIImage(named: iconSettings.iconNames[index] - ?? "AppIcon") ?? UIImage()) - .renderingMode(.original) - .resizable() - .scaledToFit() - .frame(width: 78, height: 78) - .cornerRadius(18) - .overlay( - RoundedRectangle(cornerRadius: 20) - .stroke(index == iconSettings.currentIndex ? Color.accent : Color.border, - lineWidth: index == iconSettings.currentIndex ? 3 : 1) - ) - .onTapGesture { - if index != 0, isPremium == false { - settingsNavigate(.present(.premium)) - } else { - let defaultIconIndex = iconSettings.iconNames - .firstIndex(of: UIApplication.shared.alternateIconName) ?? 0 - if defaultIconIndex != index { - // swiftlint:disable line_length - UIApplication.shared.setAlternateIconName(iconSettings.iconNames[index]) { error in - if let error { - log(error.localizedDescription) - } else { - log("Success! You have changed the app icon.") - } + #endif + + #if os(iOS) + private var appIcon: some View { + SectionView("App icon") { + LazyVGrid(columns: columns, spacing: 24) { + ForEach(0 ..< iconSettings.iconNames.count, id: \.self) { index in + HStack { + Image(uiImage: UIImage(named: iconSettings.iconNames[index] + ?? "AppIcon") ?? UIImage()) + .renderingMode(.original) + .resizable() + .scaledToFit() + .frame(width: 78, height: 78) + .cornerRadius(18) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(index == iconSettings.currentIndex ? Color.accent : Color.border, + lineWidth: index == iconSettings.currentIndex ? 3 : 1) + ) + .onTapGesture { + if index != 0, isPremium == false { + settingsNavigate(.present(.premium)) + } else { + let defaultIconIndex = iconSettings.iconNames + .firstIndex(of: UIApplication.shared.alternateIconName) ?? 0 + if defaultIconIndex != index { + // swiftlint:disable line_length + UIApplication.shared.setAlternateIconName(iconSettings.iconNames[index]) { error in + if let error { + log(error.localizedDescription) + } else { + log("Success! You have changed the app icon.") } } } } - } - .padding(3) + } } + .padding(3) } - .padding() } + .padding() } - #endif + } + #endif + + private var advanded: some View { + SectionView("Advanced settings") { + VStack(spacing: .zero) { + Row("Fonts") { + settingsNavigate(.move(.font)) + } leading: { + textIcon.icon() + } + .rowArrow() + .premium() + .onPremiumTap() - private var advanded: some View { - SectionView("Advanced settings") { - VStack(spacing: .zero) { - Row("Fonts") { - settingsNavigate(.move(.font)) + Switch(isOn: theme.$borderApp) { + Row("Borders") { + settingsNavigate(.move(.border)) } leading: { - textIcon.icon() + borderIcon.icon() } - .rowArrow() .premium() - .onPremiumTap() - - Switch(isOn: theme.$borderApp) { - Row("Borders") { - settingsNavigate(.move(.border)) - } leading: { - borderIcon.icon() - } - .premium() - } - .onPremiumTap() - .onChange(of: theme.borderApp) { value in - theme.borderSurface = value - theme.borderButtons = value - theme.borderControls = value - theme.borderTextFields = value - } + } + .onPremiumTap() + .onChange(of: theme.borderApp) { value in + theme.borderSurface = value + theme.borderButtons = value + theme.borderControls = value + theme.borderTextFields = value + } - Row("Radius") { - settingsNavigate(.move(.radius)) - } leading: { - radiusIcon.icon() - } - .rowArrow() - .premium() - .onPremiumTap() + Row("Radius") { + settingsNavigate(.move(.radius)) + } leading: { + radiusIcon.icon() } + .rowArrow() + .premium() + .onPremiumTap() } } + } - var textIcon: Image { - switch iconStyle { - case .line: - return Image.Editor.Font.square - case .fill: - return Image.Editor.Font.Square.fill - case .twoTone: - return Image.Editor.Font.Square.TwoTone.fill - } + var textIcon: Image { + switch iconStyle { + case .line: + return Image.Editor.Font.square + case .fill: + return Image.Editor.Font.Square.fill + case .twoTone: + return Image.Editor.Font.Square.TwoTone.fill } + } - var borderIcon: Image { - switch iconStyle { - case .line: - return Image.Design.verticalMirror - case .fill: - return Image.Editor.Font.Square.fill - case .twoTone: - return Image.Editor.Font.Square.TwoTone.fill - } + var borderIcon: Image { + switch iconStyle { + case .line: + return Image.Design.verticalMirror + case .fill: + return Image.Editor.Font.Square.fill + case .twoTone: + return Image.Editor.Font.Square.TwoTone.fill } + } - var radiusIcon: Image { - switch iconStyle { - case .line: - return Image.Design.path - case .fill: - return Image.Design.Path.fill - case .twoTone: - return Image.Design.Path.twoTone - } + var radiusIcon: Image { + switch iconStyle { + case .line: + return Image.Design.path + case .fill: + return Image.Design.Path.fill + case .twoTone: + return Image.Design.Path.twoTone } } -#endif +} #if os(iOS) public class AppIconSettings: ObservableObject { @@ -255,11 +251,9 @@ import SwiftUI } #endif -#if os(iOS) - struct SettingsThemeView_Previews: PreviewProvider { - static var previews: some View { - AppearanceSettingView() - .previewPhones() - } +struct SettingsThemeView_Previews: PreviewProvider { + static var previews: some View { + AppearanceSettingView() + .previewPhones() } -#endif +} diff --git a/Sources/OversizeKit/SettingsKit/Views/Notifications/NotificationsSettingsView.swift b/Sources/OversizeKit/SettingsKit/Views/Notifications/NotificationsSettingsView.swift index 17b4298..66cc4c8 100644 --- a/Sources/OversizeKit/SettingsKit/Views/Notifications/NotificationsSettingsView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/Notifications/NotificationsSettingsView.swift @@ -9,28 +9,27 @@ import OversizeUI import SwiftUI // swiftlint:disable line_length -#if os(iOS) - public struct NotificationsSettingsView: View { - @StateObject var settingsService = SettingsService() - public init() {} +public struct NotificationsSettingsView: View { + @StateObject var settingsService = SettingsService() - public var body: some View { - Page(L10n.Settings.notifications) { - soundsAndVibrations - .surfaceContentRowMargins() - } - .backgroundSecondary() + public init() {} + + public var body: some View { + Page(L10n.Settings.notifications) { + soundsAndVibrations + .surfaceContentRowMargins() } + .backgroundSecondary() } +} - extension NotificationsSettingsView { - private var soundsAndVibrations: some View { - SectionView { - VStack(spacing: .zero) { - Switch(L10n.Settings.notifications, isOn: $settingsService.notificationEnabled) - } +extension NotificationsSettingsView { + private var soundsAndVibrations: some View { + SectionView { + VStack(spacing: .zero) { + Switch(L10n.Settings.notifications, isOn: $settingsService.notificationEnabled) } } } -#endif +} diff --git a/Sources/OversizeKit/SettingsKit/Views/Screens.swift b/Sources/OversizeKit/SettingsKit/Views/Screens.swift index 062818f..a6058c7 100644 --- a/Sources/OversizeKit/SettingsKit/Views/Screens.swift +++ b/Sources/OversizeKit/SettingsKit/Views/Screens.swift @@ -29,6 +29,51 @@ public enum SettingsScreen: Routable { case sendMail(to: String, subject: String, content: String) } +public extension SettingsScreen { + var id: String { + switch self { + case .premium: + "premium" + case .premiumFeature: + "premiumFeature" + case .soundAndVibration: + "soundAndVibration" + case .appearance: + "appearance" + case .sync: + "sync" + case .about: + "about" + case .feedback: + "feedback" + case .webView: + "webView" + case .ourResorses: + "ourResorses" + case .support: + "support" + case .border: + "border" + case .font: + "font" + case .radius: + "radius" + case .setPINCode: + "setPINCode" + case .updatePINCode: + "updatePINCode" + case .security: + "security" + case .offer: + "offer" + case .sendMail: + "sendMail" + case .notifications: + "notifications" + } + } +} + public struct SettingsNavigateAction { public typealias Action = (SettingsNavigationType) -> Void public let action: Action @@ -46,7 +91,7 @@ public enum SettingsNavigationType { case dismissSheet case dismissFullScreenCover case dismissDisabled(_ isDismissDisabled: Bool = true) - case presentHUD(_ text: String) + case presentHUD(_ text: String, type: HUDMessageType) } public struct SettingsNavigateEnvironmentKey: EnvironmentKey { diff --git a/Sources/OversizeKit/SettingsKit/Views/Security/PINCode/SetPINCodeView.swift b/Sources/OversizeKit/SettingsKit/Views/Security/PINCode/SetPINCodeView.swift index c9b137b..22f88f5 100644 --- a/Sources/OversizeKit/SettingsKit/Views/Security/PINCode/SetPINCodeView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/Security/PINCode/SetPINCodeView.swift @@ -9,7 +9,7 @@ import SwiftUI public struct SetPINCodeView: View { @Environment(\.settingsNavigate) var settingsNavigate - @EnvironmentObject private var hudRouter: HUDRouter + //@EnvironmentObject private var hudRouter: HUDRouter @ObservedObject var viewModel: SetPINCodeViewModel @Environment(\.dismiss) var dismiss diff --git a/Sources/OversizeKit/SettingsKit/Views/Security/SecuritySettingsView.swift b/Sources/OversizeKit/SettingsKit/Views/Security/SecuritySettingsView.swift index ce73bb1..1bb69ed 100644 --- a/Sources/OversizeKit/SettingsKit/Views/Security/SecuritySettingsView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/Security/SecuritySettingsView.swift @@ -10,91 +10,91 @@ import OversizeUI import SwiftUI // swiftlint:disable line_length -#if os(iOS) - public struct SecuritySettingsView: View { - @Injected(\.biometricService) var biometricService - @Environment(\.settingsNavigate) var settingsNavigate - @StateObject var settingsService = SettingsService() - - public init() {} - - public var body: some View { - Page(L10n.Security.title) { - iOSSettings - .surfaceContentRowMargins() - } - .backgroundSecondary() + +public struct SecuritySettingsView: View { + @Injected(\.biometricService) var biometricService + @Environment(\.settingsNavigate) var settingsNavigate + @StateObject var settingsService = SettingsService() + + public init() {} + + public var body: some View { + Page(L10n.Security.title) { + iOSSettings + .surfaceContentRowMargins() } + .backgroundSecondary() } +} - extension SecuritySettingsView { - private var iOSSettings: some View { - VStack(alignment: .center, spacing: 0) { - faceID +extension SecuritySettingsView { + private var iOSSettings: some View { + VStack(alignment: .center, spacing: 0) { + faceID - // additionally - } + // additionally } } - - extension SecuritySettingsView { - private var faceID: some View { - SectionView(L10n.Settings.entrance) { - VStack(spacing: .zero) { - if FeatureFlags.secure.faceID.valueOrFalse, biometricService.checkIfBioMetricAvailable() { - Switch(isOn: - Binding(get: { - settingsService.biometricEnabled - }, set: { - biometricChange(state: $0) - }) - ) { - Row(biometricService.biometricType.rawValue) { - Image(systemName: biometricImageName) - .foregroundColor(Color.onBackgroundHighEmphasis) - .font(.system(size: 20, weight: .semibold)) - .frame(width: 24, height: 24, alignment: .center) - } +} + +extension SecuritySettingsView { + private var faceID: some View { + SectionView(L10n.Settings.entrance) { + VStack(spacing: .zero) { + if FeatureFlags.secure.faceID.valueOrFalse, biometricService.checkIfBioMetricAvailable() { + Switch(isOn: + Binding(get: { + settingsService.biometricEnabled + }, set: { + biometricChange(state: $0) + }) + ) { + Row(biometricService.biometricType.rawValue) { + Image(systemName: biometricImageName) + .foregroundColor(Color.onBackgroundHighEmphasis) + .font(.system(size: 20, weight: .semibold)) + .frame(width: 24, height: 24, alignment: .center) } } + } - if FeatureFlags.secure.lookscreen.valueOrFalse { - Switch(isOn: - Binding(get: { - settingsService.pinCodeEnabend - }, set: { - if settingsService.isSetedPinCode() { - settingsService.pinCodeEnabend = $0 - } else { - settingsNavigate(.present(.setPINCode)) - } - }) - ) { - Row(L10n.Security.pinCode) { - Image.Security.lock.icon() + if FeatureFlags.secure.lookscreen.valueOrFalse { + Switch(isOn: + Binding(get: { + settingsService.pinCodeEnabend + }, set: { + if settingsService.isSetedPinCode() { + settingsService.pinCodeEnabend = $0 + } else { + settingsNavigate(.present(.setPINCode)) } + }) + ) { + Row(L10n.Security.pinCode) { + Image.Security.lock.icon() } + } - if settingsService.isSetedPinCode() { - Row(L10n.Security.changePINCode) { - settingsNavigate(.present(.updatePINCode)) - } - .rowArrow() + if settingsService.isSetedPinCode() { + Row(L10n.Security.changePINCode) { + settingsNavigate(.present(.updatePINCode)) } + .rowArrow() } } } } + } - private func biometricChange(state: Bool) { - Task { - await settingsService.biometricChange(state) - } + private func biometricChange(state: Bool) { + Task { + await settingsService.biometricChange(state) } + } - private var additionally: some View { - SectionView(L10n.Settings.additionally) { - VStack(spacing: .zero) { + private var additionally: some View { + SectionView(L10n.Settings.additionally) { + VStack(spacing: .zero) { // if FeatureFlags.secure.lookscreen.valueOrFalse { // Row(L10n.Security.inactiveAskPassword, trallingType: .toggle(isOn: $settingsStore.askPasswordWhenInactiveEnabend)) // } @@ -125,34 +125,33 @@ import SwiftUI // Row(L10n.Security.facedownLock, trallingType: .toggle(isOn: $settingsStore.lookScreenDownEnabend)) // } // - if FeatureFlags.secure.blurMinimize.valueOrFalse { - Switch(isOn: $settingsService.blurMinimizeEnabend) { - Row(L10n.Security.blurMinimize) - .premium() - } - .onPremiumTap() + if FeatureFlags.secure.blurMinimize.valueOrFalse { + Switch(isOn: $settingsService.blurMinimizeEnabend) { + Row(L10n.Security.blurMinimize) + .premium() } + .onPremiumTap() + } // if FeatureFlags.secure.lookscreen.valueOrFalse { // Row(L10n.Security.authHistory, trallingType: .toggle(isOn: $settingsService.authHistoryEnabend)) // .premium() // .onPremiumTap() // } - } } } + } - private var biometricImageName: String { - switch biometricService.biometricType { - case .none: - return "" - case .touchID: - return "touchid" - case .faceID: - return "faceid" - case .opticID: - return "opticid" - } + private var biometricImageName: String { + switch biometricService.biometricType { + case .none: + return "" + case .touchID: + return "touchid" + case .faceID: + return "faceid" + case .opticID: + return "opticid" } } -#endif +} diff --git a/Sources/OversizeKit/SettingsKit/Views/SettingsView.swift b/Sources/OversizeKit/SettingsKit/Views/SettingsView.swift index 93841a8..3799b59 100644 --- a/Sources/OversizeKit/SettingsKit/Views/SettingsView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/SettingsView.swift @@ -10,38 +10,37 @@ import OversizeUI import SwiftUI // swiftlint:disable line_length -#if os(iOS) - public struct SettingsView: View { - @Environment(\.settingsNavigate) var settingsNavigate - @Environment(\.iconStyle) var iconStyle: IconStyle - @Environment(\.theme) var theme: ThemeSettings - @StateObject var settingsService = SettingsService() - - let appSection: AppSection - let headSection: HeadSection - - public init( - @ViewBuilder appSection: () -> AppSection, - @ViewBuilder headSection: () -> HeadSection - ) { - self.appSection = appSection() - self.headSection = headSection() - } - public var body: some View { - #if os(iOS) +public struct SettingsView: View { + @Environment(\.settingsNavigate) var settingsNavigate + @Environment(\.iconStyle) var iconStyle: IconStyle + @Environment(\.theme) var theme: ThemeSettings + @StateObject var settingsService = SettingsService() + + let appSection: AppSection + let headSection: HeadSection + + public init( + @ViewBuilder appSection: () -> AppSection, + @ViewBuilder headSection: () -> HeadSection + ) { + self.appSection = appSection() + self.headSection = headSection() + } + + public var body: some View { + #if os(iOS) - Page(L10n.Settings.title) { - iOSSettings - }.backgroundSecondary() + Page(L10n.Settings.title) { + iOSSettings + }.backgroundSecondary() - #else - macSettings + #else + macSettings - #endif - } + #endif } -#endif +} // iOS Settings #if os(iOS) @@ -67,288 +66,268 @@ import SwiftUI } #endif -#if os(iOS) - // Sections - extension SettingsView { - private var head: some View { - SectionView { - headSection - } +extension SettingsView { + private var head: some View { + SectionView { + headSection } + } - private var app: some View { - SectionView("General") { - VStack(spacing: .zero) { - if FeatureFlags.app.apperance.valueOrFalse { - Row(L10n.Settings.apperance) { - settingsNavigate(.move(.appearance)) - } leading: { - apperanceSettingsIcon.icon() - } - .rowArrow() + private var app: some View { + SectionView("General") { + VStack(spacing: .zero) { + if FeatureFlags.app.apperance.valueOrFalse { + Row(L10n.Settings.apperance) { + settingsNavigate(.move(.appearance)) + } leading: { + apperanceSettingsIcon.icon() } + .rowArrow() + } - if FeatureFlags.app.сloudKit.valueOrFalse || FeatureFlags.app.healthKit.valueOrFalse { - Row(L10n.Title.synchronization) { - settingsNavigate(.move(.sync)) - } leading: { - cloudKitIcon.icon() - } - .rowArrow() + if FeatureFlags.app.сloudKit.valueOrFalse || FeatureFlags.app.healthKit.valueOrFalse { + Row(L10n.Title.synchronization) { + settingsNavigate(.move(.sync)) + } leading: { + cloudKitIcon.icon() } + .rowArrow() + } - if FeatureFlags.secure.faceID.valueOrFalse - || FeatureFlags.secure.lookscreen.valueOrFalse - || FeatureFlags.secure.CVVCodes.valueOrFalse - || FeatureFlags.secure.alertSecureCodes.valueOrFalse - || FeatureFlags.secure.blurMinimize.valueOrFalse - || FeatureFlags.secure.bruteForceSecure.valueOrFalse - || FeatureFlags.secure.photoBreaker.valueOrFalse - { - Row(L10n.Security.title) { - settingsNavigate(.move(.security)) - } leading: { - securityIcon.icon() - } - .rowArrow() + if FeatureFlags.secure.faceID.valueOrFalse + || FeatureFlags.secure.lookscreen.valueOrFalse + || FeatureFlags.secure.CVVCodes.valueOrFalse + || FeatureFlags.secure.alertSecureCodes.valueOrFalse + || FeatureFlags.secure.blurMinimize.valueOrFalse + || FeatureFlags.secure.bruteForceSecure.valueOrFalse + || FeatureFlags.secure.photoBreaker.valueOrFalse + { + Row(L10n.Security.title) { + settingsNavigate(.move(.security)) + } leading: { + securityIcon.icon() } + .rowArrow() + } - if FeatureFlags.app.sounds.valueOrFalse || FeatureFlags.app.vibration.valueOrFalse { - Row(soundsAndVibrationTitle) { - settingsNavigate(.move(.soundAndVibration)) - } leading: { - FeatureFlags.app.sounds.valueOrFalse ? soundIcon.icon() : vibrationIcon.icon() - } - .rowArrow() + if FeatureFlags.app.sounds.valueOrFalse || FeatureFlags.app.vibration.valueOrFalse { + Row(soundsAndVibrationTitle) { + settingsNavigate(.move(.soundAndVibration)) + } leading: { + FeatureFlags.app.sounds.valueOrFalse ? soundIcon.icon() : vibrationIcon.icon() } + .rowArrow() + } - if FeatureFlags.app.notifications.valueOrFalse { - Row(L10n.Settings.notifications) { - settingsNavigate(.move(.notifications)) - } leading: { - notificationsIcon.icon() - } - .rowArrow() + if FeatureFlags.app.notifications.valueOrFalse { + Row(L10n.Settings.notifications) { + settingsNavigate(.move(.notifications)) + } leading: { + notificationsIcon.icon() } - - appSection + .rowArrow() } + + appSection } } + } - var apperanceSettingsIcon: Image { - switch iconStyle { - case .line: - return Image.Design.paintingPalette - case .fill: - return Image.Design.PaintingPalette.fill - case .twoTone: - return Image.Design.PaintingPalette.twoTone - } + var apperanceSettingsIcon: Image { + switch iconStyle { + case .line: + return Image.Design.paintingPalette + case .fill: + return Image.Design.PaintingPalette.fill + case .twoTone: + return Image.Design.PaintingPalette.twoTone } + } - var cloudKitIcon: Image { - switch iconStyle { - case .line: - return Image.Weather.cloud2 - case .fill: - return Image.Weather.Cloud.Square.fill - case .twoTone: - return Image.Weather.Cloud.Square.twoTone - } + var cloudKitIcon: Image { + switch iconStyle { + case .line: + return Image.Weather.cloud2 + case .fill: + return Image.Weather.Cloud.Square.fill + case .twoTone: + return Image.Weather.Cloud.Square.twoTone } + } - var securityIcon: Image { - switch iconStyle { - case .line: - return Image.Base.lock - case .fill: - return Image.Base.Lock.fill - case .twoTone: - return Image.Base.Lock.TwoTone.fill - } + var securityIcon: Image { + switch iconStyle { + case .line: + return Image.Base.lock + case .fill: + return Image.Base.Lock.fill + case .twoTone: + return Image.Base.Lock.TwoTone.fill } + } - var soundIcon: Image { - switch iconStyle { - case .line: - return Image.Base.volumeUp - case .fill: - return Image.Base.VolumeUp.fill - case .twoTone: - return Image.Base.VolumeUp.TwoTone.fill - } + var soundIcon: Image { + switch iconStyle { + case .line: + return Image.Base.volumeUp + case .fill: + return Image.Base.VolumeUp.fill + case .twoTone: + return Image.Base.VolumeUp.TwoTone.fill } + } - var vibrationIcon: Image { - switch iconStyle { - case .line: - return Image.Mobile.vibration - case .fill: - return Image.Mobile.Vibration.fill - case .twoTone: - return Image.Mobile.Vibration.twoTone - } + var vibrationIcon: Image { + switch iconStyle { + case .line: + return Image.Mobile.vibration + case .fill: + return Image.Mobile.Vibration.fill + case .twoTone: + return Image.Mobile.Vibration.twoTone } + } - var notificationsIcon: Image { - switch iconStyle { - case .line: - return Image.Base.notification - case .fill: - return Image.Base.Notification.fill - case .twoTone: - return Image.Base.Notification.TwoTone.fill - } + var notificationsIcon: Image { + switch iconStyle { + case .line: + return Image.Base.notification + case .fill: + return Image.Base.Notification.fill + case .twoTone: + return Image.Base.Notification.TwoTone.fill } + } - // App Store Review - private var help: some View { - SectionView(L10n.Settings.supportSection) { - VStack(alignment: .leading) { - Row("Get help") { - settingsNavigate(.present(.support, detents: [.medium])) - } leading: { - helpIcon.icon() - } - .rowArrow() - .buttonStyle(.row) + // App Store Review + private var help: some View { + SectionView(L10n.Settings.supportSection) { + VStack(alignment: .leading) { + Row("Get help") { + settingsNavigate(.present(.support, detents: [.medium])) + } leading: { + helpIcon.icon() + } + .rowArrow() + .buttonStyle(.row) - Row("Send feedback") { - settingsNavigate(.present(.feedback, detents: [.medium])) - } leading: { - chatIcon.icon() - } - .rowArrow() - .buttonStyle(.row) + Row("Send feedback") { + settingsNavigate(.present(.feedback, detents: [.medium])) + } leading: { + chatIcon.icon() } + .rowArrow() + .buttonStyle(.row) } } + } - var heartIcon: Image { - switch iconStyle { - case .line: - return Image.Base.heart - case .fill: - return Image.Base.Heart.fill - case .twoTone: - return Image.Base.Heart.TwoTone.fill - } + var heartIcon: Image { + switch iconStyle { + case .line: + return Image.Base.heart + case .fill: + return Image.Base.Heart.fill + case .twoTone: + return Image.Base.Heart.TwoTone.fill } + } - var mailIcon: Image { - switch iconStyle { - case .line: - return Image.Base.message - case .fill: - return Image.Base.Message.fill - case .twoTone: - return Image.Base.Message.TwoTone.fill - } + var mailIcon: Image { + switch iconStyle { + case .line: + return Image.Base.message + case .fill: + return Image.Base.Message.fill + case .twoTone: + return Image.Base.Message.TwoTone.fill } + } - var chatIcon: Image { - switch iconStyle { - case .line: - return Image.Base.chat - case .fill: - return Image.Base.Chat.fill - case .twoTone: - return Image.Base.Chat.twoTone - } + var chatIcon: Image { + switch iconStyle { + case .line: + return Image.Base.chat + case .fill: + return Image.Base.Chat.fill + case .twoTone: + return Image.Base.Chat.twoTone } + } - var infoIcon: Image { - switch iconStyle { - case .line: - return Image.Base.Info.circle - case .fill: - return Image.Base.Info.Circle.fill - case .twoTone: - return Image.Base.Info.Circle.twoTone - } + var infoIcon: Image { + switch iconStyle { + case .line: + return Image.Base.Info.circle + case .fill: + return Image.Base.Info.Circle.fill + case .twoTone: + return Image.Base.Info.Circle.twoTone } + } - var oversizeIcon: Image { - switch iconStyle { - case .line: - return Image.Brands.oversize - case .fill: - return Image.Brands.Oversize.fill - case .twoTone: - return Image.Brands.Oversize.TwoTone.fill - } + var oversizeIcon: Image { + switch iconStyle { + case .line: + return Image.Brands.oversize + case .fill: + return Image.Brands.Oversize.fill + case .twoTone: + return Image.Brands.Oversize.TwoTone.fill } + } - var helpIcon: Image { - switch iconStyle { - case .line: - return Image.Alert.Help.circle - case .fill: - return Image.Alert.Help.Circle.fill - case .twoTone: - return Image.Alert.Help.Circle.twoTone - } + var helpIcon: Image { + switch iconStyle { + case .line: + return Image.Alert.Help.circle + case .fill: + return Image.Alert.Help.Circle.fill + case .twoTone: + return Image.Alert.Help.Circle.twoTone } + } - private var about: some View { - SectionView { - VStack(spacing: .zero) { - Row(L10n.Settings.about) { - settingsNavigate(.move(.about)) - } leading: { - infoIcon.icon() - } - .rowArrow() + private var about: some View { + SectionView { + VStack(spacing: .zero) { + Row(L10n.Settings.about) { + settingsNavigate(.move(.about)) + } leading: { + infoIcon.icon() } - .buttonStyle(.row) - } - } - - var soundsAndVibrationTitle: String { - if FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { - return L10n.Settings.soundsAndVibration - } else if FeatureFlags.app.sounds.valueOrFalse, !FeatureFlags.app.vibration.valueOrFalse { - return L10n.Settings.sounds - } else if !FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { - return L10n.Settings.vibration - } else { - return "" + .rowArrow() } + .buttonStyle(.row) } } -#endif -// Mac OS Settings -#if os(iOS) - extension SettingsView { - private var macSettings: some View { - VStack(alignment: .center, spacing: 0) { - Text("Mac") - } - .frame(width: 400, height: 300) - .navigationTitle(L10n.Settings.apperance) - .preferredColorScheme(theme.appearance.colorScheme) - } - } -#endif -#if os(iOS) - public extension SettingsView where HeadSection == EmptyView { - init(@ViewBuilder appSection: () -> AppSection) { - self.init(appSection: appSection, headSection: { EmptyView() }) + var soundsAndVibrationTitle: String { + if FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { + return L10n.Settings.soundsAndVibration + } else if FeatureFlags.app.sounds.valueOrFalse, !FeatureFlags.app.vibration.valueOrFalse { + return L10n.Settings.sounds + } else if !FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { + return L10n.Settings.vibration + } else { + return "" } } +} -#endif -#if os(iOS) - extension UINavigationController: UIGestureRecognizerDelegate { - override open func viewDidLoad() { - super.viewDidLoad() - interactivePopGestureRecognizer?.delegate = self +extension SettingsView { + private var macSettings: some View { + VStack(alignment: .center, spacing: 0) { + Text("Mac") } + .frame(width: 400, height: 300) + .navigationTitle(L10n.Settings.apperance) + .preferredColorScheme(theme.appearance.colorScheme) + } +} - public func gestureRecognizerShouldBegin(_: UIGestureRecognizer) -> Bool { - viewControllers.count > 1 - } +public extension SettingsView where HeadSection == EmptyView { + init(@ViewBuilder appSection: () -> AppSection) { + self.init(appSection: appSection, headSection: { EmptyView() }) } -#endif +} diff --git a/Sources/OversizeKit/SettingsKit/Views/SoundAndVibration/SoundsAndVibrationsSettingsView.swift b/Sources/OversizeKit/SettingsKit/Views/SoundAndVibration/SoundsAndVibrationsSettingsView.swift index b6d4b2d..6465b3a 100644 --- a/Sources/OversizeKit/SettingsKit/Views/SoundAndVibration/SoundsAndVibrationsSettingsView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/SoundAndVibration/SoundsAndVibrationsSettingsView.swift @@ -9,75 +9,72 @@ import OversizeServices import OversizeUI import SwiftUI -// swiftlint:disable line_length -#if os(iOS) - public struct SoundsAndVibrationsSettingsView: View { - @Environment(\.iconStyle) var iconStyle: IconStyle - @StateObject var settingsService = SettingsService() +public struct SoundsAndVibrationsSettingsView: View { + @Environment(\.iconStyle) var iconStyle: IconStyle + @StateObject var settingsService = SettingsService() - public init() {} + public init() {} - public var body: some View { - Page(title) { - iOSSettings - .surfaceContentRowMargins() - } - .backgroundSecondary() + public var body: some View { + Page(title) { + iOSSettings + .surfaceContentRowMargins() } + .backgroundSecondary() + } - private var title: String { - if FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { - return L10n.Settings.soundsAndVibration - } else if FeatureFlags.app.sounds.valueOrFalse, !FeatureFlags.app.vibration.valueOrFalse { - return L10n.Settings.sounds - } else if !FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { - return L10n.Settings.vibration - } else { - return "" - } + private var title: String { + if FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { + return L10n.Settings.soundsAndVibration + } else if FeatureFlags.app.sounds.valueOrFalse, !FeatureFlags.app.vibration.valueOrFalse { + return L10n.Settings.sounds + } else if !FeatureFlags.app.sounds.valueOrFalse, FeatureFlags.app.vibration.valueOrFalse { + return L10n.Settings.vibration + } else { + return "" } } +} - extension SoundsAndVibrationsSettingsView { - private var iOSSettings: some View { - VStack(alignment: .center, spacing: 0) { - soundsAndVibrations - } +extension SoundsAndVibrationsSettingsView { + private var iOSSettings: some View { + VStack(alignment: .center, spacing: 0) { + soundsAndVibrations } } +} - extension SoundsAndVibrationsSettingsView { - private var soundsAndVibrations: some View { - SectionView { - VStack(spacing: .zero) { - if FeatureFlags.app.sounds.valueOrFalse { - Switch(isOn: $settingsService.soundsEnabled) { - Row(L10n.Settings.sounds) { - IconDeprecated(.music) - } +extension SoundsAndVibrationsSettingsView { + private var soundsAndVibrations: some View { + SectionView { + VStack(spacing: .zero) { + if FeatureFlags.app.sounds.valueOrFalse { + Switch(isOn: $settingsService.soundsEnabled) { + Row(L10n.Settings.sounds) { + IconDeprecated(.music) } } + } - if FeatureFlags.app.vibration.valueOrFalse { - Switch(isOn: $settingsService.vibrationEnabled) { - Row(L10n.Settings.vibration) { - vibrationIcon.icon() - } + if FeatureFlags.app.vibration.valueOrFalse { + Switch(isOn: $settingsService.vibrationEnabled) { + Row(L10n.Settings.vibration) { + vibrationIcon.icon() } } } } } + } - var vibrationIcon: Image { - switch iconStyle { - case .line: - return Image.Mobile.vibration - case .fill: - return Image.Mobile.Vibration.fill - case .twoTone: - return Image.Mobile.Vibration.twoTone - } + var vibrationIcon: Image { + switch iconStyle { + case .line: + return Image.Mobile.vibration + case .fill: + return Image.Mobile.Vibration.fill + case .twoTone: + return Image.Mobile.Vibration.twoTone } } -#endif +} diff --git a/Sources/OversizeKit/SettingsKit/Views/iCloud/iCloudSettingsView.swift b/Sources/OversizeKit/SettingsKit/Views/iCloud/iCloudSettingsView.swift index c8d9912..6a42b66 100644 --- a/Sources/OversizeKit/SettingsKit/Views/iCloud/iCloudSettingsView.swift +++ b/Sources/OversizeKit/SettingsKit/Views/iCloud/iCloudSettingsView.swift @@ -9,66 +9,65 @@ import OversizeUI import SwiftUI // swiftlint:disable line_length type_name -#if os(iOS) - public struct iCloudSettingsView: View { // Synchronization - @StateObject var settingsService = SettingsService() - public init() {} +public struct iCloudSettingsView: View { // Synchronization + @StateObject var settingsService = SettingsService() - public var body: some View { - Page(L10n.Title.synchronization) { - iOSSettings - .surfaceContentRowMargins() - } - .backgroundSecondary() + public init() {} + + public var body: some View { + Page(L10n.Title.synchronization) { + iOSSettings + .surfaceContentRowMargins() } + .backgroundSecondary() } +} - extension iCloudSettingsView { - private var iOSSettings: some View { - VStack(alignment: .center, spacing: 0) { - soundsAndVibrations - } +extension iCloudSettingsView { + private var iOSSettings: some View { + VStack(alignment: .center, spacing: 0) { + soundsAndVibrations } } +} - extension iCloudSettingsView { - private var soundsAndVibrations: some View { - SectionView { - VStack(spacing: .zero) { - if FeatureFlags.app.сloudKit.valueOrFalse { - Switch(isOn: $settingsService.cloudKitEnabled) { - Row(L10n.Settings.iCloudSync) { - Image.Weather.Cloud.square.icon() - } - .premium() +extension iCloudSettingsView { + private var soundsAndVibrations: some View { + SectionView { + VStack(spacing: .zero) { + if FeatureFlags.app.сloudKit.valueOrFalse { + Switch(isOn: $settingsService.cloudKitEnabled) { + Row(L10n.Settings.iCloudSync) { + Image.Weather.Cloud.square.icon() } - .onPremiumTap() + .premium() } + .onPremiumTap() + } - if FeatureFlags.secure.CVVCodes.valueOrFalse { - Switch(isOn: $settingsService.cloudKitCVVEnabled) { - Row(L10n.Security.iCloudSyncCVVDescriptionCloudKit, - subtitle: settingsService.cloudKitCVVEnabled ? L10n.Security.iCloudSyncCVVDescriptionCloudKit : L10n.Security.iCloudSyncCVVDescriptionLocal) - { - Image.Security.cloudLock - .icon() - .frame(width: 24, height: 24) - } - .premium() - .onPremiumTap() + if FeatureFlags.secure.CVVCodes.valueOrFalse { + Switch(isOn: $settingsService.cloudKitCVVEnabled) { + Row(L10n.Security.iCloudSyncCVVDescriptionCloudKit, + subtitle: settingsService.cloudKitCVVEnabled ? L10n.Security.iCloudSyncCVVDescriptionCloudKit : L10n.Security.iCloudSyncCVVDescriptionLocal) + { + Image.Security.cloudLock + .icon() + .frame(width: 24, height: 24) } + .premium() + .onPremiumTap() } + } - if FeatureFlags.app.healthKit.valueOrFalse { - Switch(isOn: $settingsService.healthKitEnabled) { - Row("HealthKit synchronization", subtitle: "After switching on, data from the Health app will be downloaded") { - Image.Romantic.heart.icon() - } + if FeatureFlags.app.healthKit.valueOrFalse { + Switch(isOn: $settingsService.healthKitEnabled) { + Row("HealthKit synchronization", subtitle: "After switching on, data from the Health app will be downloaded") { + Image.Romantic.heart.icon() } } } } } } -#endif +} diff --git a/Sources/OversizeKit/SystemKit/SystemServices.swift b/Sources/OversizeKit/SystemKit/SystemServices.swift index 07602e9..e68a0bc 100644 --- a/Sources/OversizeKit/SystemKit/SystemServices.swift +++ b/Sources/OversizeKit/SystemKit/SystemServices.swift @@ -33,7 +33,7 @@ public struct SystemServicesModifier: ViewModifier { } public init() {} - + @State private var screnSize: ScreenSize = .init(width: 375, height: 667) public func body(content: Content) -> some View { @@ -74,7 +74,7 @@ public struct SystemServicesModifier: ViewModifier { #endif .premiumStatus(isPremium) .theme(ThemeSettings()) - .screenSize(screnSize) + .screenSize(screnSize) } } }