import SwiftUI
import AVFoundation
class TimerSoundPlayer: NSObject, AVAudioPlayerDelegate {
var audioPlayer: AVAudioPlayer?
func playSound() {
guard let url = Bundle.main.url(forResource: "thunderstruck", withExtension: "mp3") else {
return
}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: .mixWithOthers) // Set the audio session category for playback and mix with other audio
try AVAudioSession.sharedInstance().setActive(true) // Activate the audio session
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.delegate = self
audioPlayer?.prepareToPlay()
audioPlayer?.numberOfLoops = -1 // Infinite loop until stopped
audioPlayer?.play()
} catch {
print("Error playing sound: \(error.localizedDescription)")
}
}
func stopSound() {
audioPlayer?.stop()
audioPlayer = nil
do {
try AVAudioSession.sharedInstance().setActive(false) // Deactivate the audio session
} catch {
print("Error deactivating audio session: \(error.localizedDescription)")
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
stopSound()
}
}
struct ContentView: View {
@State private var timeRemaining = 1800 // 30 minutes in seconds
@State private var timerActive = false
@State private var sliderValue = 1800.0 // Initial value of 30 minutes in seconds
@State private var showAlert = false
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
private let soundPlayer = TimerSoundPlayer()
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [Color.blue, Color.purple, Color.pink]), startPoint: .topLeading, endPoint: .bottomTrailing)
.edgesIgnoringSafeArea(.all)
VStack {
Text(timeString(time: timeRemaining))
.font(.system(size: 60))
.padding()
.background(
LinearGradient(gradient: Gradient(colors: [Color.pink, Color.yellow]), startPoint: .topLeading, endPoint: .bottomTrailing)
.cornerRadius(10)
.padding(.horizontal)
)
HStack {
Button(action: {
timerActive.toggle()
}) {
Text(timerActive ? "Pause" : "Play")
.font(.title)
.padding()
.foregroundColor(.white)
.background(timerActive ? Color.red : Color.green)
.cornerRadius(10)
}
Button(action: {
timeRemaining = 1800 // Reset the timer value to 30 minutes
timerActive = false // Pause the timer
sliderValue = 1800.0 // Reset the slider value to the initial value
}) {
Text("Reset")
.font(.title)
.padding()
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(10)
}
}
Slider(value: Binding(
get: { self.sliderValue },
set: { newValue in
self.sliderValue = newValue
if !timerActive { // Update the time only when the timer is paused
timeRemaining = Int(newValue)
}
}
), in: 0...1800, step: 1) // Set the slider range to 0 minutes to 30 minutes
.padding(.horizontal)
.background(
LinearGradient(gradient: Gradient(colors: [Color.yellow, Color.orange]), startPoint: .leading, endPoint: .trailing)
.cornerRadius(10)
.padding(.horizontal)
)
}
.foregroundColor(.white) // Set the foreground color to white for better visibility
}
.onReceive(timer) { _ in
if timerActive && timeRemaining > 0 {
timeRemaining -= 1
}
if timeRemaining == 0 {
showAlert = true
timerActive = false
soundPlayer.playSound()
}
}
.alert(isPresented: $showAlert) {
Alert(
title: Text("Timer Expired"),
message: Text("Chat smarter, not harder."),
dismissButton: .default(Text("OK")) {
showAlert = false // Dismiss the alert by setting showAlert to false
sliderValue = 1800.0 // Reset the slider value to the initial value
timeRemaining = 1800 // Reset the timer value to 30 minutes
soundPlayer.stopSound()
}
)
}
}
func timeString(time: Int) -> String {
let minutes = time / 60
let seconds = time % 60
return String(format: "%02d:%02d", minutes, seconds)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}