Repository navigation
OpenVitals 2.7.0
Released 2026-08-26.
This release is about the app answering questions it used to leave to the user. The daily goal card now says how far ahead or behind a week is and what each remaining day needs, instead of a count of days that hit the mark. Offline maps rotate under two fingers and keep the live fix centred while recording. The summary fills tile by tile as each metric arrives, so a phone with a busy Health Connect opens straight away instead of holding a spinner for minutes. A Garmin sync no longer tells the watch to drop a day of data it never received. And the app speaks Simplified Chinese.
- Goal balance and per-day catch-up. Goals met and success rate said how many days hit the goal; they could not say that a week with six met days still ended 606 steps short, or what each remaining day needs to average for the week to land on goal. The daily goal card on the activity screens now carries a standing line - so much ahead, so much behind, on track - and a catch-up line with the per-day figure for the days left, today included. The statistics grid gets a Goal balance tile. Every elapsed calendar day is judged, a day with nothing logged counting as zero, and the sign stays in your favour whichever way the goal points.
- Map rotation, and a camera that follows the recording. Both offline renderers take two-finger rotation. MapLibre gets its compass back to reset north; Mapsforge, having none, gets one that appears whenever the map is off north. The destination flag stays upright on a rotated map. While recording, the camera keeps the live fix centred; panning hands the wheel to you, and the recenter button hands it back.
- Simplified Chinese. A full translation, offered by the in-app language picker.
- The summary fills as each metric lands. Reported by a user whose app "refuses to open" for minutes at a time, worse later in the day. The dashboard waited on one batch of Health Connect reads before drawing anything. It now renders at once with every tile loading and dispatches one read per metric, in widget order, so a tile answers when its own read does. Tiles that genuinely share a read stay together. A throttled Health Connect no longer stalls the screen: a read that would have to wait more than a couple of seconds shows its fallback and the dashboard says "wait about N min" instead of spinning. The weekly cardio read also asked for a whole day of one-minute heart-rate buckets in one request, which failed on exactly the watches with the most data and silently fell back to step estimates; it now reads five-minute buckets in bounded chunks that retry alone.
- The recording screen leads with its tabs. The tab row comes first, and the Dashboard layout button sits under it rather than pushing the tabs down. CoMaps guidance lives on the map tab only - it is about the route, so it belongs with the route; the stats grid already carries it as a placeable cell. Start no longer refuses with a toast about a card you cannot see from the stats tab: it asks, with "Start anyway" and a way into CoMaps to set a route, and asks once. Dismissing the guidance card while setting a ride up no longer brings it straight back once the ride is running.
- Sleep day view drops the averages of one night. Avg gap and the sleep target card described a mean of a single night. The stat is left out on the day view and the target card needs two nights to average; the daily goal card above already says what one night is. The four key-metric cards on a single night restated what the timeline, the time-in-bed shares and the sleep score already show, so they are gone from the day view. Week, month and year keep everything.
- A Garmin sync never tells the watch to drop a file it did not download. The watch reuses its monitoring file numbers, and the sync's memory of what it had already copied was keyed on type and number alone. A new day's file matched a key from weeks earlier, was skipped, and then - on the theory that a held file the watch still offered had missed the flag - was told it was safe to archive. A day and a half of heart rate and steps went that way. The key now carries the file's date and size, and the archive flag only follows a download made in the same session.
- The recording screen's app bar is back. The activity entry route was compared with its query string attached, so it never matched: no title, no dashboard editor pencil, no outdoor-mode toggle, focus mode never hid the bar, and outdoor mode never reached the chrome - the grey band above and below a black screen. It matches on its path now. With the pencil back, the duplicate Dashboard layout button that had been added to cover for it is gone.
- Black chrome under AMOLED, and outdoor mode reaches the frame. The navigation bar took a near-black that lights a grey band along the bottom of a black screen; under the AMOLED theme it is pure black now. Outdoor mode repainted the recording body but not the app bar above or the gesture-bar inset below, framing the screen in exactly the contrast the mode exists to remove; it covers both now.
- Large Apple Health exports no longer run out of memory. Steps, distance and active energy were deduplicated across sources by sorting the whole export's worth together, so every one was held until the parse finished; a step-dense export died against the heap cap a third of the way through. Records that can no longer overlap anything still to come are converted and released as the parse runs.
The app keeps the same package name and signing certificate, so this installs as a normal update.
Distribution flow:
- Codeberg release with signed APK, signed debug APK, and signed Android App Bundle assets.
- Direct Google Play production upload from the approved Woodpecker deployment.
Generated from docs/releases/2.7.0.md. Edit it there; changes made here are overwritten.
This wiki mirrors the Markdown in Hale-MTU/OpenVitals on every push to main.
Features
- Features
- Achievements
- Activity And Training Plans
- Activity Metrics
- Apple Health Import
- Beverage Logging And Caffeine
- Bluetooth LE Sensors
- Body Energy
- Body Metrics
- CoMaps Navigation Context
- CSV Import
- Cycle Tracking
- Daily Readiness
- Elevation Correction
- Feature Map
- FIT Files Import
- Food Logging
- GPX/KML/KMZ/TCX Route Import
- Health Connect Metrics Dashboard
- Health Report Export
- Heart And Vitals
- Heart Rate Recovery
- Home Screen Widgets
- Hydration
- Manual Entry Of Metrics
- Medical Records
- Metric Detail Customization
- Mindfulness
- Non Health Connect Metrics Dashboard
- Nutrition
- Offline Maps Support
- Onboarding And Permissions
- Preloaded Beverage Nutrition Reference
- Privacy, Support, And Diagnostics
- Recording Of Activity
- Reminders
- Settings And Preferences
- Sleep Score And Recovery
- Sleep Tracking
- Statistics
- Sync With Another Phone
How-to
App
- App Guide
- FAQ
- Getting Started
- Health Connect
- Install
- Local And Connected Editions
- Permissions
- Privacy
- Screenshots
- Support
Reference
- Design Reference
- Reference
- Design Guidelines for Offline & Sync
- OpenVitals UI Notes
- Reference: Data Capture
- Reference: Data Display
- Reference: Health Connect Matchmaking
- Reference: Health Connect Onboarding
- Reference: Health Connect Permissions
- Reference: Health Connect UX
- Reference: Promoting Health Connect
Engineering
- Code Analysis
- Engineering
- Flutter ↔ Kotlin test-parity matrix
- apple-health-import
- Architecture
- body-cycle-recovery
- Design system conformance
- Development
- Feature Playbook
- Flutter -> Kotlin test parity: domain/data/core/contract/state/navigation/di/bootstrap/l10n/widget_test
- Flutter → Kotlin test-parity matrix: features section
- Flutter → Kotlin test-parity matrix: ui / goldens / integration / fixtures
- Flutter-to-Kotlin test-parity matrix — dashboard + devicesync
- manual-entry
- Translations
Proposals
- Proposals
- Activity Start Flow Analysis
- Activity Start Flow Simplification Proposals
- Caffeine Detail And Future Sleep Insights
- Cycle Tracking: Design and Status
- Medical Records Through Health Connect
- Medical Records: What Is Left
Releases
- OpenVitals 2.16.0
- OpenVitals 2.15.2
- OpenVitals 2.15.1
- OpenVitals 2.15.0
- OpenVitals 2.14.5
- OpenVitals 2.14.4
- OpenVitals 2.14.3
- OpenVitals 2.14.2
- OpenVitals 2.14.1
- OpenVitals 2.14.0
- OpenVitals 2.13.0
- OpenVitals 2.12.0
- OpenVitals 2.11.2
- OpenVitals 2.11.1
- OpenVitals 2.11.0
- OpenVitals 2.10.1
- OpenVitals 2.10.0
- OpenVitals 2.9.1
- OpenVitals 2.9.0
- OpenVitals 2.8.0
- OpenVitals 2.7.3
- OpenVitals 2.7.2
- OpenVitals 2.7.1
- OpenVitals 2.7.0
- OpenVitals 2.6.6
- OpenVitals 2.6.5
- OpenVitals 2.6.4
- OpenVitals 2.6.3
- OpenVitals 2.6.2
- OpenVitals 2.6.1
- OpenVitals 2.6.0
- OpenVitals 2.5.0
- OpenVitals 2.4.1
- OpenVitals 2.4.0
- OpenVitals 2.3.2
- OpenVitals 2.3.1
- OpenVitals 2.3.0
- OpenVitals 2.2.8
- OpenVitals 2.2.7
- OpenVitals 2.2.6
- OpenVitals 2.2.5
- OpenVitals 2.2.4
- OpenVitals 2.2.3
- OpenVitals 2.2.2
- OpenVitals 2.2.1
- OpenVitals 2.2.0
- OpenVitals 2.1.0
- OpenVitals 2.0.4
- OpenVitals 2.0.3
- OpenVitals 2.0.2
- OpenVitals 2.0.1
- OpenVitals 1.9.0
- OpenVitals 1.8.0
- OpenVitals 1.7.7
- OpenVitals 1.7.6
- OpenVitals 1.7.5
- OpenVitals 1.7.4
- OpenVitals 1.7.3
- OpenVitals 1.7.2
- OpenVitals 1.7.1
- OpenVitals 1.7.0
- OpenVitals 1.6.3
- OpenVitals 1.6.2
- OpenVitals 1.6.1
- OpenVitals 1.6.0
- OpenVitals 1.5.1
- OpenVitals 1.5.0
Project