Skip to content

Commit f33313a

Browse files
committed
Beautiful gradient animation, fixed loading spinner, made stars look like web
1 parent 28e3a86 commit f33313a

File tree

17 files changed

+675
-409
lines changed

17 files changed

+675
-409
lines changed

Example/CommandBarIOS.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
FF409B4A2B2F76C900D2A3CD /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF409B492B2F76C900D2A3CD /* GradientView.swift */; };
2020
FF409B4C2B2F7B0800D2A3CD /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF409B4B2B2F7B0800D2A3CD /* Toast.swift */; };
2121
FF409B502B2FB49C00D2A3CD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FF409B4F2B2FB49C00D2A3CD /* LaunchScreen.storyboard */; };
22+
FF409B522B30995800D2A3CD /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF409B512B30995800D2A3CD /* Color.swift */; };
2223
FFB6A38B2B1BC93D0036D16F /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB6A38A2B1BC93D0036D16F /* App.swift */; };
2324
FFB6A38D2B1E27850036D16F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB6A38C2B1E27850036D16F /* AppDelegate.swift */; };
2425
FFB6A3902B1F98860036D16F /* ConfettiSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = FFB6A38F2B1F98860036D16F /* ConfettiSwiftUI */; };
@@ -57,6 +58,7 @@
5758
FF409B492B2F76C900D2A3CD /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
5859
FF409B4B2B2F7B0800D2A3CD /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = "<group>"; };
5960
FF409B4F2B2FB49C00D2A3CD /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
61+
FF409B512B30995800D2A3CD /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
6062
FFB6A38A2B1BC93D0036D16F /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
6163
FFB6A38C2B1E27850036D16F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
6264
/* End PBXFileReference section */
@@ -181,6 +183,7 @@
181183
FF409B472B2F717200D2A3CD /* Button.swift */,
182184
FF409B492B2F76C900D2A3CD /* GradientView.swift */,
183185
FF409B4B2B2F7B0800D2A3CD /* Toast.swift */,
186+
FF409B512B30995800D2A3CD /* Color.swift */,
184187
);
185188
path = Views;
186189
sourceTree = "<group>";
@@ -371,6 +374,7 @@
371374
FF409B4C2B2F7B0800D2A3CD /* Toast.swift in Sources */,
372375
FFB6A38B2B1BC93D0036D16F /* App.swift in Sources */,
373376
FF409B412B2F6A7200D2A3CD /* SceneDelegate.swift in Sources */,
377+
FF409B522B30995800D2A3CD /* Color.swift in Sources */,
374378
);
375379
runOnlyForDeploymentPostprocessing = 0;
376380
};

Example/CommandBarIOS/App.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct CommandBarIOSExampleApp: App {
1111
WindowGroup {
1212
HomeView()
1313
}
14+
1415
}
1516

1617
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import Foundation
2+
import SwiftUI
3+
4+
extension Color {
5+
func uiColor() -> UIColor {
6+
7+
if #available(iOS 14.0, *) {
8+
return UIColor(self)
9+
}
10+
11+
let components = self.components()
12+
return UIColor(red: components.r, green: components.g, blue: components.b, alpha: components.a)
13+
}
14+
15+
private func components() -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) {
16+
17+
let scanner = Scanner(string: self.description.trimmingCharacters(in: CharacterSet.alphanumerics.inverted))
18+
var hexNumber: UInt64 = 0
19+
var r: CGFloat = 0.0, g: CGFloat = 0.0, b: CGFloat = 0.0, a: CGFloat = 0.0
20+
21+
let result = scanner.scanHexInt64(&hexNumber)
22+
if result {
23+
r = CGFloat((hexNumber & 0xff000000) >> 24) / 255
24+
g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
25+
b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
26+
a = CGFloat(hexNumber & 0x000000ff) / 255
27+
}
28+
return (r, g, b, a)
29+
}
30+
31+
static func random() -> Color {
32+
let red = Double.random(in: 0..<1)
33+
let green = Double.random(in: 0..<1)
34+
let blue = Double.random(in: 0..<1)
35+
return Color(red: red, green: green, blue: blue)
36+
}
37+
38+
init(uiColor: UIColor) {
39+
self.init(red: Double(uiColor.components.red),
40+
green: Double(uiColor.components.green),
41+
blue: Double(uiColor.components.blue),
42+
opacity: Double(uiColor.components.alpha))
43+
}
44+
45+
func lighter(by percentage: CGFloat = 30.0) -> Color {
46+
if let uiColor = self.uiColor().lighter(by: percentage) {
47+
return Color(uiColor: uiColor)
48+
}
49+
return self
50+
51+
}
52+
53+
func darker(by percentage: CGFloat = 30.0) -> Color {
54+
if let uiColor = self.uiColor().darker(by: percentage) {
55+
return Color(uiColor: uiColor)
56+
}
57+
return self
58+
59+
}
60+
61+
func adjust(by percentage: CGFloat = 30.0) -> Color {
62+
let components = self.components()
63+
return Color(red: min(Double(components.r + percentage/100), 1.0),
64+
green: min(Double(components.g + percentage/100), 1.0),
65+
blue: min(Double(components.b + percentage/100), 1.0),
66+
opacity: Double(components.a))
67+
}
68+
}
69+
70+
71+
extension UIColor {
72+
var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
73+
var red: CGFloat = 0
74+
var green: CGFloat = 0
75+
var blue: CGFloat = 0
76+
var alpha: CGFloat = 0
77+
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
78+
79+
return (red, green, blue, alpha)
80+
}
81+
func lighter(by percentage: CGFloat = 30.0) -> UIColor? {
82+
return self.adjust(by: abs(percentage) )
83+
}
84+
85+
func darker(by percentage: CGFloat = 30.0) -> UIColor? {
86+
return self.adjust(by: -1 * abs(percentage) )
87+
}
88+
89+
func adjust(by percentage: CGFloat = 30.0) -> UIColor? {
90+
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
91+
if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
92+
return UIColor(red: min(red + percentage/100, 1.0),
93+
green: min(green + percentage/100, 1.0),
94+
blue: min(blue + percentage/100, 1.0),
95+
alpha: alpha)
96+
} else {
97+
return nil
98+
}
99+
}
100+
}

Example/CommandBarIOS/Views/GradientView.swift

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,78 @@ import SwiftUI
22
import UIKit
33

44
struct GradientView: View {
5+
6+
@State private var stage: Double = 0
7+
private let maxStages: Double = 10.0
8+
9+
private let startColor: Color = .purple
10+
private let endColor: Color = .blue.darker(by: 2)
11+
12+
private let timer = Timer.publish(every: 0.1, on: .main, in: .commonModes).autoconnect() // adjust as needed
13+
514
var body: some View {
615
ZStack {
7-
RadialGradient(
8-
gradient: Gradient(colors: [Color(hue: 198/360, saturation: 1, brightness: 0.8), Color.clear]),
9-
center: .init(x: 0.82, y: 0.65),
10-
startRadius: 0,
11-
endRadius: 0.55 * UIScreen.main.bounds.width
12-
)
13-
RadialGradient(
14-
gradient: Gradient(colors: [Color(hue: 220/360, saturation: 0.37, brightness: 0.97), Color.clear]),
15-
center: .init(x: 0.47, y: 0.33),
16-
startRadius: 0,
17-
endRadius: 0.59 * UIScreen.main.bounds.width
18-
)
19-
20-
}.background(
21-
LinearGradient(gradient: Gradient(colors: [.purple, .blue]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
22-
)
16+
ForEach(0..<(Int(maxStages)), id: \.self) { i in
17+
gradient(for: i)
18+
.opacity(opacity(for: i))
19+
.animation(.linear(duration: 0.4), value: self.stage)
20+
21+
}
22+
}
23+
.edgesIgnoringSafeArea(.all)
24+
.onAppear{
25+
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
26+
withAnimation {
27+
self.stage = (self.stage + 1)
28+
}
29+
}
30+
}
2331
}
2432

25-
}
26-
27-
struct GradientBackgroundRepresentable: UIViewControllerRepresentable {
33+
private func gradient(for index: Int) -> LinearGradient {
34+
print(index)
35+
let points = gradientPoints(for: index)
36+
return LinearGradient(
37+
gradient: Gradient(colors: [startColor, endColor]),
38+
startPoint: points.0,
39+
endPoint: points.1
40+
)
41+
}
2842

29-
func makeUIViewController(context: Context) -> UIViewController {
30-
let hostingController = UIHostingController(rootView: GradientView())
31-
return hostingController
43+
private func gradientPoints(for index: Int) -> (UnitPoint, UnitPoint) {
44+
switch index {
45+
case 0:
46+
return (.topLeading, .bottomTrailing)
47+
case 1:
48+
return (.top, .bottom)
49+
case 2:
50+
return (.topTrailing, .bottomLeading)
51+
case 3:
52+
return (.trailing, .leading)
53+
case 4:
54+
return (.bottomTrailing, .topLeading)
55+
case 5:
56+
return (.bottom, .top)
57+
case 6:
58+
return (.bottomLeading, .topTrailing)
59+
case 7:
60+
return (.leading, .trailing)
61+
case 8:
62+
return (.topLeading, .bottomTrailing)
63+
default:
64+
return (.topLeading, .bottomTrailing)
65+
}
3266
}
3367

34-
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
35-
68+
private func opacity(for index: Int) -> Double {
69+
let adjustedStage = (self.stage - Double(index)) / self.maxStages
70+
return max(0, 0.5 * cos(2 * Double.pi * adjustedStage) + 0.5)
3671
}
3772
}
38-
class GradientBackgroundViewController: UIViewController {
39-
40-
override func viewDidLoad() {
41-
super.viewDidLoad()
42-
43-
let gradientBackgroundView = UIHostingController(rootView: GradientView())
44-
// Add as a child of the current view controller.
45-
addChildViewController(gradientBackgroundView)
4673

47-
// Add the SwiftUI view to the view controller view hierarchy.
48-
view.addSubview(gradientBackgroundView.view)
4974

50-
// Setup constraints to update the SwiftUI view boundaries.
51-
// gradientBackgroundView.view.translatesAutoresizingMaskIntoConstraints = false
52-
// NSLayoutConstraint.activate([
53-
// gradientBackgroundView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
54-
// gradientBackgroundView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
55-
// gradientBackgroundView.view.topAnchor.constraint(equalTo: view.topAnchor),
56-
// gradientBackgroundView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
57-
// ])
58-
//
59-
// // Notify the hosting controller that it has been moved to the current view controller.
60-
// gradientBackgroundView.didMove(toParent: self)
75+
struct GradientView_Previews: PreviewProvider {
76+
static var previews: some View {
77+
GradientView()
6178
}
6279
}

Example/CommandBarIOS/Views/HomeView.swift

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,24 @@ struct HomeView: View {
1515
VStack(alignment: .center) {
1616
ZStack {
1717
GradientView()
18-
Main
19-
18+
VStack {
19+
Spacer()
20+
VStack {
21+
LogoView()
22+
.shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 5)
23+
Text("Welcome to CommandBar!")
24+
.multilineTextAlignment(.center)
25+
.font(.title)
26+
}
27+
Spacer()
28+
VStack() {
29+
CustomButton(title: "Trigger Test Event") {
30+
// 3. Track Events
31+
CommandBarSDK.shared.trackEvent(event: "test_event")
32+
}
33+
}
34+
}.padding(.horizontal)
35+
2036
if ORG_ID == "" {
2137
VStack(alignment: .leading) {
2238
Toast(message: "Org ID not set.")
@@ -33,27 +49,4 @@ struct HomeView: View {
3349
}
3450
}
3551
}
36-
37-
var Main: some View {
38-
VStack {
39-
Spacer()
40-
VStack {
41-
LogoView()
42-
.shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 5)
43-
Text("Welcome to CommandBar!")
44-
.multilineTextAlignment(.center)
45-
.font(.title)
46-
}
47-
Spacer()
48-
VStack() {
49-
CustomButton(title: "Trigger Test Event") {
50-
// 3. Track Events
51-
CommandBarSDK.shared.trackEvent(event: "test_event")
52-
}
53-
CustomButton(title: "Open HelpHub") {
54-
CommandBarSDK.shared.openHelpHub()
55-
}
56-
}
57-
}.padding(.horizontal)
58-
}
5952
}

Example/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use_frameworks!
22

3-
platform :ios, '15.0'
3+
platform :ios, '13.0'
44

55
target 'CommandBarIOS_Example' do
66
pod 'CommandBarIOS', :path => '../'

Example/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ EXTERNAL SOURCES:
1111
SPEC CHECKSUMS:
1212
CommandBarIOS: 6c8489472ed8f1f033d36b095b44f2227f9115ec
1313

14-
PODFILE CHECKSUM: 3a5c97c63efc3c50665cd2b1d284e459972dc9db
14+
PODFILE CHECKSUM: 6d9bb10e6d829f27934a51717623c1fd87cac734
1515

1616
COCOAPODS: 1.14.2

Example/Pods/Manifest.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)