-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathWatchOS_WIthFreeze.swift
More file actions
174 lines (155 loc) · 6.25 KB
/
WatchOS_WIthFreeze.swift
File metadata and controls
174 lines (155 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import SwiftUI
import WatchKit
// THIS VERSION SUPPORTS ALL APPLE WATCHES COMPATIBLE WITH WATCHOS 11
// MARK: The Apple intelligence glow effect function
// It is made up of 4 different layers.
struct GlowEffect: View {
@State private var gradientStops: [Gradient.Stop] = GlowEffect.generateGradientStops()
@State private var timers: [Timer] = []
var freeze: Bool
// Fetch the combined device properties
let deviceProperties = DeviceConfig.deviceProperties
var body: some View {
ZStack {
// First layer is the border around the edge
// The next 3 layers are the blurry layers closer to the middle of the screen
EffectNoBlur(gradientStops: gradientStops, width: 5, deviceProperties: deviceProperties)
Effect(gradientStops: gradientStops, width: 7, blur: 4, deviceProperties: deviceProperties)
Effect(gradientStops: gradientStops, width: 9, blur: 12, deviceProperties: deviceProperties)
Effect(gradientStops: gradientStops, width: 12, blur: 15, deviceProperties: deviceProperties)
}
.onAppear {
if !freeze {
startTimers()
}
}
.onChange(of: freeze) { isFrozen in
if isFrozen {
stopTimers()
} else {
startTimers()
}
}
.onDisappear {
stopTimers()
}
}
// MARK: Function to start the timers for the gradients
private func startTimers() {
stopTimers() // Ensure no existing timers are running
timers.append(
Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { _ in
withAnimation(.easeInOut(duration: 0.6)) {
gradientStops = GlowEffect.generateGradientStops()
}
}
)
}
// MARK: Function to stop the timers for the gradients
private func stopTimers() {
timers.forEach { $0.invalidate() }
timers.removeAll()
}
// Function to generate random gradient stops on an Angular Gradient
// MARK: Function to generate the colours of the Glow Effect
// Change the hex codes to change the colours
static func generateGradientStops() -> [Gradient.Stop] {
[
Gradient.Stop(color: Color(hex: "BC82F3"), location: Double.random(in: 0...1)),
Gradient.Stop(color: Color(hex: "F5B9EA"), location: Double.random(in: 0...1)),
//Gradient.Stop(color: Color(hex: "8D9FFF"), location: Double.random(in: 0...1)),
Gradient.Stop(color: Color(hex: "FF6778"), location: Double.random(in: 0...1)),
Gradient.Stop(color: Color(hex: "FFBA71"), location: Double.random(in: 0...1)),
Gradient.Stop(color: Color(hex: "C686FF"), location: Double.random(in: 0...1))
].sorted { $0.location < $1.location }
}
}
// MARK: These Effect Functions generate the different layers that make up the gradient effect
// Effect with blur for the inner layers
struct Effect: View {
var gradientStops: [Gradient.Stop]
var width: Double
var blur: Double
var deviceProperties: (cornerRoundness: Int, screenOffset: Int)
var body: some View {
RoundedRectangle(cornerRadius: CGFloat(deviceProperties.cornerRoundness))
.strokeBorder(
AngularGradient(
gradient: Gradient(stops: gradientStops),
center: .center
),
lineWidth: width
)
.frame(
width: WKInterfaceDevice.current().screenBounds.width,
height: WKInterfaceDevice.current().screenBounds.height
)
.padding(.top, -1 * CGFloat(deviceProperties.screenOffset))
.blur(radius: blur)
}
}
// Effect without blur for the outermost layer
struct EffectNoBlur: View {
var gradientStops: [Gradient.Stop]
var width: Double
var deviceProperties: (cornerRoundness: Int, screenOffset: Int)
var body: some View {
RoundedRectangle(cornerRadius: CGFloat(deviceProperties.cornerRoundness))
.strokeBorder(
AngularGradient(
gradient: Gradient(stops: gradientStops),
center: .center
),
lineWidth: width
)
.frame(
width: WKInterfaceDevice.current().screenBounds.width,
height: WKInterfaceDevice.current().screenBounds.height
)
.padding(.top, -1 * CGFloat(deviceProperties.screenOffset))
}
}
// MARK: Color extension that converts HEX values into RGB for SwiftUI
extension Color {
init(hex: String) {
let scanner = Scanner(string: hex)
_ = scanner.scanString("#")
var hexNumber: UInt64 = 0
scanner.scanHexInt64(&hexNumber)
let r = Double((hexNumber & 0xff0000) >> 16) / 255
let g = Double((hexNumber & 0x00ff00) >> 8) / 255
let b = Double(hexNumber & 0x0000ff) / 255
self.init(red: r, green: g, blue: b)
}
}
// MARK: Screen Dimension and Offset Constants
struct DeviceConfig {
static let width = WKInterfaceDevice.current().screenBounds.width
static let height = WKInterfaceDevice.current().screenBounds.height
// MARK: Combined cornerRoundness and screenOffset
static let deviceProperties: (cornerRoundness: Int, screenOffset: Int) = {
print("Device Width: \(Int(width)), Height: \(Int(height))")
switch (Int(width), Int(height)) {
case (205, 251): // Apple Watch Ultra 1, 2 (49mm)
return (55, 17)
case (208, 248): // Apple Watch Series 10 (46mm)
return (50, 17)
case (187, 223): // Apple Watch Series 10 (42mm)
return (45, 17)
case (198,242): // Apple Watch Series 9, 8, 7 (45mm)
return (42, 24)
case (176,215): // Apple Watch Series 9, 8, 7 (41mm)
return (40, 20)
case (184, 224): // Apple Watch Series 6 (44mm) + SE (44mm)
return (35, 25)
case (162, 197): // Apple Watch Series 6 (40mm) + SE (40mm)
return (28, 20)
default: // Fallback for unknown screen sizes
return (50, 17)
}
}()
}
// Preview
#Preview {
GlowEffect(freeze: false) // Toggle `freeze` to test behavior
}