BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2 或任何藍牙控制器,搭配 MyWhoosh、Rouvy、Zwift 等。iOS、Android、Windows、macOS 均可免費試用。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Native iOS and watchOS strength tracker in SwiftUI, SwiftData and HealthKit, with widgets, Live Activities and Siri shortcuts. Fully offline, no account, zero third-party dependencies.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
A native iOS workout tracker. Build a routine, log every set as you lift, and
watch the numbers move.
Everything lives on the device — no account, no server, no network. It works in
a basement gym with no signal, and your training history is yours.查看完整 README ↗A native iOS workout tracker. Build a routine, log every set as you lift, and watch the numbers move.
Everything lives on the device — no account, no server, no network apart from the YouTube form videos it streams when you open an exercise. It works in a basement gym with no signal, and your training history is yours.
GymTrack.xcodeproj in Xcode.com.yourname.gymtrack. A free Apple ID can't reuse an identifier someone
else has registered.With a free Apple ID the app stays installed for 7 days before it needs re-running from Xcode. A paid Apple Developer account raises that to a year.
The Home Screen widgets read their numbers out of an App Group —
group.com.marwanmohamed.gymtrack, declared in the Release entitlements for the
app and widgets. If you changed the bundle identifier in step 4, change the
group to match in GymTrack.entitlements, GymTrackWidgets.entitlements, and
SharedStore.appGroup, all three together. App Groups need a paid Apple
Developer account, so the default Debug configuration leaves that entitlement
out and can be installed with a free Apple ID. In that build, the widgets say
"Open GymTrack to fill this in" rather than pretending you have no routine.
Nothing else is affected — the app, the watch and the Live Activity never go
through the group, and starting a workout from a widget is an ordinary
gymtrack:// link.
Minimum deployment target is iOS 17. The Live Activity appears on the Lock Screen on any supported iPhone; the Dynamic Island presentation needs a device that has one.
The watch app is embedded in the iPhone app, so it goes wherever the phone app goes — install GymTrack on your iPhone and the watch app appears in the Watch app on your phone under Available Apps.
Two things worth knowing:
.watchkitapp on the end. If you changed the iPhone one in step 4 above,
change the watch target's to match and update WKCompanionAppBundleIdentifier
in GymTrackWatch/Info.plist to your new iPhone identifier.Minimum watchOS is 10. Heart rate and calories need HealthKit permission, which the watch asks for the first time a session starts.
Today — the session scheduled for today, its exercises and rep targets, and a one-tap start. Plus the week at a glance, current streak, and recent sessions.
Logging — the next set you have to do is always expanded with big steppers; everything else collapses out of the way. Tap a number to type it instead of stepping. The weight you use carries to the remaining sets automatically, and last session's numbers sit next to each set so you know what to beat. A rest timer starts on its own when you log a set, keeps time correctly if you lock the phone, and notifies you when it's up.
Effort — while you rest, the timer bar asks how the set felt: Easy, Solid, Hard or All out, each with what it means in reps written underneath it. It's asked there because a rest is the one moment in a workout when you're standing still with the phone in your hand, and it never blocks the timer or the next set. A set you didn't answer for keeps a Rate chip rather than losing the question, so you can come back to it whenever. See Progressive overload for what the answer does next session — and the bullet below for what it does immediately. Turn the question off in Settings → Effort and everything behaves exactly as it did before.
What the answer does now — say a set felt easy after clearing the top of its rep range and the card offers the next rung on that machine for the sets you have left: "62.5 kg → 65 kg · 3 sets to go", one tap to take it. Say all out after falling short and it offers to hold the load instead. Nothing moves on its own, and anything you do take moves back: taking the offer leaves an Undo that restores every weight it changed and stands the offer back up, and an answer itself is cleared with one obvious button wherever you gave it. A mis-tap mid-workout should cost nothing, so none of it is one-way.
Beating last time — every logged set shows what it did against the same set last session the moment you log it: ▲ 5 kg, or ▲ 2 reps when the load is unchanged.
Machine weights — gyms aren't uniform, so the app doesn't pretend they are. Every exercise knows what its equipment is marked in and what one step is worth: a barbell moves 2.5 kg, a dumbbell 2, a pin-selected stack 5, and in a pound gym those become 5, 5 and 10. When a machine disagrees — the leg press is stamped in pounds, or its stack jumps in fifteens — tap the unit under the weight while you're logging it, pick kg or lb and the step, and that one exercise is put right for good. Steppers, the Digital Crown and the app's own progression suggestions then only ever offer weights that machine can actually be set to. Everything is still stored in kilograms and converted, so records, volume and Health stay comparable whatever each machine says; Settings → Machine weights lists anything you've corrected and the defaults behind everything else.
Putting a session down — pull the logger down by its handle, or tap Minimise, and it shrinks into a bar above the tab bar that keeps the clock, the set count and the rest countdown in view. Tap it to go back. The session survives leaving the app, switching tabs and force-quitting; discarding it is a separate, deliberate button at the bottom of the logger, never the price of getting out of the screen.
Live Activity — while a session is open it's on the Lock Screen and in the Dynamic Island: which exercise and set is up, the weight and rep target, the rest countdown ticking down on its own, sets logged and volume moved. When the rest runs out the card says so without the app having to wake up. Tapping it lands straight back on the set you were about to do.
Home Screen and Siri — a Today widget carrying the session you're due to do and a button that starts it, or, once you're training, the exercise you're on, the sets logged and the rest counting down. A Streak widget for the Home Screen and the Lock Screen, in circular, rectangular and inline shapes. And "Hey Siri, start my GymTrack workout" — which also puts GymTrack on the Action Button, in Spotlight and in Shortcuts, with no setup. Every one of those routes lands in the logger on the first set, not on the Today tab.
Apple Watch — the session, on your wrist. Swipe between three screens: controls, the set you're on, and what your body is doing. The weight and reps sit on the Digital Crown — tap a number to attach the crown to it — with a − / + pair under them for when the crown isn't to hand, and one button logs the set. The exercise list is a tap away, so a machine that's taken doesn't stop the session: pick another and both devices move with you. Rest counts down on the wrist and taps you when it's over, which is the one thing a phone in a locker can't do. Start a workout on either device and it appears on the other; finish it on either and it's finished on both. The watch keeps no database of its own — everything it does is applied on the phone and mirrored straight back, so the two can't drift — and a set logged out of range is queued and lands when the watch is back near the phone.
Heart rate and calories — starting a session starts a real workout session on the watch, so the heart rate sensor comes up to workout sampling, the app keeps running between sets with your wrist down, and the rings move. The live heart rate shows in the phone's logger too, and the session's average, peak and active energy are kept with it.
Apple Health — a finished session is written as a traditional strength training workout with one activity per exercise, carrying its sets, reps and volume, so GymTrack sessions sit in Fitness alongside everything else. Heart rate and active energy are read back for each session — from any Apple Watch worn during it, not just ours. Body weight syncs both ways: a weigh-in typed into GymTrack lands in Health, and one from a connected scale is pulled in. Each of the three is a separate switch in Settings → Health & Watch, and deleting a session in GymTrack removes its workout from Health too.
Progressive overload — double progression, built in. Clear the top of the rep range on every set and the app tells you to add weight and reset to the bottom of the range. Fall short and it tells you to hold the load or back off. The weight it names is always the next rung on that machine, never a number between two pins.
How the sets felt sharpens all of that, because reps alone can't tell a set you finished with three in the tank from one that nearly buried you. Each of the four answers changes something. Clear the range and call it easy and it moves you two rungs instead of one, which is what stops a plain double progression crawling back up through weights you already owned. Clear it hard and it still adds weight, but says to expect a fight for the bottom of the range; clear it all out and it warns you'll sit there a few sessions. Fall short at easy or solid and it stops suggesting a deload — the load isn't what stopped you, so taking weight off would be fixing the wrong thing. Answer nothing and every suggestion is identical to what it was.
Personal records — recognised on estimated 1RM, so heavier-for-fewer and lighter-for-more both count. Celebrated the moment you log the set.
Plan — multiple routines, one active. Four starter templates (Push/Pull/Legs, Upper/Lower, Full Body 3×, Minimalist Strength) or build one from scratch. Every day, exercise, set count, rep range and rest interval is editable.
Library — 410 exercises, filterable by muscle and equipment, and searched the way people actually type: word by word rather than as one literal string, with gym shorthand folded in. "lat pull down" finds the Lat Pulldowns, "incline db press" finds the Incline Dumbbell Press, "rdl" finds the Romanian Deadlifts. Each one shows its full history: a progression chart (est. 1RM, top set or volume), your bests, and every session you've done it in.
Build your own for whatever the bundled library hasn't got — straight from the search box, including mid-workout, where it drops into the session as soon as you save it. Custom exercises can be edited and deleted afterwards. Anything redundant can be swiped away and restored later from Library ▸ Hidden; hiding only governs search and browsing, so a hidden exercise already in a plan or your history keeps its name and its numbers.
Progress — streaks, volume per day, a body heatmap showing which muscles are on target for the week and which are falling behind, a 16-week consistency grid, body weight over the last twelve weeks, and your PR board.
Backups — export everything as a single JSON file, restore it on any device. The app's folder is visible in Files (On My iPhone → GymTrack), so a backup can be dropped in and restored without leaving the phone.
Changes can start from a phone. Open an issue that mentions @claude, and a Claude Code run in
GitHub Actions implements it and opens a pull request. Every pull request is built and tested on a
macOS runner (build-and-test, which gates merging) and gets an advisory Claude review that says
what to try on the device. Merging is Squash and merge.
docs/claude-pipeline.md explains how the pipeline works, how to
use it from a phone, troubleshooting, and how to port it to another repo.docs/claude-pipeline-setup-prompt.md is the prompt that
sets the same pipeline up in any repo.docs/DEVELOPMENT.md covers building, running the tests and installing
on the phone from a Mac.GymTrack/ The iPhone app
├── App/ App entry point, tab shell, session presentation
├── Models/ SwiftData entities, exercise catalog, muscle taxonomy
├── Services/ Stats, overload, rest timer, backup, templates,
│ Live Activity, HealthKit, the watch link
├── DesignSystem/ Shared components, haptics
├── Features/ One folder per screen area
└── Resources/ exercises.json — the bundled exercise library
GymTrackWatch/ The watch app — mirror of the session, wrist logging,
and the HKWorkoutSession that records heart rate
GymTrackShared/ Compiled into every target: theme tokens, weight units,
the Live Activity's attributes, and the phone/watch
payloads
GymTrackWidgets/ Widget extension — the Lock Screen and Dynamic Island
presentations of a running session, plus the Today and
Streak widgets for the Home and Lock Screens
Built with SwiftUI, SwiftData and Swift Charts. No third-party dependencies.
Text(timerInterval:) is the only clock a Live Activity keeps running on its
own, so the rest countdown uses it; how finely it ticks is the system's call.
Everything else on the card — including the session length — is a label the
app restamps on every change, which is also why it never shows blank digits.gymtrack://start-today link, which needs nothing shared
with the widget's process; Siri, the Action Button and a Shortcut go through
an App Intent that leaves a note for the app to read as it comes to the front,
and notes older than two minutes are dropped rather than replayed.GymTrackApp rather than left to
SwiftData's default, because that default is NSPersistentContainer's — which
moves to the App Group container the moment an app has the app-groups
entitlement. Adding that entitlement for the widgets would otherwise have
pointed the app at a new empty store and left every existing session unread in
the old location, which on an installed copy looks exactly like losing your
training history.SampleData.swift fills the app with a couple of months of plausible history
for design work. It's #if DEBUG only; launch with -GTSeedSampleData.This replaces an earlier Next.js/Firebase web version of GymTrack. That code is still in the git history if you want it — the bundled exercise library came from it.