Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StressPunch

StressPunch is a small SwiftUI app designed as a lighthearted way to create and manage custom stress targets, choose favorites, and interact with them through a simple punch animation and sound effect.

The project is presented as a portfolio sample demonstrating modern iOS development with SwiftUI, SwiftData, PhotosUI, Apple’s Observation framework, AVFAudio, and automated testing with Swift Testing.

Features

  • Create custom stress targets
  • Select images from the user's photo library
  • Edit existing targets
  • Delete targets
  • Mark up to four targets as favorites
  • Restore built-in default targets
  • Persist target data with SwiftData
  • Remember the currently selected target
  • Display a punch graphic at the user's tap location
  • Animate the selected target when tapped
  • Play an accompanying sound effect
  • Manage targets through a dedicated library interface

Screenshots

Technologies

  • Swift
  • SwiftUI
  • SwiftData
  • Swift Testing
  • PhotosUI
  • Observation
  • AVFAudio
  • Xcode
  • Git

Architecture

StressPunch uses a lightweight MVVM-style structure appropriate for the size of the project.

Model

StressTarget is a SwiftData model representing an individual stress target.

Each target stores:

  • Name
  • Message
  • Selection state
  • Favorite state
  • A built-in image name or user-selected image data

SwiftData provides persistence for both built-in and user-created targets.

Views

The primary views are:

  • StressPunchView — main interaction screen
  • MoreStressTargetsView — browse and select targets
  • ManageTargetLibraryView — manage favorites, editing, deletion, and default restoration
  • AddEditTargetView — create and edit custom targets

View Model

StressPunchViewModel coordinates interaction-specific behavior including:

  • Audio playback
  • Temporary punch-overlay presentation
  • Punch animation behavior

SwiftUI and SwiftData manage most application state directly where appropriate, keeping the architecture intentionally lightweight rather than introducing abstractions that are unnecessary for the size of the project.

Business Logic

Small business rules are kept separate from presentation code where appropriate so they can be tested independently.

For example, favorite-selection logic is handled by a pure function that determines whether another target can be favorited based on the current favorite count and the target’s current state.

Persistence

StressPunch uses SwiftData to persist target information.

User-selected images are stored as Data using external storage:

@Attribute(.externalStorage) var imageData: Data?

Built-in targets reference images stored in the asset catalog instead of duplicating image data in the persistent store.

When the app launches without stored targets, the default target collection is inserted into the SwiftData model context.

Photo Selection

Users can create a custom stress target by selecting an image through PhotosPicker.

The selected image is loaded asynchronously and stored with its corresponding StressTarget.

Favorite Targets

Users may choose up to four favorite targets.

Favorites are displayed directly on the main screen for quick access, while the complete collection remains available in the target library.

The favorite-limit rule is separated from the SwiftUI presentation layer and covered by unit tests, including boundary conditions for adding and removing favorites.

Testing

StressPunch includes automated tests using Swift Testing.

Unit Tests

Unit tests verify the favorite-selection business rule independently from SwiftUI and SwiftData.

The tests cover:

  • Favoriting when no favorites exist
  • Favoriting when below the four-target limit
  • Preventing an additional favorite when four favorites already exist
  • Keeping an existing favorite enabled so it can still be unfavorited

SwiftData Integration Tests

Integration tests use an in-memory SwiftData container to verify persistence behavior without modifying production data.

The tests cover:

  • Creating and saving a StressTarget
  • Fetching a saved target
  • Updating and persisting target values
  • Deleting a target from the persistent store

Using an in-memory container keeps each persistence test isolated and repeatable.

What This Project Demonstrates

StressPunch demonstrates:

  • Building an iOS interface with SwiftUI
  • Persistent models with SwiftData
  • State ownership and bindings
  • SwiftUI navigation and sheet presentation
  • CRUD-style data management
  • Photo selection with PhotosUI
  • Asynchronous image loading
  • Rendering user-provided images
  • Audio playback with AVAudioPlayer
  • Custom tap interactions and animation
  • Optional handling without unnecessary force unwrapping
  • Maintaining a single source of truth for persistent data
  • Separating testable business logic from presentation behavior
  • Unit testing with Swift Testing
  • SwiftData integration testing with an in-memory model container
  • Refactoring and modernizing an existing codebase

Project Background

StressPunch originated as an earlier iOS learning project and was later redesigned and refactored as a public portfolio sample.

The refactor focused on:

  • Renaming and rebranding the original project
  • Removing unnecessary force unwraps
  • Improving optional handling
  • Simplifying state ownership
  • Using SwiftData queries as the primary source of truth
  • Removing duplicated application state
  • Improving persistence error handling
  • Cleaning up naming and project structure
  • Separating persistent data from UI-specific behavior
  • Extracting business logic where independent testing adds value
  • Adding automated unit and persistence integration tests
  • Preparing the codebase for public review

This project represents the process of revisiting earlier code, identifying weaknesses, and improving it using knowledge gained through subsequent iOS development experience.

Requirements

  • Xcode 16 or later
  • iOS 17 or later
  • Swift 5.9 or later

Running the Project

  1. Clone the repository:
git clone https://github.com/Brett-Buchholz/StressPunch.git
  1. Open StressPunch.xcodeproj in Xcode.

  2. Select an iPhone simulator or connected iOS device.

  3. Build and run the project.

No external packages, accounts, or API keys are required.

Running the Tests

Run the full automated test suite in Xcode with:

Command-U

or choose:

Product → Test

The test suite includes both pure unit tests and SwiftData integration tests.

Future Improvements

Potential future improvements include:

  • Additional accessibility improvements
  • User-facing persistence error handling
  • Additional animation and interaction feedback
  • Expanded automated test coverage as new features are added

Author

Brett Buchholz

iOS Developer focused on Swift, SwiftUI, and UIKit.

About

SwiftUI portfolio app using SwiftData, PhotosUI, Observation, and AVFAudio to create and manage custom stress targets with persistence, favorites, animations, and sound.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages