Files
kegel/README.md
marcuspaico 55999b7458
Some checks failed
Build & Release APK / build (push) Has been cancelled
feat: store release setup — EAS config, listing copy, screenshots, new icon
- eas.json production/simulator profiles; iOS plist flags; EAS project linked
- literal versionCode/versionName in build.gradle so EAS can parse it; Gitea CI
  stamps the run number with sed instead of env-driven gradle expressions
- store/: listing copy + keyword rationale, screenshot composer (headless
  Chrome), raw simulator captures, rendered App Store / Play slides, feature
  graphic, privacy policy source, icon generator
- replace Expo placeholder icon with the session-ring mark; regenerate Android
  launcher/splash res and theme colours

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WontRuPqKcod9XK4ZN9MXv
2026-09-07 16:10:27 +10:00

75 lines
3.2 KiB
Markdown
Raw 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
Pelvic floor trainer for sexual performance — a free, local-only take on what
Stamina was before it went paid. Expo / React Native, Android + iOS.
## 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
```
## 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)
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.