Files
kegel/README.md
marcuspaico de0ad23f16
Some checks failed
Build & Release APK / build (push) Failing after 55m38s
docs: MIT license, open-source README
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WontRuPqKcod9XK4ZN9MXv
2026-09-07 17:17:09 +10:00

90 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Kegel — "Him: Kegel Exercises for Men"
Free, open-source pelvic floor trainer. A local-only take on what Stamina was
before it went paid: no account, no ads, no analytics, no network. Expo /
React Native, Android + iOS.
- **App Store**: https://apps.apple.com/app/id6809350427 (once approved)
- **Android APK**: releases on this repo, installable via Obtainium
- **Google Play**: coming
- **Privacy policy**: https://rehbock.xyz/kegel/privacy.html
- **License**: MIT — see `LICENSE`. Fork it, ship your own, no strings.
## How it works
A session is four guided blocks driven by a step timer with haptic cues:
1. **Holds** — 8 × squeeze-and-hold. This is the progressive-overload driver:
holds start at 5s and grow **+1s every 3 completed sessions** (capped at
30s). Manual ±1s adjustment in Settings.
2. **Pushes** — 5 × reverse kegel (gently bear down). Scales at half the rate
of holds, capped at 12s.
3. **Quick squeezes** — 10 × 1s burst contractions with 1s release.
4. **Quick pushes** — 10 × 1s burst pushes with 1s release.
Progress (session count, difficulty adjustment, completion history) lives in
AsyncStorage — no server, no account. The home screen shows your **day streak**
(alive until a full day is missed), best streak, and a two-week activity strip.
## Layout
- `src/app/` — expo-router screens: `index` (home), `session` (timer), `settings`
- `src/lib/workout.ts` — pure session-plan + progression logic
- `src/lib/streak.ts` — pure streak / calendar-day logic (tested)
- `src/lib/store.ts` — tiny local store persisted to AsyncStorage
- `android/` — committed prebuild output; CI builds it directly
## Development
```sh
npm install
npm start # Expo dev server
npm run typecheck
npm test # node --test over src/lib/*.test.ts
```
## Contributing
Issues and PRs welcome. Keep the app offline-only and dependency-light; the
whole point is that it never phones home. Run `npm run typecheck && npm test`
before opening a PR.
## Release
### Android APK (Gitea / Obtainium)
Push to `main` → Gitea Actions builds a signed APK and publishes a Gitea
release — install via Obtainium. `android/app/build.gradle` keeps literal
`versionCode`/`versionName`; CI stamps the run number in with `sed` before
building. Keystore: `~/.android-keys/kegel-release.jks` (repo secrets
`KEYSTORE_B64`, `KEYSTORE_PASSWORD`; alias `kegel`). Beware: `expo prebuild -p android`
(used to regenerate launcher icons from `store/icons/make.js`) rewrites
`build.gradle` and drops the release `signingConfigs` block — restore it from git.
### App Store / Google Play (EAS)
Only the maintainer can publish to the stores; `eas.json` references an App
Store Connect API key by key ID / issuer ID, which are identifiers, not
secrets — the `.p8` private key is never committed. Store builds run on EAS (project `@mrmen23/kegel`, profile `production`,
version source remote with auto-increment). The EAS-managed Android keystore
differs from the Gitea one, so Play and Obtainium installs can't update over
each other.
```sh
# Apple: needs an App Store Connect API key for non-interactive auth
export EXPO_ASC_API_KEY_PATH=~/Downloads/AuthKey_L9Z6F5H5B7.p8 EXPO_ASC_KEY_ID=L9Z6F5H5B7 \
EXPO_ASC_ISSUER_ID=<issuer uuid> EXPO_APPLE_TEAM_ID=HZ6XCKM95R EXPO_APPLE_TEAM_TYPE=INDIVIDUAL
eas build -p ios --profile production --non-interactive
eas submit -p ios --profile production --latest --non-interactive # creates the ASC record on first run
# Android: needs a Play service-account JSON with release access
eas build -p android --profile production --non-interactive
eas submit -p android --profile production --latest --key <service-account.json> --track internal
```
Listing copy, keyword rationale and screenshot generation live in `store/`
(`node store/screenshots/make.js` renders `store/screenshots/raw/*.png` into
store-sized slides). Privacy policy is served from
https://rehbock.xyz/kegel/privacy.html (source in `store/web/`). iOS dev runs
via `npx expo run:ios` from a Mac.