Skip to content

feat: add automatic weight sync from Apple Health and Google Health Connect#1156

Open
JohnWeidner wants to merge 9 commits intowger-project:masterfrom
JohnWeidner:feat/health-platform-weight-sync
Open

feat: add automatic weight sync from Apple Health and Google Health Connect#1156
JohnWeidner wants to merge 9 commits intowger-project:masterfrom
JohnWeidner:feat/health-platform-weight-sync

Conversation

@JohnWeidner
Copy link
Copy Markdown
Contributor

@JohnWeidner JohnWeidner commented Mar 28, 2026

Summary

  • Add automatic weight sync from Apple Health (iOS) and Google Health Connect (Android) using the Flutter health package
  • Import weight entries with their original timestamps — the backend supports multiple entries per day (DateTimeField since migration 0004)
  • Opt-in via a Health sync toggle in Settings, with platform permission handling
  • Convert kg values from health platforms to the user's preferred unit (kg or lb) before POSTing
  • Show the unit label (kg/lb) on the weight entry form based on user profile preference
  • Fix DashboardWeightWidget to rebuild when weight data changes (pre-existing bug)
  • Fix WeightEntry.copyWith parameter type (int?num?) (pre-existing bug)
  • Fix BodyWeightProvider.findByDate() to use calendar-date comparison via existing isSameDayAs() extension (pre-existing bug)

How it works

  1. User enables "Health sync" in Settings → app requests Health Connect / HealthKit permissions (including historical data access)
  2. On app open, the sync reads new weight entries from the health platform since the last successful sync
  3. Entries are converted to the user's preferred unit, deduplicated against existing data, and POSTed to the backend
  4. BodyWeightProvider is refreshed so the dashboard and weight screen update immediately

Known limitations

  • Weight units are display-only in the wger backend — the backend stores raw numbers with no unit metadata. Changing the kg/lb preference relabels all historical data without converting values. This is a pre-existing design decision in the wger project, not introduced by this PR.
  • iOS testing is limited — verified that the app runs, permissions are granted, and empty data is handled without errors on iPhone XR (iOS 18). Full sync testing was done on Pixel 7a (Android 16).

Platform configuration

  • Android: Health Connect permissions (READ_WEIGHT, READ_HEALTH_DATA_HISTORY), FlutterFragmentActivity, minSdkVersion raised to 26
  • iOS: HealthKit entitlement and NSHealthShareUsageDescription in Info.plist

Test plan

  • flutter analyze passes (no new warnings)
  • flutter test — all tests pass (1 pre-existing timezone failure)
  • Unit tests for weight conversion logic and HealthSyncState
  • Regression tests for copyWith and findByDate bug fixes
  • Settings test updated for ProviderScope
  • Weight form test updated for UserProvider mock
  • Manual testing on Pixel 7a: enable sync, unit conversion (kg/lb), historical data import, dashboard refresh, disable/re-enable, incremental sync
  • Manual testing on iPhone XR: enable sync, permission grant, empty data handling
  • Full iOS sync testing with Apple Health data

closes: #1153

🤖 Generated with Claude Code

JohnWeidner and others added 9 commits March 27, 2026 14:12
…onnect

Import body weight data from Apple Health (iOS) and Google Health Connect
(Android) into wger when the app is opened. Uses the Flutter `health` package
for cross-platform access. Feature is opt-in via a settings toggle.

Key changes:
- Add HealthSyncNotifier (Riverpod) for sync orchestration
- Add HealthSyncSettingsTile in settings page
- Add health package dependency and platform permissions
- Fix WeightEntry.copyWith parameter type (int? -> num?)
- Fix BodyWeightProvider.findByDate() to use calendar-date comparison
- Raise Android minSdkVersion to 26 (Health Connect requirement)
- Change MainActivity to extend FlutterFragmentActivity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show "Weight (kg)" or "Weight (lb)" on the weight entry form based on
  the user's profile preference
- Convert health sync values from kg to lb before POSTing when the user's
  profile is set to lb
- Check/request health permissions on sync to handle app restart
- Fix weight form tests to provide UserProvider mock

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sqlite3_flutter_libs 0.6.0+eol no longer bundles the native SQLite
library correctly on newer Android toolchains, causing a
DriftRemoteException on startup (dlopen failed: libsqlite3.so not found).

Replace it with drift_flutter which is the current recommended package
for providing native SQLite to drift databases. Also suppress the
StackFrame assertion error from the stack_trace package that was masking
the real error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pass isMetric to enableSync() so the initial sync from the settings
  toggle converts kg to lb when the user's profile is set to lb
- Refresh BodyWeightProvider after sync from settings tile so the
  dashboard and weight screen update immediately
- Fix DashboardWeightWidget to compute sensibleRange() inside the
  Consumer builder so it rebuilds when weight data changes
- Add permission check in syncOnAppOpen() for app restart scenarios
- Add unit tests for weight conversion logic and HealthSyncState

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use existing isSameDayAs() extension in findByDate() instead of
  manual year/month/day comparison
- Build a Set of existing timestamps for O(1) dedup lookups instead
  of O(n*m) .any() scan per data point
- Simplify nullable bool check (_isAvailable != true)
- Remove comments that restate the code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add healthSync, healthSyncDescription, healthSyncSuccess, and health
keys to app_en.arb and use AppLocalizations instead of hardcoded
English strings in the settings tile and settings page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the 30-day lookback limit on initial sync. Pull all available
weight data from Health Connect on first enable. Add
READ_HEALTH_DATA_HISTORY permission to AndroidManifest to allow
reading data older than 30 days.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Call requestHealthDataHistoryAuthorization() on Android after initial
permission grant. Without this runtime request, Health Connect limits
data access to the last 30 days regardless of the manifest permission.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JohnWeidner JohnWeidner marked this pull request as ready for review March 28, 2026 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

import weight data from Health Connect

1 participant