docs: redesign do README (padrão TwitterBR-MOD) — dados atualizados
This commit is contained in:
1 parent
8bce19c448
commit
98b09bad06
1 file changed
+109
-46
@@ -1,84 +1,147 @@
|
|||||||
# FightRateRN
|
<div align="center">
|
||||||
|
|
||||||
React Native Community CLI rebuild of FightRate. This app is **bare React Native only** and does not use Expo.
|
<img src="src/assets/fightrate-logo.png" width="110" alt="FightRate logo">
|
||||||
|
|
||||||
## Visual source of truth
|
# FightRate (HealthTracking)
|
||||||
|
|
||||||
The app follows the selected FightRate direction:
|
**Continuous heart-rate capture for combat-sport training from a BLE chest strap — a bare React Native
|
||||||
|
app (no Expo) with a native Android foreground service, local SQLite storage and metrics computed only from
|
||||||
|
real timestamped BPM.**
|
||||||
|
|
||||||
- `../FIGHTRATE_DESIGN_SYSTEM.md`
|

|
||||||
- Direction: `01 — Corner Instrument`
|

|
||||||
|

|
||||||
|
|
||||||
Do not reuse the deprecated Combat Lab/card-heavy direction.
|
[Features](#features) · [How it works](#how-it-works) · [Run locally](#run-locally) · [Known limitations](#known-limitations)
|
||||||
|
|
||||||
## Current slice
|
</div>
|
||||||
|
|
||||||
Implemented in this first slice:
|
> [!NOTE]
|
||||||
|
> **Project status:** work in progress (`package.json` is `0.0.1`, Android `versionName` `1.0`). The
|
||||||
|
> `applicationId` is `com.healthtracking.fightrate`. The latest commits (2026-06-16) ship the
|
||||||
|
> "Instrumento Forte" UI refinement (v2): tabular JetBrains Mono numerics, animated live indicators and
|
||||||
|
> a zoomable chart. The record in [`.impeccable.md`](.impeccable.md) lists `npm run typecheck` with 0
|
||||||
|
> errors and `npm test -- --runInBand` with 74/74 passing for that release.
|
||||||
|
|
||||||
- Corner Instrument app shell.
|
> [!IMPORTANT]
|
||||||
- Continuous capture-first home screen.
|
> **Real data only, Android only.** Every number on screen is computed from BPM samples received from a
|
||||||
- History, Sensor, and Insights screens.
|
> real sensor; with no samples the app shows an empty state instead of inventing a peak, zone, load or
|
||||||
- Centralized design tokens in `src/theme`.
|
> HRV. The BLE capture module is written in Kotlin (`android/…/capture/`); the `ios/` project has no
|
||||||
- Reusable UI components in `src/components`.
|
> native capture module.
|
||||||
- No Expo dependencies.
|
|
||||||
- Android `applicationId` aligned to `com.healthtracking.fightrate`.
|
|
||||||
|
|
||||||
Not implemented yet:
|
## Features
|
||||||
|
|
||||||
- Real BLE Magene H003 integration.
|
| Tab | What it does |
|
||||||
- SQLite/local persistence.
|
|---|---|
|
||||||
- Real timestamped workout chart data.
|
| **Capture** | Live BPM, average / peak / sample-count tiles, BLE, battery and background status, and the training chart. Start/stop marks a **training window** inside the continuous stream — monitoring keeps storing samples either way |
|
||||||
- Navigation library.
|
| **History** | Saved training windows and continuous-usage blocks (split by gaps), each with average / peak / min BPM; open one to inspect the timestamped data; custom time range |
|
||||||
|
| **Sensor** | BLE scan, device list, connect, connection phase, signal (RSSI), battery level, BLE services/characteristics diagnostics and a shortcut to Android battery-optimization settings |
|
||||||
|
| **Insights** | Calculation matrix: current/average BPM, range, variability, time in zones, load, heart-rate drift, post-session recovery, HRmax/HRR (marked as needing a profile) and HRV (only when the strap sends RR intervals) |
|
||||||
|
|
||||||
## Commands
|
- **Zoomable chart** (`TrainingChart`): pinch zoom, pan and a tap-to-pin marker, with tick granularity that
|
||||||
|
follows the visible span (half-second up to one-minute steps).
|
||||||
|
- **Zones** by fixed BPM thresholds: `BASE <150`, `PRESSÃO 150–169`, `REDLINE 170+`.
|
||||||
|
- Samples outside 30–240 bpm, or reported without skin contact, are discarded from metrics; a sample is
|
||||||
|
considered fresh for 12 s.
|
||||||
|
- UI copy is PT-BR; code identifiers are English.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> **Grant the permissions and exempt the app from battery optimization.** The manifest requests Bluetooth
|
||||||
|
> scan/connect, fine location, notifications and a foreground service of type `connectedDevice`. Capture
|
||||||
|
> runs in that service; the **Bateria** button on the Sensor tab opens Android's battery-optimization
|
||||||
|
> settings (`REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` is declared) so the background capture isn't
|
||||||
|
> throttled.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A["Chest strap (BLE)<br/>Heart Rate 0x180D · 2A37"] --> B["FightRateCaptureService<br/>Kotlin foreground service"]
|
||||||
|
B --> C["FightRateCaptureStore<br/>SQLite"]
|
||||||
|
B --> D["FightRateCaptureModule<br/>native module · events"]
|
||||||
|
D --> E["useHeartRateMonitor<br/>React hook"]
|
||||||
|
C -. "samples / sessions" .-> D
|
||||||
|
E --> F["trainingMetrics · continuousUsage<br/>chartViewport"]
|
||||||
|
F --> G["Capture · History · Sensor · Insights"]
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Technical details</summary>
|
||||||
|
|
||||||
|
| Piece | Where | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| BLE client | `FightRateCaptureService.kt` | Scans, connects by known device id, enables notifications on Heart Rate Measurement `2A37` (CCCD `2902`), reads Battery Level `2A19` from service `180F`, reads RSSI |
|
||||||
|
| Reconnect | same file | `START_STICKY` service; automatic reconnect with backoff 2 s → 5 s → 10 s → 30 s unless stopped manually; restores the last device after a restart; after 12 s without a valid sample it reports the stale state and waits for new real data |
|
||||||
|
| Parser | `HeartRateMeasurementParser.kt`, `src/ble/heartRateParser.ts` | Flags: UInt8/UInt16 BPM, contact detection, RR intervals (converted from 1/1024 s to ms) |
|
||||||
|
| Storage | `FightRateCaptureStore.kt` | `fightrate_rn_capture.db` (version 2): `workout_sessions` (training windows with device id/name), `continuous_heart_rate_samples` (timestamp, BPM, contact, RR intervals, device) and the legacy `heart_rate_samples`, migrated on upgrade |
|
||||||
|
| Bridge | `FightRateCaptureModule.kt`, `src/native/FightRateCaptureNative.ts` | Start/stop monitoring and capture window, connect, snapshot, session and continuous samples, battery-optimization settings; service broadcasts become JS events |
|
||||||
|
| Domain (pure TS) | `src/training/` | Live metrics, variability, drift, recovery, zones, insight dashboard, continuous-usage blocks (gap of 5 min starts a new block), chart viewport math |
|
||||||
|
| UI | `src/screens/`, `src/components/`, `src/theme/` | Tab shell in `src/app/FightRateApp.tsx` (state-driven; no navigation library), Reanimated 4 + Worklets animations, design tokens |
|
||||||
|
|
||||||
|
Design references: [`FIGHTRATE_DESIGN_SYSTEM.md`](FIGHTRATE_DESIGN_SYSTEM.md) (direction **01 — Corner
|
||||||
|
Instrument**, the official one) and, for history only,
|
||||||
|
[`FIGHTRATE_COMBAT_LAB_DESIGN_SYSTEM.md`](FIGHTRATE_COMBAT_LAB_DESIGN_SYSTEM.md) (deprecated direction — do
|
||||||
|
not reuse). Specs and plans live in [`docs/superpowers/`](docs/superpowers).
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Known limitations
|
||||||
|
|
||||||
|
- **Android only:** capture exists only in the Kotlin native module; there is no equivalent on iOS.
|
||||||
|
- **No athlete profile yet:** zones use the fixed BPM thresholds above; `%HRmax` zones, Karvonen and full TRIMP
|
||||||
|
are shown as requiring a profile — the app doesn't invent HRmax or resting heart rate.
|
||||||
|
- **HRV needs RR intervals:** without them the dashboard says so instead of estimating.
|
||||||
|
- **No navigation library:** tabs are driven by component state.
|
||||||
|
- **Release signing:** the `release` build type is configured with the **debug keystore**
|
||||||
|
(`android/app/build.gradle`); generate your own keystore before distributing.
|
||||||
|
- **Lint:** at the last record in [`.impeccable.md`](.impeccable.md), `npm run lint` fails on a pre-existing
|
||||||
|
`jest/globals` configuration error (not blocking typecheck or tests).
|
||||||
|
|
||||||
|
## Run locally
|
||||||
|
|
||||||
|
Requirements: Node ≥ 22.11 (`engines` in `package.json`), the Android SDK and a JDK. The project doesn't use Expo.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
git clone https://git.evandro.dev.br/evandro/HealthTracking.git
|
||||||
|
cd HealthTracking
|
||||||
npm install
|
npm install
|
||||||
npm run typecheck
|
npm run typecheck
|
||||||
npm run lint
|
|
||||||
npm test -- --runInBand
|
npm test -- --runInBand
|
||||||
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
Run Metro:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start
|
npm run start # Metro
|
||||||
|
npm run android # run on a device/emulator
|
||||||
```
|
```
|
||||||
|
|
||||||
Run Android on a device/emulator:
|
Debug APK:
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run android
|
|
||||||
```
|
|
||||||
|
|
||||||
Build Android debug APK:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd android
|
cd android
|
||||||
./gradlew assembleDebug
|
./gradlew assembleDebug
|
||||||
|
# output: android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
```
|
```
|
||||||
|
|
||||||
If Gradle reports `No Java compiler found`, point `JAVA_HOME` to Android Studio JBR:
|
If Gradle reports `No Java compiler found`, point `JAVA_HOME` to the JBR bundled with Android Studio:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export JAVA_HOME="/c/Users/Evandro/AppData/Local/Programs/Android Studio/jbr"
|
export JAVA_HOME="<Android Studio install dir>/jbr"
|
||||||
export PATH="$JAVA_HOME/bin:$PATH"
|
export PATH="$JAVA_HOME/bin:$PATH"
|
||||||
cd android
|
|
||||||
./gradlew assembleDebug
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If React Native autolinking keeps a stale package after renaming Android package paths,
|
If React Native autolinking keeps a stale package after renaming Android package paths, clean the generated
|
||||||
clean generated Gradle caches before rebuilding:
|
Gradle caches before rebuilding:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ..
|
|
||||||
rm -rf android/.gradle android/app/build android/build .gradle
|
rm -rf android/.gradle android/app/build android/build .gradle
|
||||||
cd android
|
cd android && ./gradlew assembleDebug
|
||||||
./gradlew assembleDebug
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Debug APK output:
|
## Notices
|
||||||
|
|
||||||
```text
|
- The literature notes in [`docs/data/pesquisa.md`](docs/data/pesquisa.md) state that population tables and
|
||||||
android/app/build/outputs/apk/debug/app-debug.apk
|
formula-based estimates are not a substitute for measured testing.
|
||||||
```
|
- Built on [React Native](https://reactnative.dev/), [Reanimated](https://docs.swmansion.com/react-native-reanimated/),
|
||||||
|
[Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler/),
|
||||||
|
[react-native-svg](https://github.com/software-mansion/react-native-svg),
|
||||||
|
[Lucide](https://lucide.dev/) icons and [JetBrains Mono](https://www.jetbrains.com/lp/mono/).
|
||||||
Reference in new issue
Block a user