Skip to content

Repository files navigation

SplitTimer

A native iOS split timer app built with SwiftUI — originally designed for timing golf cart laps, now general purpose for karting, running, or any activity where you want to track split times across multiple checkpoints.

Features

  • Tracks & splits — create named tracks with custom split checkpoints (e.g. "T-intersection", "Back straight", "Lap 1")
  • Live split timing — tap to split, times update at screen refresh rate via CADisplayLink
  • Split colors — purple for overall best, green for personal best, yellow for slower
  • Multi-runner support — name each run; personal bests are tracked per name
  • History — all runs persisted to Firebase Firestore, synced across devices
  • Haptic feedback — medium impact on each split, strong pulse on finish
  • Screen always-on — idle timer disabled during active runs
  • Background safe — timer stays accurate if app is backgrounded mid-run

Tech Stack

  • SwiftUI — declarative UI, @Observable / @ObservedObject state management
  • Firebase Firestore — NoSQL cloud database for cross-device persistence
  • CADisplayLink — frame-rate display updates (~120fps on ProMotion) for smooth timer rendering
  • UserDefaults — lightweight local persistence for runner name preference
  • UIImpactFeedbackGenerator for haptics
  • NotificationCenter for app lifecycle events

Architecture

ContentView (phase-based navigation)
├── HistoryView          — default screen, shows all runs across tracks
├── TrackPickerView      — select or create a track before running
└── RunView              — active timer, split list, finish sheet

Three view models handle all business logic:

  • TimerViewModel — owns the CADisplayLink, split recording, and Firestore write
  • TrackViewModel — track + split definition CRUD, Firestore read/write
  • HistoryViewModel — loads all runs with splits, computes best times per split definition

Data model:

Track
  └── [SplitDefinition]   id, name, order

Run
  └── [Split]             split_at timestamp, split_def_id FK

Tracks own their split definitions as an embedded array in Firestore. Runs and splits are separate top-level collections, with splits fetched and joined client-side after loading runs.

Data Flow

TrackPickerView → select track
    → TimerViewModel(track) initialized with track's SplitDefinitions
    → user taps Start → CADisplayLink begins, startTime = Date()
    → each Split tap → Split(Date(), run.id, splitDef.id) appended
    → finish → timestamps recorded, Firestore write, history reloads

Setup

  1. Clone the repo
  2. Create a Firebase project at console.firebase.google.com
  3. Add an iOS app, download GoogleService-Info.plist, add to Xcode target
  4. Enable Firestore in Firebase console (test mode is fine to start)
  5. Add Firebase SDK via SPM: https://github.com/firebase/firebase-ios-sdk
  6. Build & run

Firestore Collections

Collection Key fields
tracks name, created_at, splits[] (embedded)
runs track_id, user_name, started_at, ended_at
splits run_id, split_def_id, split_at

Potential Next Steps

  • Auth (Firebase Auth) to replace name-based personal bests with real user accounts
  • Firestore security rules scoped per user
  • Live leaderboard view per track
  • Apple Watch companion for wrist-tap splits
  • Export run data to CSV

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages