Here's the code if it helps.
`import SwiftUI
import MessageUI
import AVFoundation
import UserNotifications
struct TimerView: View {
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State var isTimerActive = false
@State var isCountingActive = false
@State var seconds = 10
@State var minutes = 0
@State var defaultSeconds = 10
@State var defaultMinutes = 0
@State var defaultTimeChange: Bool = false
@State var originalSeconds = 10
@State var currentSeconds = 10
@State var ring = 1.0
@State var toTake = 0.1
@State var gradientOn: Bool = false
@State var secretAlert: Bool = false
@State var changeBGColour: Bool = false
@State var BGColourPopover: Bool = false
@State var randomColor: Color = .red
@State var audioPlayer: AVAudioPlayer?
@State var selectedSound = "Default"
let sounds = ["Default", "Default 2", "Timer Notify"]
let mailComposeDelegate = MailDelegate()
@AppStorage("active_icon") var activeAppIcon: String = "AppIcon"
@Environment(\.colorScheme) var colourScheme
@State var selectedLightColourSet = "Light Default"
@State var selectedDarkColourSet = "Dark Default"
let colourSets = [
"Light Default", "Pastel", "Cool", "Classic", "Black",
"Dark Default", "Neon", "Night Owl", "Sunset", "White"
]
let lightColourSet: [String: Color] = [
"play": .mint,
"pause": Color(#colorLiteral(red: 0.5254901051521301, green: 0.30980387330055237, blue: 0.9960787892341614, alpha: 1.0)),
"cancel": .red,
"stroke": .blue
]
let pastelColourSet: [String: Color] = [
"play": Color(#colorLiteral(red: 0.7784313559532166, green: 0.6843138337135315, blue: 0.8313726782798767, alpha: 1.0)),
"pause": Color(#colorLiteral(red: 0.9686276316642761, green: 0.758823573589325, blue: 0.8392156958580017, alpha: 1.0)),
"cancel": Color(#colorLiteral(red: 0.48627424240112305, green: 0.5882355570793152, blue: 0.7823531627655029, alpha: 1.0)),
"stroke": Color(#colorLiteral(red: 0.699999988079071, green: 0.8509804010391235, blue: 0.7980391979217529, alpha: 1.0))
]
let coolColourSet: [String: Color] = [
"play": Color(#colorLiteral(red: 0.250980406999588, green: 0.32156866788864136, blue: 0.5098039507865906, alpha: 1.0)),
"pause": Color(#colorLiteral(red: 0.16862738132476807, green: 0.21568626165390015, blue: 0.2941175699234009, alpha: 1.0)),
"cancel": Color(#colorLiteral(red: 0.8156865239143372, green: 0.1921570897102356, blue: 0.38039207458496094, alpha: 1.0)),
"stroke": Color(#colorLiteral(red: 0.09019533544778824, green: 0.5411766171455383, blue: 0.5803923010826111, alpha: 1.0))
]
let classicColourSet: [String: Color] = [
"play": .green,
"pause": .orange,
"cancel": .black,
"stroke": .orange
]
let blackColourSet: [String: Color] = [
"play": .black,
"pause": .black,
"cancel": .black,
"stroke": .black
]
let darkColourSet: [String: Color] = [
"play": Color(#colorLiteral(red: 0.003918447997421026, green: 0.7803922891616821, blue: 0.9882356524467468, alpha: 1.0)),
"pause": .white,
"cancel": .red,
"stroke": .pink
]
let neonColourSet: [String: Color] = [
"play": Color(#colorLiteral(red: 0.10887768119573593, green: 1.0000001192092896, blue: 0.10887082666158676, alpha: 1.0)),
"pause": Color(#colorLiteral(red: 0.3204635977745056, green: 0.9998816847801208, blue: 1.000000238418579, alpha: 1.0)),
"cancel": Color(#colorLiteral(red: 0.9910205006599426, green: 1.0000001192092896, blue: 0.04019148647785187, alpha: 1.0)),
"stroke": Color(#colorLiteral(red: 1.0000003576278687, green: 0.12729215621948242, blue: 0.9811344742774963, alpha: 1.0))
]
let nightowlColourSet: [String: Color] = [
"play": Color(#colorLiteral(red: 0.4432700574398041, green: 0.057988740503787994, blue: 1.0000001192092896, alpha: 1.0)),
"pause": Color(#colorLiteral(red: 0.3215680718421936, green: 0.8392159342765808, blue: 0.9882352948188782, alpha: 1.0)),
"cancel": Color(#colorLiteral(red: 0.9052000641822815, green: 0.4251731038093567, blue: 0.11207173019647598, alpha: 0.6875)),
"stroke": Color(#colorLiteral(red: 0.9931392073631287, green: 1.000000238418579, blue: 0.26665163040161133, alpha: 1.0))
]
let sunsetColourSet: [String: Color] = [
"play": Color(#colorLiteral(red: 0.9353944659233093, green: 0.37844473123550415, blue: 1.000000238418579, alpha: 1.0)),
"pause": Color(#colorLiteral(red: 0.9960785508155823, green: 0.7058826088905334, blue: 0.24705874919891357, alpha: 1.0)),
"cancel": Color(#colorLiteral(red: 1.0000004768371582, green: 0.25098052620887756, blue: 0.08235275000333786, alpha: 1.0)),
"stroke": Color(#colorLiteral(red: 1.0000001192092896, green: 0.7725490927696228, blue: 0.6705884337425232, alpha: 1.0))
]
let whiteColourSet: [String: Color] = [
"play": .white,
"pause": .white,
"cancel": .white,
"stroke": .white
]
var body: some View {
NavigationView {
ZStack {
Spacer()
if changeBGColour {
randomColor.opacity(0.1).edgesIgnoringSafeArea(.all)
}
VStack(spacing: 25) {
ZStack {
Circle()
.stroke(
Color.gray.opacity(0.1),
style: StrokeStyle(
lineWidth: 35, lineCap: .round
)
)
Circle()
.trim(from: 0, to: isTimerActive ? ring: 1)
.stroke(
gradientOn ?
(
AngularGradient(gradient: Gradient(colors: [Color.red, Color.orange, Color.yellow, Color.green, Color.blue, Color.indigo, Color.purple]), center: .center)
) : (
AngularGradient(gradient: Gradient(colors: [colourSetButton(button: "stroke")]), center: .center)
),
style: StrokeStyle(
lineWidth: 35, lineCap: .round
)
)
.rotationEffect(.init(degrees: -90))
.onTapGesture(count: 5) {
gradientOn.toggle()
}
if !isTimerActive {
VStack {
Text("\(formatTime(time: Int(minutes))):\(formatTime(time: Int(seconds)))")
.foregroundColor(colourScheme == .light ? .black:.white)
.font(.system(size:34))
HStack {
Stepper(value: $seconds, in: 0...59) {
Text("Seconds")
}
.padding(.horizontal, 50)
}
HStack {
Stepper(value: $minutes, in: 0...59) {
Text("Minutes")
}
.padding(.horizontal, 50)
}
}
} else if isTimerActive {
Text("\(formatTime(time: Int(minutes))):\(formatTime(time: Int(seconds)))")
.foregroundColor(colourScheme == .light ? .black:.white)
.font(.system(size:34))
}
}
.frame(width: 280, height: 280)
.padding()
HStack(spacing: 25) {
Button(
action: {
if !isTimerActive && !isCountingActive {
withAnimation(.easeInOut) {
isTimerActive = true
isCountingActive = true
}
originalSeconds = (minutes * 60) + seconds
toTake = 1.0 / Double(originalSeconds)
} else if isTimerActive && isCountingActive {
if (seconds + (minutes * 60)) > 1 {
withAnimation(.easeInOut) {
isCountingActive = false
}
}
} else if isTimerActive && !isCountingActive {
withAnimation(.easeInOut) {
isCountingActive = true
}
}
}) {
Label(
isTimerActive ? (isCountingActive ? "Pause": "Resume") : "Start",
systemImage: isTimerActive ? (isCountingActive ? "pause.fill": "play.fill") : "play.fill"
)
.foregroundStyle(
gradientOn ? (
LinearGradient(
colors: [.red, .orange, .yellow, .green, .blue, .indigo, .purple],
startPoint: .leading,
endPoint: .trailing
)
) : (
LinearGradient(
colors: [
(
!isTimerActive && !isCountingActive && minutes == 0 && seconds == 0 ? .gray : (
isCountingActive ? (
colourSetButton(button: "pause")
) : (
colourSetButton(button: "play")
)
)
)
],
startPoint: .leading,
endPoint: .trailing
)
)
)
.padding(14)
.font(.title)
}
.disabled(!isTimerActive && !isCountingActive && minutes == 0 && seconds == 0 ? true:false)
.keyboardShortcut("p", modifiers: .command)
Button(
action: {
withAnimation(.easeInOut) {
isTimerActive = false
isCountingActive = false
ring = 1.0
}
seconds = defaultSeconds
minutes = defaultMinutes
}) {
Label("Cancel", systemImage: "backward.end.fill")
.foregroundStyle(
gradientOn ? (
LinearGradient(
colors: [.red, .orange, .yellow, .green, .blue, .indigo, .purple],
startPoint: .leading,
endPoint: .trailing
)
) : (
LinearGradient(
colors: [
(
isTimerActive ? colourSetButton(button: "cancel"): .gray
)
],
startPoint: .leading,
endPoint: .trailing
)
)
)
.padding(14)
.font(.title)
}
.disabled(isTimerActive ? false:true)
.keyboardShortcut("r", modifiers: .command)
}
}
Spacer()
}
.onAppear {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
} else if let error = error {
print(error.localizedDescription)
}
}
}