Shelf Life is a SwiftUI app for keeping track of household products and seeing what is about to expire. Products, photos, shelf entries, and expiration dates are stored locally with SwiftData.
- Create reusable products with a name, category, and optional photo.
- Choose photos from the library or capture them with the device camera.
- Add registered products to the shelf with a quantity and expiration date.
- Browse shelf items grouped by category and ordered by expiration date.
- Identify expiration urgency by color:
- Green: more than 14 days remaining.
- Yellow: 8–14 days remaining.
- Red: 7 days or fewer, including expired products.
- Receive a local notification three days before a product expires.
- Delete products and shelf entries with standard list gestures.
- Xcode 26.5 or later.
- iOS 26.5 or later.
- An iOS simulator or physical device.
A physical device is required to capture a photo with the camera. The photo library and all other app features can be used in the simulator.
- Clone the repository.
- Open
shelf-life.xcodeprojin Xcode. - Select the
shelf-lifescheme. - Choose an iOS simulator or connected device.
- Build and run with
Cmd + R.
You can also verify the project from the command line:
xcodebuild \
-project shelf-life.xcodeproj \
-scheme shelf-life \
-configuration Debug \
-sdk iphonesimulator \
CODE_SIGNING_ALLOWED=NO \
build- Tap Register and create a product such as milk, apples, or toothpaste.
- Optionally select a photo or take one with the camera.
- Tap Add and choose a registered product.
- Set its quantity and expiration date, then tap Add again.
- Review the product on the main shelf.
Deleting a shelf entry also cancels its pending expiration notification.
Shelf Life schedules local notifications with the UserNotifications
framework. No push-notification service or external server is required.
- Permission is requested when the app first attempts to schedule a reminder.
- Reminders are scheduled three days before expiration at 09:00 local time.
- A reminder is not scheduled when its calculated delivery date is already in the past.
- Notifications can appear while the app is open as well as when it is in the background.
- Only newly added shelf entries are scheduled; existing stored entries are not backfilled automatically.
Debug builds display a bell button in the top-right corner of the main screen.
Tap it, allow notifications if prompted, and wait five seconds for the test
notification. The button and test method are excluded from release builds with
#if DEBUG.
If no notification appears, check the app's notification permission in the device or simulator Settings app. Reinstalling the app resets its permission prompt in the simulator.
| Permission | When it is requested | Purpose |
|---|---|---|
| Camera | When Take Photo is selected | Capture a product photo |
| Photo library | When the photo picker requires access | Select an existing photo |
| Notifications | When a reminder is first scheduled | Warn about approaching expiration |
The project uses SwiftUI for the interface, SwiftData for local persistence, AVFoundation for camera capture, PhotosUI for image selection, and UserNotifications for expiration reminders.
shelf-life/
├── Assets.xcassets/
├── datamodel/
│ ├── Category.swift
│ ├── Product.swift
│ └── ShelfProduct.swift
├── managers/
│ └── ExpirationNotificationManager.swift
├── views/
│ ├── AddProductView.swift
│ ├── CameraView.swift
│ ├── ContentView.swift
│ ├── ListRegisteredProductView.swift
│ ├── ProductThumbnail.swift
│ └── RegisterProductView.swift
└── shelf_lifeApp.swift
Productis a reusable catalog entry containing a name, category, and optional image data.ShelfProductrepresents a product currently on the shelf, including its quantity, expiration date, and notification identifier.Categorydefines the supported product groups used by the registration and shelf screens.
Licensed under the terms in LICENSE.