Initial commit
Generated by create-expo-app 4.0.0.
This commit is contained in:
commit
f66034136d
19 changed files with 7409 additions and 0 deletions
5
.claude/settings.json
Normal file
5
.claude/settings.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"enabledPlugins": {
|
||||||
|
"expo@claude-plugins-official": true
|
||||||
|
}
|
||||||
|
}
|
||||||
41
.gitignore
vendored
Normal file
41
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Expo
|
||||||
|
.expo/
|
||||||
|
dist/
|
||||||
|
web-build/
|
||||||
|
expo-env.d.ts
|
||||||
|
|
||||||
|
# Native
|
||||||
|
.kotlin/
|
||||||
|
*.orig.*
|
||||||
|
*.jks
|
||||||
|
*.p8
|
||||||
|
*.p12
|
||||||
|
*.key
|
||||||
|
*.mobileprovision
|
||||||
|
|
||||||
|
# Metro
|
||||||
|
.metro-health-check*
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.*
|
||||||
|
yarn-debug.*
|
||||||
|
yarn-error.*
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# generated native folders
|
||||||
|
/ios
|
||||||
|
/android
|
||||||
3
AGENTS.md
Normal file
3
AGENTS.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Expo HAS CHANGED
|
||||||
|
|
||||||
|
Read the exact versioned docs at https://docs.expo.dev/versions/v56.0.0/ before writing any code.
|
||||||
20
App.tsx
Normal file
20
App.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { StatusBar } from 'expo-status-bar';
|
||||||
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text>Open up App.tsx to start working on your app!</Text>
|
||||||
|
<StatusBar style="auto" />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
1
CLAUDE.md
Normal file
1
CLAUDE.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
@AGENTS.md
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
25
app.json
Normal file
25
app.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "weegschaal-app",
|
||||||
|
"slug": "weegschaal-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/icon.png",
|
||||||
|
"userInterfaceStyle": "light",
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"backgroundColor": "#E6F4FE",
|
||||||
|
"foregroundImage": "./assets/android-icon-foreground.png",
|
||||||
|
"backgroundImage": "./assets/android-icon-background.png",
|
||||||
|
"monochromeImage": "./assets/android-icon-monochrome.png"
|
||||||
|
},
|
||||||
|
"predictiveBackGestureEnabled": false
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"favicon": "./assets/favicon.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/android-icon-background.png
Normal file
BIN
assets/android-icon-background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/android-icon-foreground.png
Normal file
BIN
assets/android-icon-foreground.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
BIN
assets/android-icon-monochrome.png
Normal file
BIN
assets/android-icon-monochrome.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4 KiB |
BIN
assets/favicon.png
Normal file
BIN
assets/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/icon.png
Normal file
BIN
assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 384 KiB |
BIN
assets/splash-icon.png
Normal file
BIN
assets/splash-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
1186
docs/superpowers/plans/2026-06-27-weegschaal-app-implementation.md
Normal file
1186
docs/superpowers/plans/2026-06-27-weegschaal-app-implementation.md
Normal file
File diff suppressed because it is too large
Load diff
88
docs/superpowers/specs/2026-06-27-weegschaal-app-design.md
Normal file
88
docs/superpowers/specs/2026-06-27-weegschaal-app-design.md
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Weegschaal App — Design Doc
|
||||||
|
|
||||||
|
## Overzicht
|
||||||
|
|
||||||
|
React Native app voor het handmatig invoeren en opslaan van metingen van een slimme weegschaal. Data wordt lokaal opgeslagen in SQLite en gesynchroniseerd met Nextcloud via WebDAV.
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type Measurement = {
|
||||||
|
id: string // UUID v4
|
||||||
|
weight: number // kg
|
||||||
|
bmi: number
|
||||||
|
bodyFatPercentage: number
|
||||||
|
fatMass: number
|
||||||
|
musclePercentage: number
|
||||||
|
muscleMass: number
|
||||||
|
visceralFat: number // index
|
||||||
|
bmr: number // kcal (stofwisseling in rust)
|
||||||
|
measuredAt: string // ISO 8601 datum/tijd
|
||||||
|
createdAt: string
|
||||||
|
updatedAt: string
|
||||||
|
syncStatus: 'local' | 'synced'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Technische Stack
|
||||||
|
|
||||||
|
| Laag | Keuze |
|
||||||
|
|---|---|
|
||||||
|
| Framework | Expo (managed workflow) |
|
||||||
|
| Lokale opslag | expo-sqlite |
|
||||||
|
| Navigatie | @react-navigation/native-stack |
|
||||||
|
| Grafiek | react-native-chart-kit |
|
||||||
|
| Sync | Eigen laag via fetch() naar Nextcloud WebDAV |
|
||||||
|
|
||||||
|
## Schermen
|
||||||
|
|
||||||
|
1. **Dashboard** — Toont de laatste meting en een lijn grafiek van het gewicht over de laatste 30 dagen.
|
||||||
|
2. **Nieuwe meting** — Formulier met genummerde invoervelden voor alle meetwaarden. Datum/tijd wordt automatisch ingevuld maar is aanpasbaar.
|
||||||
|
3. **Historie** — FlatList van alle metingen gesorteerd op `measuredAt` (nieuwste eerst).
|
||||||
|
4. **Instellingen** — WebDAV URL, gebruikersnaam, wachtwoord (opgeslagen in SecureStore), handmatige sync-knop.
|
||||||
|
|
||||||
|
## Component Structuur
|
||||||
|
|
||||||
|
```
|
||||||
|
App
|
||||||
|
├── NavigationContainer
|
||||||
|
│ ├── DashboardScreen
|
||||||
|
│ │ ├── LatestMeasurementCard
|
||||||
|
│ │ └── WeightChart
|
||||||
|
│ ├── NewMeasurementScreen
|
||||||
|
│ │ └── MeasurementForm
|
||||||
|
│ ├── HistoryScreen
|
||||||
|
│ │ └── MeasurementList → MeasurementRow
|
||||||
|
│ └── SettingsScreen
|
||||||
|
│ └── WebDAVConfigForm
|
||||||
|
├── database/
|
||||||
|
│ └── db.ts — SQLite initialisatie, CRUD operaties
|
||||||
|
├── sync/
|
||||||
|
│ └── syncService.ts — WebDAV upload/download/merge
|
||||||
|
├── types.ts — TypeScript types
|
||||||
|
└── utils/
|
||||||
|
└── uuid.ts — UUID generatie
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sync Strategie
|
||||||
|
|
||||||
|
- **Opslag op WebDAV:** Enkel JSON-bestand op `weegschaal/measurements.json`
|
||||||
|
- **Bij app start:**
|
||||||
|
1. Download measurements.json van WebDAV
|
||||||
|
2. Merge met lokale SQLite: per meting de versie met laatste `updatedAt` behouden
|
||||||
|
3. Lokale database bijwerken
|
||||||
|
- **Na een nieuwe meting:**
|
||||||
|
1. Opslaan in SQLite met `syncStatus: 'local'`
|
||||||
|
2. Direct uploaden naar WebDAV
|
||||||
|
- **Handmatige sync:** Volledige merge + upload
|
||||||
|
|
||||||
|
## Foutafhandeling
|
||||||
|
|
||||||
|
- Geen netwerk → meting wordt lokaal opgeslagen met `syncStatus: 'local'`
|
||||||
|
- Conflict → last-write-wins op `updatedAt`
|
||||||
|
- WebDAV credentials fout → melding in Settings tonen
|
||||||
|
|
||||||
|
## Testen
|
||||||
|
|
||||||
|
- Jest voor unit tests (database, sync merge logica)
|
||||||
|
- Geen E2E in eerste versie
|
||||||
8
index.ts
Normal file
8
index.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { registerRootComponent } from 'expo';
|
||||||
|
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||||
|
// It also ensures that whether you load the app in Expo Go or in a native build,
|
||||||
|
// the environment is set up appropriately
|
||||||
|
registerRootComponent(App);
|
||||||
5983
package-lock.json
generated
Normal file
5983
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
22
package.json
Normal file
22
package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "weegschaal-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.ts",
|
||||||
|
"dependencies": {
|
||||||
|
"expo": "~56.0.12",
|
||||||
|
"expo-status-bar": "~56.0.4",
|
||||||
|
"react": "19.2.3",
|
||||||
|
"react-native": "0.85.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "~19.2.2",
|
||||||
|
"typescript": "~6.0.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
6
tsconfig.json
Normal file
6
tsconfig.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "expo/tsconfig.base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue