Skip to content

Releases: DuarteSantos8/openGym

v1.4.1

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 10 Oct 16:23

Bug fixes for v1.4.0, mostly the things you told us about on Discord and GitHub.

  • Smooth animations in the app. They lagged and stuttered on real phones (the phone's video
    player stalled at every loop). The app now shows them as animated images, the way the old GIFs
    worked, with the original timing. The web and self-hosted servers keep their clips.
  • The update check finds new versions again. It asked the GitLab mirror, which never got
    v1.4.0. It asks GitHub now, and the 300 MB download goes straight to storage instead of into
    memory, checked against its checksum before the installer opens.
  • The rest bell rings over music. With the app open, the end tone now plays like the
    screen-off alarm does: your music turns down for a moment instead of drowning it.
  • The Coach has its own button on the Plan page, no more hunting in the share menu.
  • Search: the exercises you have done come right after your favourites, and "leg press"
    finds the plain 45° leg press first.
  • Add exercise gets the Type row the library has (#521).
  • Exercise progress gets 1M / 3M / 1Y / All, like the body weight chart (#511).
  • Imports: two workouts on the same day stay two (#505).
  • Coach: an OpenAI-compatible server without /v1 in its address works, e.g. Open WebUI (#508).

Android: openGym-1.4.1.apk, check it with sha256sum -c openGym-1.4.1.apk.sha256.

v1.4.0

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 09 Oct 13:54

The biggest update openGym has had: a new exercise database with 5,632 exercises and new
animations, everything that was planned for v1.3.11 and v1.3.12, and the features you asked for
most. Forty-seven community pull requests from twenty contributors. Web bundle, APK and API image.

Nothing you logged changes. Every exercise that ever shipped keeps its id, name and muscles,
so workouts, routines, records and backups stay exactly as they are. A phone still on v1.3.x keeps
working with a v1.4.0 server, and shows the new exercises it doesn't know yet without losing them.

The new exercise database

  • 5,632 exercises instead of 1,324: bands and kettlebells, suspension trainers and landmines,
    machines of every kind, plus stretching, mobility, yoga and pilates. Each one with a short
    description, steps, body part, equipment and muscles, and its name in every app language
    (German names for the new exercises are machine-made and waiting for a review).
  • New animations, licensed from Gym visual: sharp 360 px loops inside the app, 180 px on the
    web and on your own server, and a still for every exercise.
  • Male or female drawings: about 940 exercises are drawn on both figures. Settings, Look,
    "Exercise drawings" picks which one you see. Only the picture changes, never your data.
  • A type filter in the library: strength, calisthenics, olympic, stretching, mobility, yoga
    and more.
  • Search rebuilt (#192): best matches first, typos forgiven ("sqat", "dumbel curl"), gym
    shorthand understood ("db", "rdl", "ohp"), plurals too ("pull ups"), and "Similar exercises"
    under the results, so a search almost never ends on nothing.
  • Swap suggests the same muscle first (#473), same equipment at the top.
  • The catalogue lives in the repository, one file per exercise, open to fixes and translations
    by pull request (catalogue/README.md). "Suggest a fix for this exercise" in the app opens an
    issue for that one exercise.

Training

  • Sets to failure: mark any set as taken to failure from its set menu and it gets a little
    purple "F". It counts as RIR 0 in your effort stats and the fatigue map (unless you rated it
    yourself) and stays a normal work set for volume and records. "Last set to failure" in an
    exercise's settings plans the final set as an all-out one.
  • Triple progression (#179): reps climb to the top of the range, then a set is added, up to
    the most sets you allow; when every set sits at the top, the weight goes up and you start over.
  • Back-off sets (dennismstfc, #475): every set one step lighter than the one before.
  • Per dumbbell or both together (#474): say what a dumbbell weight means, and volume and
    records count it right. Your old entries stay as you typed them.
  • Your dumbbell rack (#376): list the dumbbells you own, and progression, deloads, warm-ups and
    the + and − buttons only land on those.
  • Treadmill incline: an incline in % next to speed on walking, running and stair machines.
  • A fairer fatigue map (sg41, #436): counted in hard sets with its own recovery time per
    muscle, so a split no longer looks fatigued forever.
  • Pyramid sets with a weight per set (akram1089, #446, #445), 1RM from seven formulas with
    your pick of one (giulioleuci, #195, #155), per-set progress lines (iamtechnoana, #450, #145).

During a workout

  • Exercise chips (#323): a numbered dot per exercise at the top, filled as you go. Tap one to
    jump there.
  • Collapse completed exercises (helgehelge123, #241; Discord): in the list view a finished
    exercise folds into one line the moment you tick its last set, and a tap opens it again. Turn it
    on for good in Settings, Workout.
  • Focus view (giulioleuci, #222): one exercise at a time, nothing else on screen.
  • Pick your rest-end sound (#306): chime, classic, bell, beep-beep, whistle or soft, with a
    preview, on Android with the screen off too.
  • Superset names and their own rest after each round.

After a workout and around it

  • Last time and next time on the finish screen (#324): up, same or down, and what's next.
  • Share a workout as an image (anihothur, #455, #453).
  • Export to Garmin (#447): any finished workout as a .fit file, sets included.
  • Body measurements (robertgeica, #82): waist, arms, body fat and anything else, each with its
    own curve.
  • A note for a missed day (#261): sick, travelling, injured or your own words. The missed-day
    reminder leaves that day alone.
  • Health Connect on Android (DrDamnation, #371, #200): finished workouts and weigh-ins go to
    Health Connect.

Equipment and languages

  • Bench and pull-up bar as equipment (pawell67, #464), starter plans fitted to your equipment
    (#469), clubbell and macebell (akram1089, #425).
  • 🇧🇩 Bengali (mrjohndoel, #465), Polish exercise names and a full Polish review
    (pawell67, #467), French says tu and Russian says вы throughout (kurktchiev, #413, #414), plainer
    Turkish (iamtechnoana, #451).

Coach

  • The Coach sticks to your equipment and never sneaks in a machine you don't have.
  • A follow-up question in the chat no longer comes back as "something the app couldn't use" (#471).
  • Extra headers and an adjustable output limit for OpenAI-compatible endpoints (janviernine, #386;
    danifuuu, #390), bases that carry their own version (iamtechnoana, #449, #437), consent and intake
    in your language (kurktchiev, #415).

The app and your server

  • Cloudflare Access (EthanetXYZ, #439): pair with a server behind Zero Trust using a service
    token, which only ever goes to that one server.
  • Plain http:// servers at home can be paired (#428); the "not connected" line is gone on a phone
    kept local and can be closed by a guest (anshuman83-40, #462, #454).
  • The web image runs without root (mvanhorn, #466). Kubernetes and Helm now use port 8080.
  • Self-hosting got simpler: the exercise media ship inside the web image, nothing is downloaded
    on first start. An old media service or folder is no longer used and can go.
  • Helm chart (aphisitworachorch, #418), Nix flake and NixOS module (gerrydoro, #452), push
    to private addresses with ALLOWED_PRIVATE_IPS (ViktorShapoval, #448).

Fixes

  • In the Android app the exercise animations play by themselves (they sat on their first frame),
    and the rest-end tone plays with the screen off on phones that refused it before.
  • Warm-ups: unilateral ones count (sgoendoer, #388), a barbell warm-up is never lighter than the
    bar (#409), editing one leaves the rest of the ramp alone (#442).
  • Superset Move up/down stays inside the superset (#443), swipes land where they should (#457),
    zero added weight stays editable (ac1982, #461), Apple Health imports read each record's unit
    (ac1982, #432), plate targets stay loadable (ac1982, #433), big media exports stay importable
    (agammann, #430), the rest bar keeps its scale (aitordiaz, #423), a failed Sign out says what
    failed (#456), and a re-import from Strong or Hevy no longer splits one exercise into two.
  • Many small fixes from kurktchiev (#401 to #410, #412).

Licence

The exercise stills and animations are © Aliaksandr Makatserchyk, Gym visual, licensed for use in
openGym only and not covered by the AGPL. Details in NOTICE.md.


Android: openGym-1.4.0.apk (signed, same key as every release, SHA-256 in openGym-1.4.0.apk.sha256). It is larger than before because every exercise animation is inside the app.

Docker: ghcr.io/duartesantos8/opengym-api:1.4.0 and opengym-web:1.4.0 (also 1.4 and latest). The exercise media are part of the web image now; see the self-hosting notes above.

v1.3.10

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 07 Oct 16:46

A new look, a rotation for people who don't train on fixed weekdays, swipe actions, your own
accent colour, and a sync that holds on to every rep. Grab the APK below or pull the new images,
and then update the app on every device you sync. 🏋️

This one grew. The plan was a queue and a rotation; along the way the whole app got a calmer look,
swipe actions arrived, you can pick any accent colour you like, and sync was taken apart and put
back together so that no device can quietly lose your training again. Thirty-five community pull
requests from twelve contributors, fifteen issues closed, and a long night of testing behind it.
Web bundle, APK and API image.

Please update the app on every device that syncs (phone, browser tabs, the Android app). An
older phone keeps working, but only a fully updated set of devices gets all of the new safety
nets. Before you update, open each device once with internet so everything it owes the server has
arrived.

A new design

  • Settings on one screen, with search at the top, your account on a card, and everything else
    on sub-pages: Workout, Reminders, Units & language, Data & backup and friends. Nothing was taken
    away, it just has a home now. Type "rest", "swipe" or "vibrate" and you are there.
  • Plan is two tabs, Schedule and Routines. One switch between a fixed week and a rotation, a
    menu for export, print, import and starter plans, and the weekly muscle volume moved to Stats.
  • A workout screen that gets out of your way. The tab bar steps aside while you train, a
    labelled Finish, grouped ⋯ menus, a small thumbnail of the exercise, and the rest timer docked
    as one row at the bottom. Tap its clock to set the time left.
  • A rest-time wheel, iPhone style, for anything from 0:00 to 15:00, in Settings, in the new
    in-workout settings sheet and per exercise. Done without scrolling leaves your rest alone.
  • The in-workout settings sheet: rest timer, sound, vibrate, flash, screen awake, layout and
    effort without leaving the session.
  • Finish opens a small sheet: finish and save, or discard. And any set's menu can turn it into
    a warm-up set on the spot (or back).
  • One icon per idea. The shuffle icon used to mean twelve different things. Not any more.
  • New profiles start with smaller exercise animations and "weigh in before workouts" off. Your
    existing profile keeps whatever you had.

Rotation and the session queue

  • A rotation beside the fixed week (#158, #69; kurktchiev's #167 and giulioleuci's kurktchiev#1).
    A, B, C, A, ...: the next session is the next one you haven't done, whatever the weekday, so a
    missed Tuesday no longer shoves the plan around. Build the loop in Plan, reorder it, start a new
    pass whenever you like. Switching back to a fixed week asks first and leaves your weekdays as
    they were.
  • Home shows what is next, how much of the pass is done, and when the next one starts. A coach
    app that writes your week through the API is marked "Externally managed".
  • Planned vs completed weekly volume per muscle (EmilZapata, #333, #327), now on Stats, with
    each queue or rotation session counted once.

Swipe actions

  • Swipe a set left to delete it, with Undo, or right to copy it. In cards, list and compact,
    mirrored in Arabic. The last set stays put ("Keep at least one set, champ"). A timed per-side
    hold slides its left and right rows together.
  • Swipe in Plan: a routine left to delete (with Undo), right to duplicate; an exercise out of
    the routine editor or a routine out of the loop, with Undo too.
  • One switch for all of it, "Swipe actions" (Settings → Workout → Fine-tuning, or the in-workout
    settings sheet), on by default.

Your own colour

  • Any accent colour you like, from the rainbow swatch after the presets. openGym checks it
    against light and dark and nudges it until text on it stays readable. It syncs like the presets.

Safer sync, and no more lost data

This is the part we are proudest of, and the part you will hopefully never notice. Most of these
could already happen in v1.3.9:

  • Every change carries its own stamp, down to a single setting, plan day or routine field. Two
    devices editing the same routine now merge field by field instead of one copy winning whole.
  • A phone whose clock runs late no longer loses its edits and deletions.
  • A deletion stays deleted, even when another device changes something unrelated afterwards,
    and the order of your routines survives a conflict.
  • Two tabs in one browser no longer overwrite each other or the running workout, and signing
    out or switching accounts with a second tab open leaves nothing behind.
  • Signing out during a workout no longer deletes it, and signing in with a guest plan asks
    first. Anything that does not fit lands under Settings as kept changes, with "Save as a backup
    file", instead of disappearing.
  • A server that falls back to an older copy (say, from a backup) is merged with, not trusted
    blindly. A full disk or a slow answer can no longer hand a device an old state.
  • Importing a backup keeps the workout you are in the middle of, whether it replaces or merges.
  • On the server: every write is flushed to disk before openGym says "saved", a copy of the last
    good db.json is kept as db.json.bak, and the server starts from that copy if the main file
    is damaged. We killed it eighty times mid-write; every confirmed save was on disk.

Reminders and alerts

  • The missed-workout nudge (opt-in): one push on the evening of a planned day you skipped, in
    the tone you pick: Friendly, Guilt trip or Drill sergeant. It backs off after three missed days
    in a row and never bothers you on a rest day.
  • Vibrate on silent too (noname-nan, #375), Android: the end of a rest or a hold buzzes like
    an alarm even when the phone is on silent. Off by default.
  • The rest alarm on Android rings even when the notification permission dialog is still open, and
    a killed app brings its rest bar and countdown back.
  • "Rest over" rings only the device that rested (kurktchiev, #348).
  • Classic beeps (tomlongfield, #372): the quieter three-beep sound from before 1.3.9 is back as
    a choice.

More in the workout and history

  • Repeat today (Space-Hermes, #58): open a past workout in History and start it again today.
  • Pyramid sets (NtsCiccio, #367, #362): one rep target per set (12 · 8 · 6 · Max), a rest per
    set, and a "Max reps" chart in Stats.
  • Per side on timed holds (horusglez, #322): left and right each run the full hold, with a
    10-second "switch sides" pause in between.
  • Progress photos (horusglez, #361): every photo kept with a workout on one timeline, with a
    before/after slider.
  • Update routine from the session (FranciscoFavela, #336): copy an exercise's warm-ups, rest and
    note back into its routine.
  • "Last time" in days, weeks or months (xwr3, #363) instead of a date. Hover for the full one.
  • Pick your own backup folder on Android (#161), for example a sync app's folder.

Community pull requests

Thank you, all of you. This release is half yours.

Bug fixes

  • Custom exercises can be edited and deleted again, including older ones and ones from a shared
    or Coach plan (Teo230, #358; svillar, #378).
  • The up and down arrows move an exercise within a superset, and out of it at the edge (svillar,
    #377).
  • Strong's current export, the one with semicolons, imports again (davidjorgensen, #394).
  • Pairing the phone app says why it failed: a proxy or CORS rule in the way, a login page answering
    in openGym's place, or a server that can't be reached (#329).
  • A cardio block or a long hold at the end no longer shortens the workout's duration.
  • 8.5 in a reps field no longer becomes 85, a running plank survives a reload, and the rest timer
    stops when you sign out.
  • Loading the same starter plan twice no longer doubles your routines; a custom exercise can share
    a name with a catalogue one; an equipment profile no longer hides imported custom exercises.
  • Plates: a single stack counts each pair properly.
  • Imports refuse impossible dates and numbers (year 9999, negative, 1e308 kg), a Hevy session over
    midnight keeps its length, a zip's photos upload straight away, and the summary says how many
    rows it skipped.
  • Workouts dated later today are no longer in the future, durations and b...
Read more

v1.3.9 — edit your history, the two Discord reports fixed, password sign-in and thirty-nine community pull requests

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 28 Sep 14:03

The milestone was "edit your history", and it is in: fix a saved workout after the fact, move it to
another day, change how long it took, attach photos and videos to it. Around it, the two reports
from Discord that mattered most — a paired phone that quietly stopped syncing and lost a week, and
a routine planned at 2 × 10 that opened at 2 × 15 — are fixed at the root. Password sign-in for
instances that want it, more than one passkey per profile, your own picture on your own exercises,
Structural Balance, plate loading per set, the rest countdown in an Android notification, Ukrainian
and Arabic. Thirty-nine community pull requests from eighteen contributors, plus five more taken
in part. Web bundle, APK and API image.

The two reports from Discord

  • 🔌 A paired phone can no longer lose your workouts without telling you (andi242). After the
    server refused a phone's sign-in once — "Sign out everywhere" does that, so does an expired
    token — the next start of the app unpaired it silently but kept you on screen, every sync after
    that went nowhere and was counted as done, and Disconnect then wiped the phone. Every paired
    phone since v1.2.10 could get there. Now:
    • The app says when it is not connected, always: a line at the top for offline, a server that
      cannot be reached, a server that refuses this phone, an answer that is not the server's, and
      phone-only or guest use.
    • A refused phone keeps its pairing and its data and offers Pair again. Phones already stuck
      in that state from an earlier version are healed when they start, and their unsynced workouts
      reach the server once they are paired again.
    • Settings → Server & sync shows the host, the account, the status, the last sync, what is
      still waiting, and a Sync now button.
    • Disconnect and Sign out ask first when something has not reached the server yet — try again,
      export it, or go ahead anyway. Going ahead keeps a copy on the device, and it is merged back
      the next time you connect to the same account.
    • Pairing again or signing in to the same account merges, instead of replacing the phone's copy
      with the server's. A phone in use renews its sign-in on its own.
    • Signing in or pairing waits for your answer to "add this device's workouts?" before it touches
      anything, and a kg ↔ lb conversion, a reset or a backup import now reaches every device.
    • Tip if you were hit by this: the phone's daily backup files (Documents/openGym/, or
      Documents/opengym-backup-….json from before this version) may still hold the lost days —
      Settings → Import.
  • 📋 The plan owns the reps (seals187, Supportlik, #275, #216). A session copied its reps from
    the last time you did that exercise in any routine, so a 2 × 10 day opened at the 2 × 15 you
    had done somewhere else. Now a planned session starts from the plan (Settings → "Planned sessions
    start from": your plan, or your last session), progression runs per routine slot and falls back
    to the exercise's history only when the slot has none, an edited plan restarts progression with
    its new weight, and the card says "Plan: 2 × 10" (or "2 × 10–15" for a range).
  • 🔁 Double progression waits for the top of the range (Diego-Sanchez2000, #278, bluzername's
    #297) before it adds weight.
  • 🗂️ A stale second tab can no longer overwrite the server (danielkleinert, #283). Each tab
    tracks the revision it last saw, and a conflict keeps the latest edit of every routine and
    workout instead of whole copies.
  • 📴 The iPhone home-screen app opens offline again (tpodolak, #274, bluzername's #298) — and a
    slow connection no longer cuts a download off halfway.

Editing your history

  • ✏️ Edit a saved workout (Space-Hermes, #203, #143, #229) — weights, reps, sets and exercises,
    in the same screen you logged it on; progression and records re-read the corrected session. A
    workout emptied in the editor offers to delete it instead of saving nothing.
  • 🕐 Date, start time and duration (Parth-Vasave, #263, expressiveminute, #218), without
    touching what you lifted.
  • 📸 Photos and videos on a workout — attach them on the finish screen or in the workout's
    detail. They live on your server and the device, never in the synced data.
  • 🗓️ Log a missed day (svillar, #284) — mark a planned routine from a past day as done; its
    rows only look at the history from before that day.
  • 📚 Drop sets and supersets show in History, an exercise's history opens from a past workout, a
    workout copies as text, a finished session saves as a routine of its own (Space-Hermes, #211),
    and every weigh-in has a history with weekly averages.
  • 🚫 "Don't count for progression" for one exercise or a whole workout (the ⋯ and ⋮ menus) —
    an injury day stays out of the next session's numbers.

Accounts and sign-in

  • 🔐 Password sign-in, if you want it (#118). Off by default; an instance switches it on with
    PASSWORD_LOGIN=1, and each profile opts in by setting a password in Settings. Sign in with the
    profile's name or an e-mail address you add (no mail is ever sent). Passwords are stored with
    scrypt, repeated wrong guesses pause sign-in for that name, and an admin can hand out a one-time
    reset code. Removing a passkey or the password asks for proof first.
  • 🔑 More than one passkey, and a new device by code (AlexanderVott, #95). Settings lists a
    profile's passkeys to add, rename or remove, and Add another device shows a one-time code and
    QR; the code creates a passkey on the new device, never a session by itself.

During a workout

  • ⏸️ Pause the rest timer — paused time does not count, and the alert moves with it.
  • 🔔 The rest countdown in an Android notification (vitox013, #296, #122), with Pause, ±15 s and
    Skip, on time with the screen off. A louder chime, and a Vibrate switch of its own.
  • 🏋️ Plate loading per set (kurktchiev, #194) — each row shows the plates for its weight, from
    the plates you own; "No bar" Smith machines count from zero, and drop sets land on a weight you
    can actually load.
  • ⌨️ Keyboard shortcuts (#133) — Space or Enter ticks the next set, the arrow keys switch
    exercise, for a keyboard or a Bluetooth button.
  • ⏱️ Rest timers stay on Ready when they run out, and a timed hold may run into overtime
    (Space-Hermes, #204). The rest timer and a hold can no longer run at once (kurktchiev, #251).
  • The line under each exercise can show your best set instead of last time (Flxp49, #173); the
    next workout card peeks in while you swipe (Space-Hermes, #202, sgoendoer, #113); "Set current"
    goes straight to card view (bluzername, #262, xwr3, #260); typing an exact RIR/RPE no longer
    ticks the set on the first keystroke (kurktchiev, #288).

Plan, library and stats

  • 🧮 Structural Balance (Josevi, !140) — Stats compares your lifts with each other against the
    Poliquin, Thibaudeau and ATG ratios and names the weakest one.
  • 🖼️ Your own picture on your own exercises (#126, #170; based on horusglez's #295 and
    Vaibhav159's #246) — one photo, GIF or short video (up to 40 MB and 60 s) and one link per custom
    exercise. The file is stripped of its location data, kept on your server and on the device, never
    in the synced data, and works offline once seen; a YouTube link makes no request until you tap
    it. Shared plans carry the link, never the file.
  • 🔄 Replace an exercise in the routine editor (codedmind, #110) and keep its sets, reps, weight
    and rule; print a single routine or save it as PDF (Teo230, #282); swipe left to delete a
    routine in Plan (Agripa22, #286); a drag handle on computers (seals187, #277, sgoendoer, #114).
  • A compact "+" on a day that already has a routine (seals187, #276), a live result count in
    exercise search (GitLab !31), "benchpress" finds "bench press", cardio speed in mph for imperial
    users, the activity heatmap by time or by volume (Space-Hermes, #205), repeated exercises add up
    the same way in History and Stats (Space-Hermes, #212), a changed load cascades down the sets
    without overwriting the ones you set by hand (Space-Hermes, #209), and the Home body-weight card
    can be hidden (sacgsxr, #279).

Languages

  • 🇺🇦 Ukrainian (illinoiseeee, #285) and 🇸🇦 Arabic, laid out right to left (smsmy, GitLab
    !36) — seventeen languages in all.
  • 📖 Exercise names in seven languages: German (mkoester, #290), Spanish (AlexRomero12, #245),
    Russian (dima-po, #266), Italian and French (giulioleuci, #254), next to Brazilian Portuguese and
    Hungarian — each with a switch to show the English name beside it, or only the English name.
  • 🌐 DEFAULT_LANG (edgardjnr, #303) — an instance can pick the language of its sign-in screen and
    of profiles that never chose one; otherwise a new visitor starts in their browser's language.
  • Russian demo strings (dima-po, #265), untranslated Coach equipment chips (dima-po, #264), and CSV
    imports that read localized month names (sTOrM2202, #273).
  • "1 workout and 1 weigh-in" instead of "1 workouts and 1 weigh-ins" when signing in finds entries
    from while you were signed out.

The AI Coach

  • A review that swaps in an exercise the routine already has is told the rule and keeps the rest of
    its proposal, instead of failing as "unusable" (fama-lama, #313).
  • Routine icons from the Coach work, and its plans pick more varied exercises (ameer-khan-ashraf,
    #311).
  • The maximum message length is an admin setting (bluzername, #280, SSamDav, #267, #268).
  • A bonus set no longer reads as a stall you never had (kurktchiev, #287); Save in the Coach setup,
    the demo Coach's failure state and the intake line are fixed (kurktchiev, #289); a weekly review
    is due until it has run, not for one minute a week (kurktchiev, #249).
  • On an iPhone the Coach waits out a slow local model instead of giving up after 30 seconds
    (thedandano, part of #187), and the phone refuses a plain `http:...
Read more

v1.3.8 — the keyboard stays open, and twenty-four reports are closed

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 20 Sep 20:00

Twenty-four reports closed: the keyboard that would not stay open on iPhone and iPad, notifications
that arrived with notifications switched off, reps you could not read on a narrow phone, and
assisted pull-ups that recorded your progress backwards. Plus the four things this milestone
promised — reorder your routines, a Smith machine with no bar, two-decimal weights, and deleting an
account for real. Eleven community pull requests from six contributors. Web bundle, APK and API image.

The fixes people actually hit

  • ⌨️ The keyboard stays open (FabianReitz, hectorroaz, #242). On iPhone and iPad, tapping a field
    threw the keyboard straight back out about four times in five — worst on "Create new profile",
    where a new user could not type a name. The page-alignment guard blurred the field you had just
    tapped, because its "is the keyboard open?" check compares two numbers that both move while the
    keyboard animates in. Measured on iOS 26.6: innerHeight fell 684 → 374 while the visual viewport
    sat at 158, so the keyboard read as closed ~100 ms after every tap. Nothing acts on that check
    while a text field has focus now.
  • 🔔 Notifications respect the switch (shibbrich1, #239). The rest-timer alert asked for the
    browser permission itself and then fired whether or not Push was on — and a permission cannot be
    handed back. Off is off.
  • 📱 Reps are readable again on a narrow phone (seals187, #235). A row with weight, reps, an
    effort column and the +/− buttons left the number nothing: at 320 px the reps field was empty and
    102.5 kg showed as "102". Every number field now reserves the widest value it shows and the
    buttons give way first — checked across 108 combinations of width, layout, effort mode and
    per-side rows.
  • 🏋️ Assisted pull-ups and dips count the right way (dpatrongomez, kvalev, #232, #176). The
    stack carries part of your weight, so less assistance is the harder set — but 30 kg stayed the
    record over 20 kg, and progression answered a clean session by offering more help. Eight
    catalogue exercises are affected, and assisted on a custom exercise marks any other.
  • 📋 List view keeps your place (xwr3, #224) — it opens at the exercise you are on, not at the
    top of the session.
  • ➕ Extra sets stay out of the plan (kvalev, #233). A heavier bonus set used to raise next
    session's weight, and a hard one taken short reported the whole session as missed.
  • 🌐 Subpath deployments work (leon332157, #238). Behind a proxy that strips its prefix there is
    nothing to configure; one that passes the prefix through takes BASE_PATH=/gym.

The four this milestone promised

  • ↕️ Reorder your routines (hjeroen-git, #142) — arrows in Plan, and the Start screen, the
    day sheets and every picker follow the same order.
  • 🔩 "No bar" (Aoto Ideguchi, #138) — a Smith machine that carries its own carriage now counts
    plates from zero instead of snapping back to a 9 kg bar.
  • 🔢 Two-decimal weights (Aoto Ideguchi, #139) — Settings → Weight decimals, for quarter plates
    and microplates. 62.75 stays 62.75 instead of rounding to 62.8.
  • 🗑️ Delete an account (shibbrich1, #107) — the admin dashboard can remove a profile and
    everything attached to it, not just disable it. It asks twice and offers their data as a download
    first; it refuses to delete you or the last admin.

Community pull requests

  • kurktchiev: the iOS Home Screen icon behind an auth proxy (#184), an unknown path no longer serves
    a shell that cannot load (#185), and a way back to the Start screen on a day that already has a
    plan (#237).
  • Space-Hermes: typo-tolerant exercise search (#206), Olympic-lift muscle groups (#207), shared plans
    keep their kg/lb unit (#210), and a Coach test that no longer fails around midnight (#208).
  • aaron-rai: the activity heatmap follows your week-start setting (#220).
  • ncbachh: rename a workout while it is running (#228).
  • Strazdonis: the big weight read-out can be typed into (#234).
  • mkoester: standard ß in the German pack (#190).

Found by a QA sweep of every screen, and fixed

  • 🔍 Search: "wrist" returned 200 abdominal exercises, because the typo tolerance matched body parts
    and equipment as well as names. Fuzzy matching is now name-only, and only for words with no exact
    hit anywhere.
  • ⚖️ Switching kg ↔ lb left each workout's stored total and session body weight in the old unit, so
    History, the calendar and the heatmap showed kilo totals under a pound label. Body weight also
    converts at 0.1 now, not in plate steps, so a round trip comes home.
  • 📤 Sharing a plan stripped a custom exercise down to its name and body part: it arrived with no
    equipment, no muscles, and no way to edit or delete it.
  • 📥 Importing a second export re-created the custom exercises the first one had made, splitting the
    history in two; imported volume counted warm-up sets; hyphenated names ("Stiff-Legged Deadlift")
    were filed under the wrong body part.
  • 📊 Tapping an exercise in Stats → Strength threw instead of opening its history.
  • 🛠️ Admin: a profile whose stored file held a malformed entry blanked the whole dashboard, and that
    account could then not be disabled. The API answers 400 (or 413) for a request the client got
    wrong instead of 500 with a stack trace, and refuses an array as the state document — which used
    to wipe the profile and silently reset its revision.
  • 📐 Phone-width layout: the double-progression row wraps into pairs, list-row titles keep their
    width, page headers give way before their button, drop-set rows and cardio speeds are readable,
    and the column header lines up over per-side rows.
  • 🇷🇺 Muscle names no longer leak internal ids ("gluteal", "hip-flexors") into the picker, the config
    sheet or the Muscles list, and a day with one routine says "1 routine".

Known and not fixed: counts in Russian and the other Slavic packs use the English two-form plural
rule, so "2 дней" where it should read "2 дня". It affects every counter in the app and is being
done properly rather than patched here.

Image Tags Digest
registry.gitlab.com/duartesantos8/opengym/api 1.3.8 1.3 latest sha256:aa5ef20ce0fa8c8e274dc2772fdb7e3745f0f66c41988db8bda5452711a177da
registry.gitlab.com/duartesantos8/opengym/web 1.3.8 1.3 latest sha256:ab15e3ec654f8ccaa6f3d89adc557f726242b59680b7fd913ea651d348cb9463

Both images are linux/amd64 + linux/arm64. Android: openGym-1.3.8.apk, SHA-256 955a70e8a55a8540bbdc3071634bffff7048ef461028ea225c892a5d9b17796d — check it with sha256sum -c openGym-1.3.8.apk.sha256. Signed with the same certificate as every release since v1.2.7 (0d22a49e…), so it installs over your current one. Built from f91cde1c.


Published on GitHub on 2026-09-20, mirroring the GitLab release of the same tag, where the artefacts above were built. The same images are on GHCR, built from this release by GitHub Actions: ghcr.io/duartesantos8/opengym-api:1.3.8 and ghcr.io/duartesantos8/opengym-web:1.3.8.

openGym v1.3.7

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 12 Sep 22:04

The v1.3.6 tag's Android build failed on a double dash inside an XML comment, so the APK for everything in v1.3.6 is this one — plus the iPhone timer-sound fix that landed an hour later. Web bundle, APK and API image; v1.3.6 and v1.3.7 are the same code apart from the two items below.

  • 📦 The Android build builds again: a comment in styles.xml (from the safe-area work in v1.3.6) contained --, which XML forbids inside comments.
  • 🔊 Timer sounds on iOS (kurktchiev, #183, #152): every tone resumes the audio context first
    (a lock or app switch leaves it suspended and silent), the context is unlocked from the taps that
    lead to a timer, and Settings → Sounds gains Play sounds when the phone is on silent (off by
    default, iOS 17+), which switches the page's audio session to playback so the ring/silent switch
    no longer mutes the beep — at the cost of pausing whatever else the phone was playing.
Image Tags Digest
registry.gitlab.com/duartesantos8/opengym/api 1.3.7 1.3 latest sha256:b16ef522c1c8c2e1a3b0f24babbe896ca9b4611bc3fb091bd9876358c80efe91
registry.gitlab.com/duartesantos8/opengym/web 1.3.7 1.3 latest sha256:f43470b2ba50d5bb577a0702a273522693de744d6fabad7b67eb908825bce292

Both images are linux/amd64 + linux/arm64. Android: openGym-1.3.7.apk, SHA-256 650d8fa59ebbbcbce30d7d732f8fece593832c2ce0fd9ade34b2c937cbe97673 — check it with sha256sum -c openGym-1.3.7.apk.sha256. Built from d7f0f0d.


Published on GitHub on 2026-09-13, mirroring the GitLab release of the same tag, where the artefacts above were built (!NN numbers are GitLab merge requests). The same images are on GHCR, built from this release by GitHub Actions: ghcr.io/duartesantos8/opengym-api:1.3.7 and ghcr.io/duartesantos8/opengym-web:1.3.7. The full v1.3.6 change list — sync revisions, offline mode, push, the phone fixes, the Astra findings, eleven community merges — is under v1.3.6; this tag carries its artefacts.

openGym v1.3.6

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 12 Sep 21:32

Sync you can trust and a phone that behaves: signed in, the server's profile is always the truth, two devices merge instead of overwriting each other, the app polls for changes and works offline with a banner; reminders and push subscriptions heal themselves; chip rows, sheets under the notch and the tab bar are fixed on iOS; the twelve Astra findings, eleven community merges and a headless QA sweep of every screen. Web bundle, APK and API image.

The Coach reports after v1.3.5 had one thing in common: it failed and nobody could see why.

Bug round (2026-09-12) — the reports from the owner's own phone: push late or missing, desktop and
phone out of step, the Exercises chip rows scrolling the page, sheets under the Dynamic Island, the
tab bar mid-screen during a workout. Web bundle, APK and API image.

  • 🔄 Two devices no longer overwrite each other. Sync was "whichever copy was saved last wins,
    whole document": a desktop tab left open for a day and then touched — one setting — pushed its
    stale copy over the workouts the phone had logged meanwhile, and the phone adopted the loss at
    its next start (issues #128, #124; GitLab #33, #25). The server now keeps a revision on every
    profile (_rev, GET /api/data hands it out) and refuses a write that is not based on the
    current one (409, with the current document attached). The app merges the two copies — every
    workout, routine, weigh-in, custom exercise and favourite from both sides is kept; settings follow
    the newer copy — and pushes once more. It also asks the server what changed whenever the tab,
    window, app or network comes back (throttled to once per 15 s), one push and one pull at a time,
    and nothing pushes before the first pull of a session has landed. Older clients that send no
    revision keep overwriting as before, so a paired phone on an old build still syncs.
    Import and "Reset everything" are deliberate replacements and skip the merge.
  • 👤 Signed in, the server's profile is the truth — always. Signing in used to keep whatever
    copy had the newer timestamp, and anything tracked while signed out is always newer: the owner
    signed out, logged a session as a guest, signed back in and kept seeing the guest copy while the
    desktop showed the real profile. Sign-in (and pairing a phone) now adopts the server's profile —
    settings, plan, history, everything — and asks one question when the device holds workouts or
    weigh-ins the profile does not have: Add them (only those entries join the profile) or
    Keep profile as is. A profile that has no state yet still takes the device's data, as
    creating one always did.
  • 📡 The newest copy is fetched every chance it gets. While the app is open and signed in it
    asks the server for its revision every 30 seconds (one tiny request, GET /api/data/rev) and on
    every return to the tab, window, app or network, and fetches the document only when the number
    moved. A desktop tab left open all day now shows the phone's session within half a minute.
  • 📴 Offline mode says so. A signed-in user who cannot reach the server sees one line under the
    header — "Offline — your changes are saved on this device and sync when you are back online" —
    or "Not synced yet — tap to retry" when the server refused a push. The changes stay on the device,
    are retried by the poll and the moment the network is back, and a toast confirms "Back online —
    synced with the server". The app also flushes a pending change on pagehide, since Safari can
    kill the home-screen app without a visibility event. Guests and the standalone Android build have
    no server and see none of this.
  • 🧱 The home-screen app comes back without a network. The service worker cloned each
    response for its cache a moment too late — after the page had started reading it — so the
    clone failed silently and nothing but exercise media was ever cached: a reload of the installed
    app without a connection gave the browser's "you're offline" page. The worker now caches the
    shell and every script, style and icon the built index.html references at install, keeps them
    fresh network-first, and serves them when the network is gone. Its cache is named after the
    build, so a deploy is a new worker with its own cache and the previous build's files are
    dropped. Starting the app offline also raises the offline line at once, and the in-progress
    workout, stored on the device, is exactly where it was.
  • 🔔 Reminders that were due still arrive. The workout-day reminder wanted its exact minute:
    an API restart, a redeploy or a stalled tick across those 60 seconds lost the whole day's
    reminder. A reminder is now sent for up to 15 minutes after its time, once per day, never later.
    The tick also stops re-reading every account's state every 10 seconds (it re-reads only files
    that changed).
  • 🔁 A push subscription the server lost comes back on its own. The browser keeps its
    subscription through anything that happens on the server — a row pruned after a dead send, a
    rebuilt db.json, a regenerated VAPID key — and Settings said "on" while nothing would ever
    arrive. On every signed-in start the app hands the server its subscription again
    (POST /api/push/subscribe is an upsert, GET /api/push/status is what the switch shows),
    a subscription made for a key the instance no longer has is replaced, the service worker answers
    the push service's own key rotation (pushsubscriptionchange), a payload that fails to parse
    still shows a notification instead of counting as a silent push, and a send refused with 403 is
    pruned like a dead endpoint. Off https the row says push is not supported instead of hanging.
  • ⏱️ A rest-timer alert belongs to the device that started the rest. The server held one timer
    per account, so a desktop tab finishing its rest on screen cancelled the alert the phone in the
    gym was waiting for. Each browser now carries its own token; older clients keep the old behaviour.
    (The Android APK has no Web Push: its reminders are local notifications scheduled on the phone.)
  • 👉 The Exercises chip rows scroll sideways only. Revealing the active chip used
    scrollIntoView, which also scrolls every ancestor: with the row above the fold a tap made the
    whole page jump. The row now moves only its own scroll position, it contains overscroll on
    both axes, and the chips' enlarged tap area no longer gives the row a 4 px vertical scroll range
    of its own (a diagonal swipe or a wheel tick used to shift the whole row up and leave it there). On a desktop browser a chip row can be dragged with the mouse (HenryByte, !119, #147).
  • 📱 Sheets stop short of the notch / Dynamic Island. Every bottom sheet's height now subtracts
    the top safe-area inset (and so does the exercise picker when the keyboard is up); centred
    dialogs scroll inside themselves instead of growing past the screen. On Android the app declares
    the cutout mode and adjustResize, so the same insets are real there.
  • 🧭 The tab bar stays at the bottom after the keyboard. On iOS a weight field kept its focus
    when you tapped the tick (WebKit does not blur on button taps), the keyboard went away, and the
    viewport stayed displaced — tab bar and rest timer mid-screen. Ticking a set and opening a sheet
    now blur the field, and the correction also works while a sheet has the page pinned. The mobile
    workout screen keeps less blank space under the last set (mflova, !121).
  • ⚖️ Weigh in before workouts is a switch (kurktchiev, #174, #137): off, Start goes straight into
    the session; body weight can still be logged from Home and Stats.
  • 🇨🇭 Swiss German (mkoester, #171): de-CH derived from the German pack (ss for ß, Swiss
    number formatting), no second pack to maintain.
  • 🍎 iOS shell builds with Xcode 26 / iOS 26 (shailantani, #117; thedandano, !125): UIScene
    lifecycle, deployment target 15.5.
  • 🔥 Rest between warm-up ramp sets (kurktchiev, #164): a per-exercise warmupRestSec for
    plan files; the break into the first work set stays the working rest.
  • 🧰 Custom exercises (LuckaPow, #162): equipment is chosen (and required), muscle names read
    like the built-in ones, cardio gets its target, a chip's focus outline is no longer clipped in
    a sheet.
  • 🐳 nginx resolver is configurable (T13o, !110, #148): RESOLVER env (default Docker's
    127.0.0.11) so /api resolves under Podman and Kubernetes.
  • 🖨️ Plan as PDF on the phone (HenryByte, !118, #149): "Print as PDF" opens the OS print
    dialog, which saves to Files / Drive.
  • 🎛️ The equipment filter survives a body-part change in the exercise picker
    (ErrorUsernameAlreadyTaken, !120, #150), and per-side (L/R) data is preserved through progression
    and session flows (!133).
  • 🔐 Coach job directory (T13o, !135): permissions set with chmod instead of chown, so the
    built-in Coach runs on a container without CAP_DAC_OVERRIDE.
  • 🛡️ The twelve Astra findings (kurktchiev, #166, #160): a request target that does not parse
    answers 400 instead of an unhandled rejection; a stored state the reminder tick cannot read is
    skipped instead of taking the API down, and PUT /api/data refuses non-array workouts /
    routines; the push-endpoint address rule judges every IPv6 spelling; "sign out everywhere"
    voids unredeemed pairing codes; the built-in Coach's daily and instance limits cannot be reset by
    "forget", queued jobs hold budget and are dropped on forget, scheduled reviews do not bill the
    same workout twice; the local copy remembers its owner and is wiped when another profile signs
    in; a copy adopted from the server keeps the server's timestamp; "Reset everything" says what it
    deletes and where; a 413 on sync is shown instead of swallowed; nginx allows 5 MiB on /api/.
  • 🌍 Seven strings that arrived with combine routines, the layout switch and the 1RM deload were in
    no locale pack and showed in English in every l...
Read more

v1.3.5

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 11 Sep 09:19

One bug, and the one everybody with the Android app and their own API key ran into. Web bundle and
APK; the API only carries the version number.

  • 🔑 "Bring my own API key" works on the phone. Since v1.3.0 every key-store call on Android
    hung before it started: the secure-storage plugin was handed to the app as the value of a promise,
    and a Capacitor plugin object answers any property name with a native method — then
    included — so the promise took it for a thenable, called a native SecureStorage.then() that does
    not exist, and never settled. That one stuck await was all three reports at once: "Save and use
    the Coach" greyed out forever, the key "not saved" when you came back, and a Coach that sat on
    "thinking…" without end because the job read the key first. The plugin now travels inside a plain
    object, a test drives the store through a Capacitor-style proxy so it cannot come back, and the
    whole flow — save, intake, plan, restart with the key still there — was run on an emulator before
    tagging. The web app and the "use my self-hosted openGym" mode were never affected.
    (issues #42, #58; reported by many on Discord)

Install or upgrade

docker compose pull && docker compose up -d
Image Tags Digest
registry.gitlab.com/duartesantos8/opengym/api 1.3.5 1.3 latest sha256:ea111626ba222beb6f0de29f2b458272b2e51b0e84a00a806c7ff2335bd52c0c
registry.gitlab.com/duartesantos8/opengym/web 1.3.5 1.3 latest sha256:cbba591c7441cf297bdbedb48bcd0448367407e84c8829c993d1cae3afad94a6

Both images are linux/amd64 + linux/arm64. Android: openGym-1.3.5.apk, SHA-256 b4f4747930689703516cbbad26986f1a08b8a16d791e2b7806c94c5291de583c — check it with sha256sum -c openGym-1.3.5.apk.sha256. Built from 684b005.


Published on GitHub on 2026-09-11, mirroring the GitLab release of the same tag, where the artefacts above were built (!NN numbers are GitLab merge requests). The same images are on GHCR, built from this release by GitHub Actions: ghcr.io/duartesantos8/opengym-api:1.3.5 and ghcr.io/duartesantos8/opengym-web:1.3.5.

v1.3.4

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 11 Sep 09:18

Two things noticed on the phone right after v1.3.3. Web bundle and APK; the API only carries the
version number.

  • 🎨 The effort picker looks like the rest of the app. The v1.3.3 sheet was a grid of colour-edged
    tiles that matched nothing else on screen. It is now the same list the ⋯ menus use: a tinted
    square with the value where the icon sits, the sentence as the row, a tick on the current one, and
    an "Exact RIR" row carrying the app's own stepper, tinted like the logged cell. Same six levels, same
    colours, same free value.
  • 🖼️ Animations that fail to load fall back instead of breaking. If the animation cannot be
    fetched (dropped connection, CDN hiccup, an instance that gates media behind a session) the still
    picture takes its place; if that fails too, a neutral tile does, and a tap tries again. No more
    broken-image glyph on a white block.

Install or upgrade

docker compose pull && docker compose up -d
Image Tags Digest
registry.gitlab.com/duartesantos8/opengym/api 1.3.4 1.3 latest sha256:fc747675504f7389218e2d655bcf31ab061552b99823676113351c5879dc51ce
registry.gitlab.com/duartesantos8/opengym/web 1.3.4 1.3 latest sha256:5b8d83cf068d195e4a1153666742d2d72b5e490904af93c73b554c431ccc2961

Both images are linux/amd64 + linux/arm64. Android: openGym-1.3.4.apk, SHA-256 eef8189f9eee3c1f66ab4d4ac1fac6890b903fb2d0d7e518f4f9fad93d7350a9 — check it with sha256sum -c openGym-1.3.4.apk.sha256. Built from 9c7c351.


Published on GitHub on 2026-09-11, mirroring the GitLab release of the same tag, where the artefacts above were built (!NN numbers are GitLab merge requests). The same images are on GHCR, built from this release by GitHub Actions: ghcr.io/duartesantos8/opengym-api:1.3.4 and ghcr.io/duartesantos8/opengym-web:1.3.4.

v1.3.3

Choose a tag to compare

@DuarteSantos8 DuarteSantos8 released this 11 Sep 09:18

The workout screen gets out of the way, and the bug round from the board. Same day as v1.3.2 on
purpose: that one is the contributors' batch, this one is the redesign and the fixes on top of it.
Self-hosters need the new web bundle and images; the API is unchanged. This is the release to
install on Android — it is the first APK that can update itself.

The workout screen

  • ⋯ One menu per exercise. Note, details, progression settings, bar weight, add a warm-up set,
    make a superset with the previous or next exercise, swap, move up, move down, remove — all behind
    one button next to the exercise name, acting on exactly that exercise, also inside a superset. The
    rows of buttons that used to sit in the header, under the sets and under the card are gone; a
    pencil still appears once an exercise has a note. (issue #20)
  • 🔢 The set number is the set's menu: drop set, rest-pause burst, remove this set. No more
    "+ Drop / + Burst" chips on every row and no per-row X on warm-ups.
  • 📌 List view keeps the header pinned — name, clock, set counter, discard and finish stay at the
    top while the session scrolls.
  • 🎛️ Settings → During a workout → Workout controls. Four switches bring any of the old groups
    back: weight and reps +/− buttons (off: tap the number and type it), drop/burst shortcuts on every
    set, superset buttons in the header, move/swap/remove buttons below the exercise. Existing profiles
    read as the lean default.
  • 🌈 Colour-coded RIR / RPE. An unrated set shows one "RIR" (or "RPE") button; tapping it opens
    a picker with six levels, each with a sentence — "Nothing left, went to failure" through "Easy,
    warm-up territory" — and a field for an exact value. A logged rating tints its cell by how close
    to failure it was, the same colour whether you think in RIR or RPE; the +/− on it follow the
    Workout-controls switch. (ErrorUsernameAlreadyTaken, !91 — issue #32)
  • 📖 History without leaving the workout. ⋯ → History: a line of your best set (or estimated
    1RM, longest hold, minutes) over time and the last ten sessions with every set, the volume and a
    PR marker. Also reachable from an exercise's details in the library. (issue #43)
  • ▶️ On the workout screen the centre tab button reads "Workout" and stays lit instead of an idle
    "Resume"; Resume from anywhere else returns to the exercise you marked, which no longer moves on
    its own. (issues #29, #21)

Planning and library

  • ⭐ Favourite exercises. Star an exercise in its details; favourites sort first in the picker,
    the library and the muscle explorer, and the picker gets a Favourites chip. (issue #6)
  • ⚖️ Switching kg ↔ lb converts your numbers — or keeps them and only changes the label, your
    choice in a sheet: logged sets and drops, working weights, routine targets and increments, warm-up
    configs, body weight, goal and bar weights; lb rounded to 0.5, kg to 0.25. (issue #22)
  • 🪢 Resistance bands count as bodyweight equipment: one reps stepper and the reps-then-sets
    progression, unless you switch Bodyweight off for that exercise. (issue #39)
  • 🔥 Warm-up ramps snap to the exercise's own increment (1.25 kg plates) instead of the unit default.
  • 📄 Copying a copy of a routine gives "Name (Copy 2)"; the swap picker's "+" quick-adds like every
    other picker; a weekday whose routine no longer exists no longer triggers the starter-plan prompt.

Android

  • 🔄 In-app update. Settings → Data shows "openGym vX available" when a newer release exists; one
    tap downloads the signed APK, verifies its SHA-256 against the published checksum and opens the
    installer. No checksum, no install. Needs the "install unknown apps" permission the first time.
    (ErrorUsernameAlreadyTaken, !40 — issues #38, #9)
  • 🧠 Saving the Coach with your own API key no longer hangs on a greyed-out button: the mode is
    written before the key, the secure store gets a timeout, and every failure says what went wrong
    in a toast. (issue #42)
  • 🔢 The APK carries version code 17 (v1.3.2: 16). Two releases had reused 15; the update check
    compares the version name, so nothing changes for you, but Android's own "newer" check is honest again.

Install or upgrade

docker compose pull && docker compose up -d
Image Tags Digest
registry.gitlab.com/duartesantos8/opengym/api 1.3.3 1.3 latest sha256:ada6b341893463e892b96d6df7bf83219a862ab46d13838b378594641e8ab800
registry.gitlab.com/duartesantos8/opengym/web 1.3.3 1.3 latest sha256:af9cecac3ddb11b06e4e17c208b3fa54758bdc7b95d96b67e020e7f1deffe013

Both images are linux/amd64 + linux/arm64. Android: openGym-1.3.3.apk, SHA-256 0fadb6b096355607a63a6f74507962184de7c3e609bbbc2b0c4a2e7005225939 — check it with sha256sum -c openGym-1.3.3.apk.sha256. Built from 078f091.


Published on GitHub on 2026-09-11, mirroring the GitLab release of the same tag, where the artefacts above were built (!NN numbers are GitLab merge requests). The same images are on GHCR, built from this release by GitHub Actions: ghcr.io/duartesantos8/opengym-api:1.3.3 and ghcr.io/duartesantos8/opengym-web:1.3.3.