# Overrun An iOS app for trimming and managing HealthKit workouts. Built for the common problem of forgetting to stop recording — leaving you with an 8-hour "run" that wrecks your stats.

Workout list grouped by month      Detail view showing a forgot-to-stop workout

## Features ### Workout List - Animated gradient header with icon colors (cyan, lime green, hot pink) - Workouts grouped by month/year with section headers - **Search** by activity type name (case-insensitive) - **Sort** by date (default), longest duration, or shortest duration — useful for quickly finding forgot-to-stop workouts or accidental recordings - Paginated loading (50 at a time) with infinite scroll - Pull-to-refresh and automatic refresh via HealthKit observer (updates when workouts are added or deleted externally) ### Guided Trim Flow The workout detail view walks you through a step-by-step process: 1. **Trim and save** — Activity graph showing heart rate, active energy, or distance over time. Range slider to select the portion to keep, with live-updating start/end times, duration, and activity type picker. Explainer text describes what data is preserved and what is lost. 2. **Upload to Strava** (optional) — Upload the trimmed workout directly to Strava via OAuth. Shown after saving, with connect/upload/status inline. 3. **Remove the original** — Instructions to delete the original in Apple Fitness (swipe left → "Delete Workout & Data"), with an "Open Fitness" button. If the original was created by Overrun, it is automatically deleted. Steps 2 and 3 are visible but dimmed before step 1 is complete, so you know the full process before you begin. ### Data-Preserving Trim When you trim a workout, Overrun creates a new workout and migrates all associated data within the trimmed time range: - **Heart rate, active/basal energy, distance, step count** samples - **Running dynamics** — speed, power, stride length, vertical oscillation, ground contact time - **VO2 max** and **physical effort** samples - **Workout effort scores** (iOS 18+, user-entered only) - **Workout routes** (GPS/location data) - **Workout events** (laps, segments, etc.) - **Metadata** (indoor/outdoor flag, weather, timezone, METs, etc.) - **Configuration** — activity type, indoor/outdoor location type, swimming config ### Strava Integration - OAuth authentication via the Strava app (falls back to Safari if not installed) - Direct upload of workouts as TCX files with heart rate and GPS data - Upload status tracking with polling (uploading → processing → success) - Connect/disconnect from anywhere in the trim flow ## Known Limitations ### HealthKit / Apple Platform - **Cannot modify workouts in place.** HealthKit provides no API to change a workout's start/end dates, samples, or metadata. Trimming must create a new workout and delete the original. - **Cannot delete workouts from other apps.** HealthKit only allows an app to delete objects it created. Workouts from Apple Watch, Fitness+, or other apps must be deleted manually by the user (e.g., swipe left in Apple Fitness and choose "Delete Workout & Data"). - **Estimated workout effort is not copyable.** `estimatedWorkoutEffortScore` is computed by Apple's algorithms and cannot be written by third-party apps. It may or may not be recomputed by the system for the new workout. User-entered effort scores (`workoutEffortScore`, iOS 18+) are migrated via `relateWorkoutEffortSample`. - **Physical effort samples are system-generated.** `physicalEffort` samples are computed by the OS and cannot be created or associated by third-party apps. - **Activity icons in Apple Fitness are source-dependent.** Even though we correctly set `locationType` (e.g., `.indoor`) and carry over `HKMetadataKeyIndoorWorkout`, Apple Fitness may display a generic icon for workouts from third-party sources instead of the specialized icon (e.g., indoor run icon) shown for Apple Watch workouts. - **Apple Fitness may crash when sharing copied workouts.** This is a known Apple bug where Fitness crashes when trying to view interval details or share workouts created by third-party apps via `HKWorkoutBuilder`. This is not specific to Overrun. - **No deep link to specific workouts.** Apple provides no URL scheme to open a specific workout in Fitness or Health. `activitytoday://` opens Fitness to the activity rings view only. - **Splits are not shown for third-party workouts.** Since iOS 14, Apple Fitness only displays per-kilometer/mile splits for workouts created by Apple's native Workout app. The underlying distance samples exist in HealthKit, but Fitness will not render the splits table for workouts from any third-party source. There is no API or workaround. - **Running dynamics may not be present.** Running speed, power, stride length, vertical oscillation, and ground contact time are only recorded by Apple Watch Series 6+ / Ultra with watchOS 9+. Older devices or non-running workouts will not have these samples. ### Strava - **Strava only imports workouts from Apple's native Workout app.** Strava checks the `sourceRevision` bundle identifier on each HealthKit workout and only accepts workouts from Apple's Workout app and Apple Fitness+. Workouts written by any third-party app (including Overrun) are intentionally excluded from Strava's HealthKit import list, regardless of how complete the data is. - **This is a Strava policy, not a data issue.** The workout data we write is fully valid and appears correctly in Apple Health and Apple Fitness. - **Direct upload works.** Overrun bypasses the HealthKit import limitation by uploading directly to Strava's API via OAuth + TCX file upload. ## Requirements - iOS 17+ - Xcode 15+ - HealthKit entitlement ## Building Open `WorkoutEditor.xcodeproj` in Xcode and run on a device or simulator. The app requires HealthKit authorization to read and write workouts and associated samples. ### Strava Setup 1. Register an API application at [strava.com/settings/api](https://www.strava.com/settings/api) 2. Set the Authorization Callback Domain to `localhost` 3. Copy `Secrets.xcconfig.template` to `Secrets.xcconfig` and fill in your Client ID and Client Secret 4. `Secrets.xcconfig` is gitignored and will not be committed In debug builds, 200 sample workouts are auto-generated on first launch for testing. ## Localization The app is set up for internationalization using Xcode String Catalogs (`.xcstrings`). All user-facing strings in SwiftUI views are automatically extracted by Xcode. ### Contributing a Translation 1. Open the project in Xcode 2. Go to **Project Settings → Info → Localizations** and add your language 3. Xcode will create localized entries in `Localizable.xcstrings` and `InfoPlist.xcstrings` 4. Open `Localizable.xcstrings` in Xcode's String Catalog editor and translate each string 5. `InfoPlist.xcstrings` contains the app name and HealthKit usage descriptions — translate those too 6. Activity type names (Running, Cycling, etc.) and all step/button labels are included in the catalog ### Files - `WorkoutEditor/Localizable.xcstrings` — all app UI strings - `WorkoutEditor/InfoPlist.xcstrings` — Info.plist strings (app name, permission descriptions)