├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── AlertX
│ ├── AlertX-Elements
│ ├── AlertX.swift
│ ├── Button.swift
│ └── Window.swift
│ ├── Essentials
│ ├── AlertXViewController.swift
│ ├── AlertX_View.swift
│ └── View+Extension.swift
│ └── Options
│ ├── Animations.swift
│ └── Themes.swift
└── Tests
├── AlertXTests
├── AlertXTests.swift
└── XCTestManifests.swift
└── LinuxMain.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Neel Makhecha
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "AlertX",
8 | platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13)],
9 | products: [
10 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
11 | .library(
12 | name: "AlertX",
13 | targets: ["AlertX"]),
14 | ],
15 | dependencies: [
16 | // Dependencies declare other packages that this package depends on.
17 | // .package(url: /* package url */, from: "1.0.0"),
18 | ],
19 | targets: [
20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
21 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
22 | .target(
23 | name: "AlertX",
24 | dependencies: []),
25 | .testTarget(
26 | name: "AlertXTests",
27 | dependencies: ["AlertX"]),
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AlertX
2 |
3 | ## Custom alerts in SwiftUI made easy
4 |
5 | AlertX is a library for SwiftUI projects to have custom alerts that can be implemented in a very easy and simple way, just like implementing built-in system alerts.
6 |
7 | ## A Quick Example
8 |
9 |
10 | import SwiftUI
11 | import AlertX
12 | ...
13 | ...
14 |
15 |
16 | Button(action: {
17 |
18 | self.showAlertX.toggle()
19 |
20 | }, label: {
21 |
22 | Text("Show AlertX")
23 |
24 | }).alertX(isPresented: $showAlertX, content: {
25 |
26 | AlertX(title: Text("AlertX Title"),
27 | message: Text("An optional message indicating some action goes here..."),
28 | primaryButton: .cancel(),
29 | secondaryButton: .default(Text("Done"), action: {
30 | // Some action
31 | }),
32 | theme: .graphite(withTransparency: true, roundedCorners: true),
33 | animation: .classicEffect())
34 | })
35 |
36 |
37 | 
38 |
39 | # Documentation
40 |
41 | ## Working and Installation
42 |
43 | AlertX is a Swift Package and can be installed just like installing any other Swift Package libraries.
44 |
45 | 1. In your Xcode project, navigate to File > Swift Packages > Add Package Dependency.
46 | 2. In the package repository URL, enter this: https://github.com/neel-makhecha/AlertX.git
47 |
48 | One awesome thing about AlertX is that the implementation of it is much similar to the implementation of system's built in alerts. Once AlertX is installed and imported, a new instance method `alertX(isPresented: Binding, content: () -> AlertX)` can be used with any SwiftUI View, similar to the built-in method.
49 |
50 |
51 | ## Themes
52 |
53 | The appearance of AlertX is customizable with themes. There are a bunch of pre-defined themes already included, but you can also have your very own theme.
54 |
55 | All the themes of AlertX are of type `AlertX.Theme`. There are static methods for each pre-defined theme. Here's an example of how you can apply a theme:
56 |
57 | Button(action: {
58 | self.showAlertX.toggle()
59 | }, label: {
60 | Text("Show AlertX")
61 | }).alertX(isPresented: $showAlertX, content: {
62 | AlertX(title: Text("The Title"), theme: .wine())
63 | })
64 |
65 |
66 |
67 |
68 | For the static methods of all pre-defined themes, you can also pass boolean to enable or disable transparency and rounded corners for alert and buttons. By default, for all themes, transparency is true and rounded corners is set to false.
69 |
70 | AlertX.Theme.wine(withTransparency: false, roundedCorners: true)
71 |
72 |
73 |
74 | (The above example uses wine theme with transparency false and roundedCorners true)
75 |
76 | Here's a list of all pre-defined themes:
77 |
78 | graphite (default)
79 | light
80 | dark
81 | sun
82 | cherry
83 | mint
84 | wine
85 |
86 |
87 | To create a custom theme, use the following method which offers a variety of options:
88 |
89 |
90 | AlertX.Theme.custom(windowColor: Color,
91 | alertTextColor: Color,
92 | enableShadow: Bool,
93 | enableRoundedCorners: Bool,
94 | enableTransparency: Bool,
95 | cancelButtonColor: Color,
96 | cancelButtonTextColor: Color,
97 | defaultButtonColor: Color,
98 | defaultButtonTextColor: Color,
99 | roundedCornerRadius: CGFloat)
100 |
101 |
102 | ## Animations
103 |
104 | Animations for AlertX can be applied using `AlertX.AnimationX`. There are various cool pre-defined animations already included. Similar to themes, they can be applied using static method for each animation present inside `AlertX.AnimationX`.
105 |
106 | 
107 |
108 | Here's how you can apply an animation:
109 |
110 | `AlertX(title: Text("Some Title"), animation: .fadeEffect())`
111 |
112 | Here's a list of all pre-defined animations:
113 |
114 | defaultEffect
115 | classicEffect
116 | zoomEffect
117 | fadeEffect
118 | slideUpEffect
119 |
120 | You can also create your own animations just like you would for any other SwiftUI View using the following method:
121 |
122 | AlertX.AnimationX.custom(withTransition: AnyTransition)
123 |
124 | ## Adding More Buttons
125 |
126 | Use the initialiser which takes an array of AlertX.Button (buttonStack) to add as many buttons as you want in the alert. Here's an example (body of the closure to be passed in the alertX method):
127 |
128 |
129 | let buttons = [
130 | AlertX.Button.default(Text("Yes")),
131 | AlertX.Button.default(Text("No")),
132 | AlertX.Button.cancel()]
133 |
134 | return AlertX(title: Text("Are you sure about this?"), buttonStack: buttons)
135 |
136 | ## Future Work
137 |
138 | 1. Support for text fields.
139 | 2. Even more and better pre-defined themes and animations.
140 |
141 | ## Contributing
142 |
143 | You are most welcome in contributing to this project with either new features (maybe one mentioned from the future work or anything else), refactoring and improving the code or adding new pre-defined themes and animations. Also, feel free to give suggestions and feedbacks.
144 |
145 |
146 | Created with ❤️ by Neel Makhecha.
147 |
148 | Get in touch on [Twitter](https://twitter.com/neelmakhecha). Visit: [neelmakhecha.tech](https://neelmakhecha.tech)
149 |
--------------------------------------------------------------------------------
/Sources/AlertX/AlertX-Elements/AlertX.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertX.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 |
8 | import SwiftUI
9 |
10 | public struct AlertX: View {
11 |
12 | // Constant Parameters
13 | static let defaultCornerRadius: CGFloat = 25.0
14 | static let defaultShadowRadius: CGFloat = 1.0
15 | static let defaultAlertOpacity: Double = 0.9
16 |
17 |
18 | // Variable parameters
19 | var alertX_cornerRadius: CGFloat
20 | var alertX_shadowRadius: CGFloat
21 | var alertX_shadowColor: Color = Color.black
22 |
23 | // AlertX Fields
24 | var alertX_title: Text
25 | var alertX_message: Text?
26 |
27 | var buttonStack: [AlertX.Button]?
28 |
29 | // Theme and Animation
30 | var theme: AlertX.Theme = AlertX.Theme()
31 | var animation: AlertX.AnimationX = AlertX.AnimationX()
32 |
33 | public init(title: Text, message: Text? = nil, primaryButton: AlertX.Button? = .default(Text("OK")), secondaryButton: AlertX.Button? = nil, theme: AlertX.Theme = AlertX.Theme(), animation: AlertX.AnimationX = .defaultEffect()) {
34 | self.alertX_title = title
35 | self.alertX_message = message
36 |
37 | self.buttonStack = [primaryButton!]
38 | if let secondaryButton = secondaryButton {
39 | self.buttonStack?.append(secondaryButton)
40 | }
41 |
42 | self.theme = theme
43 | self.alertX_cornerRadius = theme.enableRoundedCorners ? theme.roundedCornerRadius : 0.0
44 | self.alertX_shadowRadius = theme.enableShadow ? AlertX.defaultShadowRadius : 0.0
45 |
46 | self.animation = animation
47 | }
48 |
49 | public init(title: Text, message: Text? = nil, buttonStack: [AlertX.Button] = [AlertX.Button.default(Text("OK"))], theme: AlertX.Theme = AlertX.Theme(), animation: AlertX.AnimationX = .defaultEffect()) {
50 | self.alertX_title = title
51 | self.alertX_message = message
52 |
53 | self.buttonStack = buttonStack
54 |
55 | self.theme = theme
56 | self.alertX_cornerRadius = theme.enableRoundedCorners ? theme.roundedCornerRadius : 0.0
57 | self.alertX_shadowRadius = theme.enableShadow ? AlertX.defaultShadowRadius : 0.0
58 |
59 | self.animation = animation
60 | }
61 |
62 | public var body: some View {
63 |
64 | ZStack {
65 |
66 | VStack {
67 |
68 | alertX_title
69 | .padding(.init(top: 35, leading: 25, bottom: 15, trailing: 25))
70 | .foregroundColor(theme.alertTextColor)
71 | .font(.headline)
72 |
73 | alertX_message
74 | .padding(.init(top: 0, leading: 25, bottom: 35, trailing: 25))
75 | .foregroundColor(theme.alertTextColor)
76 |
77 |
78 | if buttonStack != nil {
79 |
80 | if buttonStack!.count < 3 {
81 |
82 | HStack {
83 | ForEach((0...(buttonStack?.count ?? 0)-1), id: \.self) {
84 |
85 | self.buttonStack?[$0]
86 | .background(self.buttonStack![$0].buttonType == AlertX.ButtonType.default ? self.theme.defaultButtonColor : self.theme.cancelButtonColor)
87 | .foregroundColor(self.buttonStack![$0].buttonType == AlertX.ButtonType.default ? self.theme.defaultButtonTextColor : self.theme.cancelButtonTextColor)
88 | .cornerRadius(self.theme.enableRoundedCorners ? theme.roundedCornerRadius : 0.0)
89 |
90 | }
91 | }.padding()
92 |
93 | } else {
94 |
95 | VStack {
96 |
97 | ForEach((0...(buttonStack!.count)-1), id: \.self) {
98 |
99 | self.buttonStack?[$0]
100 | .background(self.buttonStack![$0].buttonType == AlertX.ButtonType.default ? self.theme.defaultButtonColor : self.theme.cancelButtonColor)
101 | .foregroundColor(self.buttonStack![$0].buttonType == AlertX.ButtonType.default ? self.theme.defaultButtonTextColor : self.theme.cancelButtonTextColor)
102 | .cornerRadius(self.theme.enableRoundedCorners ? theme.roundedCornerRadius : 0.0)
103 | .padding(.bottom, 10)
104 |
105 | }
106 |
107 | }.padding()
108 |
109 | }
110 |
111 | }
112 |
113 | }.background(AlertX.Window(color: theme.windowColor, cornerRadius: self.theme.enableRoundedCorners ? theme.roundedCornerRadius : 0.0, transparencyEnabled: theme.enableTransparency))
114 | .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
115 | .padding()
116 | .shadow(radius: alertX_shadowRadius)
117 | .cornerRadius(alertX_cornerRadius)
118 |
119 | }
120 |
121 | }
122 | }
123 |
124 |
125 |
--------------------------------------------------------------------------------
/Sources/AlertX/AlertX-Elements/Button.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ButtonX.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import SwiftUI
10 |
11 | typealias SystemButton = Button
12 | extension AlertX {
13 |
14 | enum ButtonType {
15 | case `default`
16 | case cancel
17 | }
18 | public struct Button: View {
19 |
20 | let text: Text
21 | var buttonType: AlertX.ButtonType = .default
22 |
23 | var buttonAction: (() -> Void)?
24 |
25 | private init(text: Text, buttonType: AlertX.ButtonType, action: (() -> Void)? = {}) {
26 | self.text = text
27 | self.buttonType = buttonType
28 | self.buttonAction = action
29 | }
30 |
31 | public var body: some View {
32 | SystemButton(action: {
33 |
34 | func prepareForDismiss(completion: @escaping () -> Void) {
35 |
36 | if let reference = AlertX_View.currentAlertXVCReference {
37 | AlertX_View.currentAlertXVCReference = nil
38 | reference.dismiss(animated: true, completion: completion)
39 |
40 | } else {
41 | completion()
42 | }
43 |
44 | }
45 |
46 | prepareForDismiss {
47 | buttonAction?()
48 | }
49 |
50 | }, label: {
51 | text
52 | .frame(minWidth: 150, maxWidth: .infinity, alignment: .center)
53 | .padding(.init(top: 10, leading: 10, bottom: 10, trailing: 10))
54 | .shadow(radius: 1.0)
55 | })
56 |
57 | }
58 |
59 | // button types
60 | public static func `default`(_ label: Text, action: (() -> Void)? = {}) -> AlertX.Button {
61 | return AlertX.Button(text: label, buttonType: .default, action: action)
62 | }
63 |
64 | public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> AlertX.Button {
65 | return AlertX.Button(text: label, buttonType: .cancel, action: action)
66 | }
67 |
68 | public static func cancel(_ action: (() -> Void)? = {}) -> AlertX.Button {
69 | return AlertX.Button(text: Text("Cancel"), buttonType: .cancel, action: action)
70 | }
71 |
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/AlertX/AlertX-Elements/Window.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Window.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import SwiftUI
10 |
11 | extension AlertX {
12 |
13 | struct Window: View {
14 |
15 | var windowColor: Color
16 | var windowColorOpacity: Double
17 | var cornerRadius: CGFloat
18 |
19 | public init(color: Color, cornerRadius: CGFloat, transparencyEnabled: Bool) {
20 | self.windowColor = color
21 | self.windowColorOpacity = transparencyEnabled ? AlertX.defaultAlertOpacity : 1.0
22 | self.cornerRadius = cornerRadius
23 | }
24 |
25 | var body: some View {
26 | Rectangle()
27 | .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
28 | .foregroundColor(windowColor.opacity(windowColorOpacity))
29 | .cornerRadius(cornerRadius)
30 | }
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/AlertX/Essentials/AlertXViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertXViewController.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import UIKit
10 | import SwiftUI
11 |
12 | class AlertXViewController: UIHostingController {
13 |
14 | var alertX_view: AlertX_View
15 | var isPresented: Binding
16 |
17 | init(alertX_view: AlertX_View, isPresented: Binding) {
18 | self.alertX_view = alertX_view
19 | self.isPresented = isPresented
20 | super.init(rootView: self.alertX_view)
21 | }
22 |
23 | required init?(coder: NSCoder) {
24 | fatalError("init(coder:) has not been implemented")
25 | }
26 |
27 | public override func viewWillDisappear(_ animated: Bool) {
28 | self.isPresented.wrappedValue = false
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/AlertX/Essentials/AlertX_View.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertX_View.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct AlertX_View: View {
12 |
13 | static var currentAlertXVCReference: AlertXViewController?
14 |
15 | @Binding var visible: Bool
16 | @State var show: Bool = false
17 |
18 | let alertX: AlertX
19 |
20 | public var body: some View {
21 |
22 | ZStack {
23 |
24 | Rectangle()
25 | .foregroundColor(Color.black.opacity(0.25))
26 | .edgesIgnoringSafeArea(.all)
27 |
28 | if show {
29 | alertX
30 | .transition(self.alertX.animation.transition)
31 | }
32 |
33 | }.onAppear{
34 | Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false) { timer in
35 | withAnimation {
36 | if self.visible {
37 | self.show = true
38 | }
39 | }
40 | }
41 | }
42 |
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/AlertX/Essentials/View+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewExtension.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import SwiftUI
10 |
11 | extension View {
12 |
13 | public func alertX(isPresented: Binding, content: () -> AlertX) -> some View {
14 |
15 | let alertX_view = AlertX_View(visible: isPresented, alertX: content())
16 | let alertXVC = AlertXViewController(alertX_view: alertX_view, isPresented: isPresented)
17 | alertXVC.modalPresentationStyle = .overCurrentContext
18 | alertXVC.view.backgroundColor = UIColor.clear
19 | alertXVC.modalTransitionStyle = .crossDissolve
20 |
21 | if isPresented.wrappedValue {
22 | if AlertX_View.currentAlertXVCReference == nil {
23 | AlertX_View.currentAlertXVCReference = alertXVC
24 | }
25 |
26 | let viewController = self.topViewController()
27 | viewController?.present(alertXVC, animated: true, completion: nil)
28 | } else {
29 | alertXVC.dismiss(animated: true, completion: nil)
30 | }
31 |
32 | return self
33 | }
34 |
35 | private func topViewController(baseVC: UIViewController? = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController) -> UIViewController? {
36 |
37 | if let nav = baseVC as? UINavigationController {
38 | return topViewController(baseVC: nav.visibleViewController)
39 | }
40 | if let tab = baseVC as? UITabBarController {
41 | if let selected = tab.selectedViewController {
42 | return topViewController(baseVC: selected)
43 | }
44 | }
45 | if let presented = baseVC?.presentedViewController {
46 | return topViewController(baseVC: presented)
47 | }
48 | return baseVC
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/AlertX/Options/Animations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Animations.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import SwiftUI
10 |
11 | extension AlertX {
12 |
13 | public struct AnimationX {
14 |
15 | let transition: AnyTransition
16 |
17 | public init() {
18 | self = AlertX.AnimationX.defaultEffect()
19 | }
20 |
21 | private init(transition: AnyTransition) {
22 | self.transition = transition
23 | }
24 |
25 | public static func custom(withTransition transition: AnyTransition) -> AlertX.AnimationX {
26 | return AlertX.AnimationX(transition: transition)
27 | }
28 |
29 | public static func defaultEffect() -> AlertX.AnimationX {
30 | let transition = AnyTransition.scale(scale: 1.2).combined(with: .opacity).animation(.easeOut(duration: 0.15))
31 | return AlertX.AnimationX(transition: transition)
32 | }
33 |
34 | public static func classicEffect() -> AlertX.AnimationX {
35 | let spring = Animation.spring(response: 0.25, dampingFraction: 0.6, blendDuration: 0.25)
36 | let transition = AnyTransition.scale.combined(with: .opacity).animation(spring)
37 | return AlertX.AnimationX(transition: transition)
38 | }
39 |
40 | public static func zoomEffect() -> AlertX.AnimationX {
41 | let transition = AnyTransition.scale.combined(with: .opacity)
42 | return AlertX.AnimationX(transition: transition)
43 | }
44 |
45 | public static func fadeEffect() -> AlertX.AnimationX {
46 | let transition = AnyTransition.opacity
47 | return AlertX.AnimationX(transition: transition)
48 | }
49 |
50 | public static func slideUpEffect() -> AlertX.AnimationX {
51 | let transition = AnyTransition.move(edge: .bottom).combined(with: .opacity).animation(.easeOut)
52 | return AlertX.AnimationX(transition: transition)
53 | }
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/Sources/AlertX/Options/Themes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertX+Options.swift
3 | // AlertX
4 | //
5 | // Copyright © 2020 Neel Makhecha. All rights reserved.
6 | // https://github.com/neel-makhecha/AlertX
7 | //
8 |
9 | import SwiftUI
10 |
11 | extension AlertX {
12 |
13 | public struct Theme {
14 |
15 | //Default theme
16 | public static var defaultTheme: AlertX.Theme = graphite()
17 | public static let defaultCornerRadius = AlertX.defaultCornerRadius
18 |
19 | // General Properties
20 | var windowColor: Color
21 | var alertTextColor: Color
22 | var enableShadow: Bool
23 | var enableRoundedCorners: Bool
24 | var roundedCornerRadius: CGFloat
25 | var enableTransparency: Bool
26 |
27 | // Button Properties
28 | var cancelButtonColor: Color
29 | var cancelButtonTextColor: Color
30 | var defaultButtonColor: Color
31 | var defaultButtonTextColor: Color
32 |
33 | // Public init
34 | public init() {
35 | self = AlertX.Theme.defaultTheme
36 | }
37 |
38 | // Private init
39 | private init(windowColor: Color, alertTextColor: Color, enableShadow: Bool, enableRoundedCorners: Bool, enableTransparency: Bool, cancelButtonColor: Color, cancelButtonTextColor: Color, defaultButtonColor: Color, defaultButtonTextColor: Color, roundedCornerRadius: CGFloat = defaultCornerRadius) {
40 |
41 | self.windowColor = windowColor
42 | self.alertTextColor = alertTextColor
43 | self.enableShadow = enableShadow
44 | self.enableRoundedCorners = enableRoundedCorners
45 | self.roundedCornerRadius = roundedCornerRadius
46 | self.enableTransparency = enableTransparency
47 |
48 | self.cancelButtonColor = cancelButtonColor
49 | self.cancelButtonTextColor = cancelButtonTextColor
50 | self.defaultButtonColor = defaultButtonColor
51 | self.defaultButtonTextColor = defaultButtonTextColor
52 | }
53 |
54 | // Define custom theme
55 | public static func custom(windowColor: Color, alertTextColor: Color, enableShadow: Bool, enableRoundedCorners: Bool, enableTransparency: Bool, cancelButtonColor: Color, cancelButtonTextColor: Color, defaultButtonColor: Color, defaultButtonTextColor: Color, roundedCornerRadius: CGFloat = defaultCornerRadius) -> AlertX.Theme {
56 |
57 | let theme = AlertX.Theme(windowColor: windowColor,
58 | alertTextColor: alertTextColor,
59 | enableShadow: enableShadow,
60 | enableRoundedCorners: enableRoundedCorners,
61 | enableTransparency: enableTransparency,
62 | cancelButtonColor: cancelButtonColor,
63 | cancelButtonTextColor: cancelButtonTextColor,
64 | defaultButtonColor: defaultButtonColor,
65 | defaultButtonTextColor: defaultButtonTextColor,
66 | roundedCornerRadius: roundedCornerRadius)
67 |
68 | return theme
69 | }
70 |
71 | // Predefined themes
72 |
73 | public static func graphite(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
74 | let theme = AlertX.Theme(windowColor: Color(red: 94/255, green: 94/255, blue: 94/255),
75 | alertTextColor: Color.white,
76 | enableShadow: true,
77 | enableRoundedCorners: roundedCorners,
78 | enableTransparency: transparency,
79 | cancelButtonColor: Color(red: 213/255, green: 213/255, blue: 213/255),
80 | cancelButtonTextColor: Color.black,
81 | defaultButtonColor: Color(red: 0/255, green: 0/255, blue: 0/255),
82 | defaultButtonTextColor: Color.white)
83 |
84 | return theme
85 | }
86 |
87 | public static func light(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
88 | let theme = AlertX.Theme(windowColor: Color(red: 255/255, green: 255/255, blue: 255/255),
89 | alertTextColor: Color.black,
90 | enableShadow: true,
91 | enableRoundedCorners: roundedCorners,
92 | enableTransparency: transparency,
93 | cancelButtonColor: Color(red: 213/255, green: 213/255, blue: 213/255),
94 | cancelButtonTextColor: Color.black,
95 | defaultButtonColor: Color(red: 146/255, green: 146/255, blue: 146/255),
96 | defaultButtonTextColor: Color.white)
97 |
98 | return theme
99 | }
100 |
101 | public static func dark(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
102 | let theme = AlertX.Theme(windowColor: Color(red: 0/255, green: 0/255, blue: 0/255),
103 | alertTextColor: Color.white,
104 | enableShadow: true,
105 | enableRoundedCorners: roundedCorners,
106 | enableTransparency: transparency,
107 | cancelButtonColor: Color(red: 213/255, green: 213/255, blue: 213/255),
108 | cancelButtonTextColor: Color.black,
109 | defaultButtonColor: Color(red: 94/255, green: 94/255, blue: 94/255),
110 | defaultButtonTextColor: Color.white)
111 |
112 | return theme
113 | }
114 |
115 | public static func sun(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
116 | let theme = AlertX.Theme(windowColor: Color(red: 253/255, green: 184/255, blue: 51/255),
117 | alertTextColor: Color(red: 118/255, green: 82/255, blue: 14/255),
118 | enableShadow: true,
119 | enableRoundedCorners: roundedCorners,
120 | enableTransparency: transparency,
121 | cancelButtonColor: Color(red: 255/255, green: 213/255, blue: 62/255),
122 | cancelButtonTextColor: Color(red: 118/255, green: 82/255, blue: 14/255),
123 | defaultButtonColor: Color(red: 255/255, green: 247/255, blue: 94/255),
124 | defaultButtonTextColor: Color(red: 118/255, green: 82/255, blue: 14/255))
125 |
126 | return theme
127 | }
128 |
129 | public static func cherry(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
130 | let theme = AlertX.Theme(windowColor: Color(red: 239/255, green: 35/255, blue: 60/255),
131 | alertTextColor: Color.white,
132 | enableShadow: true,
133 | enableRoundedCorners: roundedCorners,
134 | enableTransparency: transparency,
135 | cancelButtonColor: Color(red: 216/255, green: 0/255, blue: 50/255),
136 | cancelButtonTextColor: Color.white,
137 | defaultButtonColor: Color(red: 255/255, green: 150/255, blue: 141/255),
138 | defaultButtonTextColor: Color.white)
139 |
140 | return theme
141 | }
142 |
143 | public static func mint(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
144 | let theme = AlertX.Theme(windowColor: Color(red: 111/255, green: 255/255, blue: 233/255),
145 | alertTextColor: Color(red: 11/255, green: 19/255, blue: 43/255),
146 | enableShadow: true,
147 | enableRoundedCorners: roundedCorners,
148 | enableTransparency: transparency,
149 | cancelButtonColor: Color(red: 91/255, green: 192/255, blue: 190/255),
150 | cancelButtonTextColor: Color.white,
151 | defaultButtonColor: Color(red: 11/255, green: 19/255, blue: 43/255),
152 | defaultButtonTextColor: Color.white)
153 |
154 | return theme
155 | }
156 |
157 | public static func wine(withTransparency transparency: Bool = true, roundedCorners: Bool = false) -> AlertX.Theme {
158 | let theme = AlertX.Theme(windowColor: Color(red: 100/255, green: 18/255, blue: 32/255),
159 | alertTextColor: Color.white,
160 | enableShadow: true,
161 | enableRoundedCorners: roundedCorners,
162 | enableTransparency: transparency,
163 | cancelButtonColor: Color(red: 178/255, green: 30/255, blue: 53/255),
164 | cancelButtonTextColor: Color.white,
165 | defaultButtonColor: Color(red: 224/255, green: 30/255, blue: 55/255),
166 | defaultButtonTextColor: Color.white)
167 |
168 | return theme
169 | }
170 |
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/Tests/AlertXTests/AlertXTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import AlertX
3 |
4 | final class AlertXTests: XCTestCase {
5 | func testExample() {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | XCTAssertEqual(AlertX().text, "Hello, World!")
10 | }
11 |
12 | static var allTests = [
13 | ("testExample", testExample),
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/Tests/AlertXTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(AlertXTests.allTests),
7 | ]
8 | }
9 | #endif
10 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import AlertXTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += AlertXTests.allTests()
7 | XCTMain(tests)
8 |
--------------------------------------------------------------------------------