User Notification in SwiftUI (A Simple Pomodoro Timer)

In this post, we will learn how to create a simple Pomodoro timer using user notifications. The goal is to start a 25-minute timer, and when it expires, we will see a notification on the home screen.

We follow these steps:

  • Define the user permission for local notifications.
  • Take a look at the user notification properties.
  • Implement the app.

Privacy and Permissions

First of all, we have to add the “Privacy – User Notifications Usage Description” to the Info.plist to define the reason for the user notification.

UserNotification

Second, how to declare a UserNotification:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
        if success {
            let content = UNMutableNotificationContent()
            content.title = "Pomodoro elapsed"
            content.subtitle = "Take a break"
            content.sound = UNNotificationSound.default
            
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Double(25 * 60), repeats: false)
            
            let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
            
            UNUserNotificationCenter.current().add(request)
        } else if let error {
            print(error.localizedDescription)
        }
    }

The first step is to request authorization. This will display a message asking for the user’s approval (only the first time, if the user accepts). If we get authorization, we create the content of the notification with a title, subtitle, and default sound. Next, we create a timer for the notification, create the request for the notification, and add it to the notification center. Note that we create a unique identifier for the notification using UUID().uuidString.

The pomodoro App

The last step is to add a timer to count the elapsed time (for the Pomodoro) and put everything together.

import SwiftUI
import UserNotifications

struct ContentView: View {
    @State var timer: Timer.TimerPublisher = Timer.publish(every: 1, on: .main, in: .common)
    let pomodoroLength = 25 * 60
    @State var counter = 0
    @State var timeString = "25:00"
    @State var hasPermission = false
    
    var body: some View {
        VStack(spacing: 10) {
            Button("Start pomodoro") {
                if hasPermission {
                    counter = 0
                    timeString = "25:00"
                    setTimer()
                    timer.connect()
                    
                    let content = UNMutableNotificationContent()
                    content.title = "Pomodoro elapsed"
                    content.subtitle = "Take a break"
                    content.sound = UNNotificationSound.default
                    
                    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Double(pomodoroLength), repeats: false)
                    
                    let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
                    
                    UNUserNotificationCenter.current().add(request)
                }
            }
            Text("\(timeString)").onReceive(timer, perform: { _ in
                counter += 1
                
                let remaining = pomodoroLength - counter
                let minutes = remaining / 60
                let secs = remaining % 60
                timeString = "\(minutes):\(secs)"
                if counter == pomodoroLength {
                    timer.connect().cancel()
                }
            })
        }.onAppear {
            UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
                if success {
                    hasPermission = true
                } else if let error {
                    print(error.localizedDescription)
                }
            }
        }
    }
    func setTimer() {
        self.timer = Timer.publish(every: 1, on: .main, in: .common)
    }
}

We need to import UserNotifications, then define a timer, the Pomodoro length in seconds, the initial string minutes:seconds value, and a counter to count the elapsed time. We also introduce a hasPermission variable that is set when the application starts, so we don’t need to check the authorization every time.

When we tap on “Start Pomodoro”, the notification is created with its timer, and the counter is initialized. Every second, we calculate the remaining time and display it until it equals zero, then the timer is stopped. If everything is set up correctly, we should see a notification.

For testing, I suggest setting the Pomodoro time to a few seconds, but at least enough to lock the screen or switch applications (otherwise you won’t see the notification).

The code https://github.com/niqt/PomodoroApp

Note: English is not my native language, so I apologize for any errors. I use AI solely to generate the banner of the post; the content is human-generated.

share this post with friends

Picture of Nicola De filippo

Nicola De filippo

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve

Leave a comment

Your email address will not be published. Required fields are marked *

Who I am

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve.

Follow Me Here

Get The Latest Updates

Periodically receive my super contents on coding and programming

join the family;)

Recent Posts