Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 42 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Builds the Windows app and the Android APK, then publishes them as a single
# GitHub Release.
# Builds the Windows app, macOS app, and Android APK, then publishes them as a
# single GitHub Release.
#
# It runs only when you push a version tag like "v0.1.0" — see how to do that
# in the README's "Cutting a release" section. The two build jobs upload their
# in the README's "Cutting a release" section. The build jobs upload their
# artifacts; a final release job attaches them to one release and generates the
# notes once (so they aren't duplicated).

Expand Down Expand Up @@ -112,16 +112,53 @@ jobs:
name: android
path: "intervalssync-${{ github.ref_name }}-android.apk"

macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6

- name: Compute version from tag
run: echo "APP_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"

- name: Stamp version into the app
run: echo "__version__ = \"$APP_VERSION\"" > src/intervalssync/_version.py

- name: Stamp Dropbox app key into the app
env:
IGPSYNC_DROPBOX_APP_KEY: ${{ secrets.IGPSYNC_DROPBOX_APP_KEY }}
run: |
python -c "from pathlib import Path; import os; Path('src/intervalssync/_dropbox_app_key.py').write_text('DROPBOX_APP_KEY = ' + repr(os.getenv('IGPSYNC_DROPBOX_APP_KEY', '')) + '\n', encoding='utf-8')"

- name: Build macOS app
run: uv run flet build macos --yes --verbose --build-version "${{ env.APP_VERSION }}"

- name: Package into a versioned zip
run: |
for app in build/macos/*.app; do
if [ -d "$app" ]; then
ditto -c -k --sequesterRsrc --keepParent "$app" "intervalssync-${{ github.ref_name }}-macos.zip"
exit 0
fi
done
echo "No macOS .app bundle found in build/macos" >&2
exit 1

- uses: actions/upload-artifact@v4
with:
name: macos
path: "intervalssync-${{ github.ref_name }}-macos.zip"

release:
needs: [windows, android]
needs: [windows, android, macos]
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: dist

# Create (or update) the Release for this tag, attach both files, and
# Create (or update) the Release for this tag, attach all files, and
# generate the notes a single time (avoids the duplicate notes you get
# when each build job generates them).
#
Expand Down
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<p align="center">
<a href="LICENSE"><img src="https://img.shields.io/github/license/jorge-huxley/intervalssync?style=flat" alt="License: MIT" /></a>
<a href="https://github.com/jorge-huxley/intervalssync/releases"><img src="https://img.shields.io/github/v/release/jorge-huxley/intervalssync?style=flat&sort=semver" alt="GitHub release" /></a>
<a href="https://github.com/jorge-huxley/intervalssync/releases"><img src="https://img.shields.io/badge/platform-Windows%20%7C%20Android-lightgrey?style=flat" alt="Platforms" /></a>
<a href="https://github.com/jorge-huxley/intervalssync/releases"><img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Android-lightgrey?style=flat" alt="Platforms" /></a>
<a href="https://github.com/jorge-huxley/intervalssync/stargazers"><img src="https://img.shields.io/github/stars/jorge-huxley/intervalssync?style=flat&label=stars" alt="GitHub stars" /></a>

</p>
Expand All @@ -24,7 +24,7 @@
Enter your credentials once, press <strong>Sync</strong>, and your latest rides from
<strong>iGPSPORT</strong> or <strong>Bryton Active</strong> land on <strong>intervals.icu</strong>. You can also push
planned workouts from intervals.icu back to iGPSPORT or Bryton Active.
Free and open source, for <strong>Windows</strong> and <strong>Android</strong>.
Free and open source, for <strong>Windows</strong>, <strong>macOS</strong>, and <strong>Android</strong>.
</p>

<p align="center">
Expand Down Expand Up @@ -61,7 +61,7 @@
- **Workout upload window** in Settings — how many calendar days to upload (default: today only)
- **Sets the intervals.icu sport type** after upload (e.g. Mountain Bike Ride / Gravel Ride) — iGPSPORT exports everything as a generic "Ride"
- Optionally deletes the local `.fit` files after a successful upload
- Stores your credentials in the **OS secure vault** (Windows Credential Manager / Android Keystore), never in a file
- Stores your credentials in the **OS secure vault** (Windows Credential Manager / macOS Keychain / Android Keystore), never in a file
- Lets you know when a newer version is available
- **Sync zones to iGPSPORT** — push FTP, LTHR, max HR, and power/HR zones from intervals.icu into your iGPSPORT profile (Settings → iGPSPORT profile, or `intervalssync sync-zones`; the app prompts on launch when thresholds differ)
- **Headless CLI** — activity sync, workout upload, and iGPSPORT zone/threshold sync from the terminal, with JSON output and exit codes for automation and AI agents (see [CLI & automation](#cli--automation-ai-agents))
Expand All @@ -82,6 +82,16 @@ Your password and API key are stored in your operating system's **secure
credential store** — Windows Credential Manager on Windows (the same vault
Windows uses for its own logins) — never in a plain text file.

## Download & run (macOS)

1. Go to the [Releases](../../releases) page and download the latest `macos.zip`.
2. Unzip it and move the app to **Applications** if you want.
3. Open the app, fill in **Settings** (same fields as above), then **Sync** or **Upload to iGPSPORT** / **Upload to Bryton**.

On macOS your credentials are stored in Keychain. Release builds are not
notarized yet, so macOS may require right-clicking the app and choosing
**Open** the first time.

## Download & run (Android)

1. On the [Releases](../../releases) page, download the latest `.apk`.
Expand All @@ -106,14 +116,15 @@ cp .env.example .env # optional: credentials for CLI; IGPSYNC_DROPBOX_APP_KEY
uv run --env-file .env intervalssync-gui
```

## Build the Windows executable
## Build the desktop apps

```bash
uv run flet build windows
uv run flet build macos
```

The distributable lands in `build/windows/`. (Flet downloads the Flutter
toolchain on the first build.)
The distributables land in `build/windows/` and `build/macos/`. (Flet downloads
the Flutter toolchain on the first build; macOS builds require a macOS host.)

## Roadmap

Expand Down
Loading