Planungen android
All checks were successful
Deploy to production / deploy (push) Successful in 2m17s

This commit is contained in:
Torsten Schulz (local)
2026-07-08 22:28:51 +02:00
parent f5b3f174e6
commit 53becb6630
90 changed files with 5901 additions and 42 deletions

9
android/.idea/android.iml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

1965
android/.idea/caches/deviceStreaming.xml generated Normal file

File diff suppressed because it is too large Load Diff

13
android/.idea/deviceManager.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

8
android/.idea/markdown.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownSettings">
<option name="previewPanelProviderInfo">
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
</option>
</component>
</project>

5
android/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<project version="4">
<component name="ProjectRootManager" version="2">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
android/.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/android.iml" filepath="$PROJECT_DIR$/.idea/android.iml" />
</modules>
</component>
</project>

6
android/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

605
android/ANDROID_APP_PLAN.md Normal file
View File

@@ -0,0 +1,605 @@
# Android-App-Plan fuer YourPart3
Stand: 2026-07-08
## Ziel
Dieses Dokument plant eine Android-App fuer das bestehende YourPart3-Projekt unter `/android`.
Das Projekt besteht aktuell aus:
- `frontend`: Vue 3, Vite, Vuetify, Vue Router, Vuex, Axios, Socket.IO Client, Three.js
- `backend`: Node.js/Express 5, Sequelize, Redis-Sessiondaten, OAuth/OIDC, Socket.IO, REST-APIs
- Authentifizierung: Login liefert einen User mit `id`/`authCode`; API-Requests senden Header `userid` und `authcode`
- Realtime: Socket.IO fuer Backend-Events und separater Daemon-WebSocket fuer Falukant-Updates
- Deployment: Backend serviert die gebaute SPA aus `frontend/dist`
Backend-Implementierung ist nicht Teil dieses Android-Starts. Das vorhandene Backend wird als gegeben betrachtet; Android-seitig werden nur Kompatibilitaet, URLs, Auth-Header, OAuth-Weiterleitung und Realtime-Verbindungen getestet.
## Empfehlung
Die Android-App sollte in Phase 1 als Capacitor-App umgesetzt werden, nicht als nativer Rewrite.
Begruendung:
- Die bestehende App ist bereits eine grosse SPA mit vielen Views: Social Network, Falukant, Vokabeltrainer, Minigames, Kalender, Admin, Settings.
- Der Auth-Mechanismus und die vorhandenen API-Clients sind Web-orientiert und koennen in einer WebView nahezu unveraendert weiterlaufen.
- OAuth-Callback-Routen existieren bereits im Frontend (`/auth/oauth/callback`, `/auth/oauth/user/callback`).
- Socket.IO und WebSocket-Verbindungen funktionieren in Capacitor deutlich schneller als in einem nativen Rewrite.
- Ein nativer Rewrite wuerde zuerst API-Vertraege, Sessionmodell, Navigation, Offline-Strategie und UI-Komponenten neu definieren muessen.
Zielarchitektur Phase 1:
```text
/android
capacitor.config.ts
package.json
android/
Android-native Projektdateien, durch Capacitor generiert
/frontend
bestehende Vue/Vite-App
/backend
bestehende Express/API/Socket.IO-App
```
Capacitor verwendet den bestehenden `frontend`-Build als Web-Bundle und erzeugt daraus eine installierbare Android-App.
## Nicht-Ziele fuer Phase 1
- Kein kompletter nativer Kotlin/Jetpack-Compose-Rewrite.
- Keine Offline-First-Synchronisation fuer Falukant/Social/Vocab.
- Keine komplette Neugestaltung aller mobilen Screens.
- Keine API-Versionierung fuer mobile Clients, solange die App nur das bestehende Web-Frontend verpackt.
- Keine Play-Store-Verteilung vor Datenschutz-, Content- und OAuth-Pruefung.
- Keine Backend-Neuentwicklung und keine Backend-API-Neuplanung.
## Getroffene Entscheidungen
### App-Technologie
- Entscheidung: Capacitor mit lokal gebuendelter Vue/Vite-App.
- Kein nativer Kotlin-Rewrite in Phase 1.
- Kein reiner Remote-WebView-Wrapper auf `https://www.your-part.de`.
- Begruendung: Der vorhandene Funktionsumfang ist breit, Web-Auth und Socket.IO existieren bereits, und Capacitor ermoeglicht spaetere native Erweiterungen ohne sofortigen Rewrite.
### App-ID und Name
- App-ID: `de.yourpart.app`
- Launcher-Name: `YourPart`
- Android-Projektpfad: `/android`
- Capacitor `webDir`: `../frontend/dist`
### Ziel-Distribution
- Phase 1: interne Debug-/Test-APK.
- Phase 2: signiertes internes AAB/APK fuer Testgeraete.
- Play Store erst nach separatem Compliance-Check fuer Datenschutz, UGC, Moderation und Adult Content.
### Backend-Abgrenzung
- Backend bleibt unveraendert.
- Android nutzt die bestehenden REST-Endpunkte, Auth-Header, OAuth-Routen, Socket.IO-Events und Daemon-WebSocket-Events.
- Backendbezogene TODOs sind nur Test- und Konfigurationschecks. Falls ein Test scheitert, wird der konkrete Anpassungsbedarf danach separat entschieden.
### Admin-Bereich
- Admin-Routen bleiben in Phase 1 nicht priorisiert.
- Wenn Admin-Menues durch bestehende Berechtigungen sichtbar sind, werden sie nicht aktiv entfernt.
- Abnahmekriterien fuer Phase 1 gelten nur fuer normale Nutzerfunktionen.
### Adult-/Erotikbereiche
- Phase 1: vorhandenes Web-Gating bleibt bestehen, keine neue native Adult-Content-Funktion.
- Play-Store-Ziel ist blockiert, bis Altersfreigabe, UGC-Moderation, Melden/Blockieren, Datenschutz und Store-Policy separat geprueft sind.
- Fuer interne APK-Tests darf der Bereich technisch erreichbar bleiben, wenn der bestehende Account-/Altersstatus ihn erlaubt.
### OAuth
- Phase 1 startet mit Username/Passwort-Login als Pflichtfunktion.
- OAuth ist Phase-1-Testumfang, aber kein Blocker fuer das erste Debug-APK.
- Zielrichtung fuer OAuth: externer Browser bzw. System-Browser plus App Links, nicht OAuth in einer versteckten WebView erzwingen.
### Push Notifications
- Push ist nicht Teil des ersten Android-Scaffolds.
- Push wird nach stabiler App-Shell geplant, weil dafuer Device Tokens, Opt-in, Settings und Backend-Zustellung noetig sind.
### 3D / WebGL
- 3D-Charaktere werden im Android-Debug-Build initial per `VITE_DISABLE_3D=true` deaktiviert.
- Begruendung: Die Login-Seite rendert mehrere `Character3D`-Instanzen sofort. In Kombination mit CORS-Fehlern und vielen GLB-Kandidaten kann der Emulator-WebView-Renderer per OOM abstuerzen.
- Reaktivierung erfolgt erst nach erfolgreichem CORS-Test und separatem 3D-Performance-Test.
### Navigation
- Vue `createWebHistory` bleibt initial unveraendert.
- Hash-Routing wird nur eingefuehrt, wenn Capacitor-Tests echte Routing-Probleme zeigen.
- Android Back Button wird als native App-Anforderung in Phase 1 umgesetzt.
- Mobile Navigation bleibt Teil der Web-App, wird aber fuer Android als kompakte Hybrid-Navigation gehaertet: Header-Leiste, aufklappbares scrollbares Menue, keine dauerhaft sichtbare Desktop-Menueflaeche auf kleinen Displays.
### Sichere Speicherung
- Phase 1 darf bestehendes `localStorage`/`sessionStorage` weiterverwenden.
- Vor Play-Store-Release wird Auth-Persistenz auf Secure Storage/Android Keystore umgestellt.
## Technische Ausgangslage
### Frontend
- Zentrale API-Konfiguration: `frontend/src/utils/axios.js`
- API-Basis-URL: `frontend/src/utils/appConfig.js` ueber `VITE_API_BASE_URL`
- Auth-Header: `userid` und `authcode`
- Persistenz: `localStorage` oder `sessionStorage` fuer `isLoggedIn`, `user`, `userid`
- Router: `createWebHistory`, viele Clean-URL-Routen
- Realtime: `socket.io-client` ueber `VITE_SOCKET_IO_URL`
- Daemon-WebSocket: ueber `VITE_DAEMON_SOCKET`
- 3D/Assets: Three.js und Modelle ueber `/api/models` bzw. statische Assets
### Backend
- CORS erlaubt aktuell konfigurierte Origins und lokale Web-Origins.
- Auth-Middleware prueft `userid` und `authcode`.
- OAuth startet serverseitig per Redirect.
- Socket.IO erlaubt aktuell `origin: '*'`.
- Backend serviert SPA-Fallback fuer Nicht-API-Routen.
## Android-Strategie
### Phase 1: Capacitor Shell
Die Android-App laedt nicht die Produktionswebsite remote, sondern nutzt das lokal gebundelte Vite-Build-Artefakt.
Vorteile:
- App startet auch dann, wenn die Website selbst nicht als Web-Seite geladen werden muss.
- Google Play bewertet sie eher als App statt als reinen Browser-Shortcut.
- Versionierbare Builds mit reproduzierbarer Web-Bundle-Version.
- Zugriff auf native Funktionen bleibt moeglich: Splash Screen, Deep Links, Push Notifications, sichere Speicherung.
Wichtige Anpassung:
- `VITE_API_BASE_URL`, `VITE_SOCKET_IO_URL`, `VITE_DAEMON_SOCKET` muessen fuer Android-Builds explizit auf die produktiven HTTPS/WSS-Endpunkte gesetzt werden.
- Relative API-URLs sind in einer gebuendelten Android-WebView riskant, weil `window.location.origin` nicht der Server-Origin ist.
### Phase 2: Mobile Web-Haertung
Die bestehende UI muss fuer kleine Viewports und Touch-Nutzung stabilisiert werden.
Prioritaeten:
- Login/Register/OAuth
- Hauptnavigation
- Falukant-Overview, Branch, Family, Bank
- Vokabeltrainer und Lessons
- Chat/Friends/Forum-Basics
- Minigames nur nach separater Touch-Performance-Pruefung
### Phase 3: Native Integrationen
Nach stabiler Shell koennen echte App-Features ergaenzt werden:
- Push Notifications fuer Chat, Freund-Login, Falukant-Events
- Deep Links fuer OAuth-Callbacks und geteilte Inhalte
- Android Back Button Integration
- Splash Screen und App Icons
- Secure Storage fuer Authdaten
- App Update / Version Check
### Phase 4: Selektiv native Screens
Wenn einzelne Bereiche Performance- oder UX-Probleme haben, koennen sie spaeter nativ ersetzt werden. Kandidaten:
- Login/Onboarding
- Push Notification Center
- Vokabeltrainer Session
- Falukant Status/Quick Actions
## Repository-Layout
Vorgeschlagenes Layout:
```text
android/
ANDROID_APP_PLAN.md
README.md
package.json
capacitor.config.ts
android/ # Capacitor Android-Projekt
scripts/
build-android-web.sh
sync-android.sh
```
Hinweis: In Phase 1 wird `/android/android` generiert, weil `/android` die Capacitor-Projektwurzel ist. Die generierten Android-Dateien werden versioniert, weil reproduzierbare Builds und native Anpassungen wichtig sind.
## Build-Konzept
### Android Web-Build
Ein eigener Build-Modus verhindert Vermischung mit Web-Production:
```bash
cd frontend
npm run build -- --mode android
```
Dafuer wird eine Datei `frontend/.env.android` benoetigt:
```env
VITE_API_BASE_URL=https://www.your-part.de
VITE_SOCKET_IO_URL=https://www.your-part.de
VITE_DAEMON_SOCKET=wss://www.your-part.de
VITE_PUBLIC_BASE_URL=https://www.your-part.de
```
Wichtig: `VITE_API_BASE_URL` ist bewusst nur die Origin ohne `/api`, weil die bestehenden Frontend-Aufrufe bereits Pfade wie `/api/auth/login` enthalten. Mit `/api` in der Base-URL entstehen Android-seitig falsche Requests wie `/api/api/...`.
Die exakten WebSocket-Pfade muessen gegen die produktive Apache-/Backend-Konfiguration verifiziert werden.
### Lokaler Emulator-Stand
Android Studio und mehrere AVDs sind lokal vorhanden. Fuer die ersten Stabilitaetstests ist `trainingstagebuchApi35` die bevorzugte VM, weil sie im bisherigen Test stabiler lief als das Play-Store-Image `Medium_Phone`.
```bash
ANDROID_AVD_HOME=/home/torsten/.config/.android/avd /home/torsten/Android/Sdk/emulator/emulator -avd trainingstagebuchApi35 -no-snapshot-save
adb install -r android/android/app/build/outputs/apk/debug/app-debug.apk
adb shell am start -W -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n de.yourpart.app/.MainActivity
```
Ergebnis bisher:
- Debug-APK wurde erfolgreich gebaut.
- APK wurde auf einem Emulator installiert.
- App startet als `de.yourpart.app/.MainActivity`.
- Login-Screen rendert mobil.
- API-Base-URL wurde von `/api` auf die Origin `https://www.your-part.de` korrigiert, damit keine `/api/api`-Requests entstehen.
- Capacitor `server.hostname` darf nicht auf `www.your-part.de` gesetzt werden, weil sonst echte Backend- und Model-URLs als lokale App-Assets behandelt werden.
- Nach Entfernung der Hostname-Kollision ist die Android-App-Origin `https://localhost`. Das Backend muss diese Origin in `CORS_ORIGINS` erlauben, sonst blockiert die WebView REST- und GLB-Requests.
### Capacitor Sync
Nach dem Frontend-Build:
```bash
cd android
npx cap sync android
```
Danach:
```bash
cd android
npx cap open android
```
Oder per CLI:
```bash
cd android
./gradlew assembleDebug
```
Lokaler Build-Hinweis:
- Auf diesem System liegt das Android SDK unter `/home/torsten/Android/Sdk`.
- Die lokale Datei `/android/android/local.properties` setzt `sdk.dir` darauf und ist absichtlich nicht versioniert.
- Erstes Debug-APK wurde erfolgreich gebaut: `/android/android/app/build/outputs/apk/debug/app-debug.apk`.
## Authentifizierung
### Bestehender Login
Der bestehende Login kann initial unveraendert bleiben:
- `POST /api/auth/login`
- Antwort enthaelt User inkl. `authCode`
- Axios haengt `userid` und `authcode` an Folgerequests
- Storage bleibt vorerst `localStorage`/`sessionStorage`
### Sicherheitsverbesserung
Phase 1 kann noch mit Web Storage starten. Vor Play-Store-Release sollte Auth aber in native sichere Speicherung verschoben werden:
- Capacitor Preferences nur fuer unkritische Werte
- Fuer sensible Werte besser Android Keystore ueber ein Secure-Storage-Plugin
- Migration: Store liest zuerst Secure Storage, fallback auf lokalen Web Storage, migriert dann
### OAuth
OAuth ist der groesste Integrationspunkt.
Kurzfristige Option:
- OAuth im In-App Browser oder externen Browser starten
- Callback bleibt auf `https://www.your-part.de/auth/oauth/callback`
- Die Callback-Seite tauscht `code/state` wie bisher gegen einen App-User
Bessere App-Option:
- Android App Links fuer `https://www.your-part.de/auth/oauth/callback`
- `assetlinks.json` auf der Domain bereitstellen
- Capacitor App Plugin verarbeitet den Deep Link und routet intern weiter
Risiko:
- OAuth Provider koennen eingebettete WebViews einschraenken. Deshalb sollte OAuth nicht in einer versteckten WebView erzwungen werden, sondern ueber Browser/App Links laufen.
## API und CORS
Fuer Capacitor-Bundles ist die Origin nicht immer identisch mit der Website-Origin.
Zu pruefen:
- Welche Origin sendet Android WebView bei Requests an `https://www.your-part.de/api`?
- Muss `CORS_ORIGINS` um `https://localhost` erweitert werden?
- Funktionieren Custom Header `userid` und `authcode` in der WebView?
- Funktionieren Preflight-Requests mit den bestehenden erlaubten Headers?
Noetige Backend-Konfiguration fuer Debug-Builds:
```env
CORS_ORIGINS=https://www.your-part.de,https://localhost,http://localhost:5173,http://127.0.0.1:5173
```
Nur nach Test setzen; nicht blind `CORS_ALLOW_ALL=1` fuer Produktion verwenden.
## Navigation und Deep Links
Die Vue-App nutzt `createWebHistory`. In Capacitor kann das funktionieren, aber folgende Punkte muessen getestet werden:
- Direktstart auf `/`
- Interne Navigation zu `/falukant/home`, `/friends`, `/socialnetwork/vocab/...`
- Android Back Button
- OAuth Callback URL
- App-Resume nach Browser-OAuth
Falls History-Mode Probleme in der WebView macht:
- Option A: Capacitor-spezifisch auf Hash-History wechseln
- Option B: History beibehalten und Deep-Link-Routing sauber behandeln
Hash-History waere technisch einfacher, aber wegen bestehender SEO-/Web-Routen nicht global fuer das Web-Frontend umstellen.
## Realtime
### Socket.IO
Bestehender Ablauf:
- Nach Login `initializeSocket`
- Socket verbindet zu `VITE_SOCKET_IO_URL`
- Client sendet `setUserId` mit `hashedId` oder `id`
Android-Testfaelle:
- Login erzeugt Socket-Verbindung
- App im Hintergrund trennt/reconnectet sauber
- Friend-Login-Events kommen an
- Schlechte Verbindung erzeugt keine Endlos-Fehlerdialoge
### Daemon-WebSocket
Falukant nutzt zusaetzliche Daemon-Events. Android muss mindestens diese Events empfangen koennen:
- `falukantUpdateFamily`
- `falukantUpdateStatus`
- `falukantUpdateProductionCertificate`
- `children_update`
- `falukantUpdateChurch`
- `falukantUpdateDebt`
Test:
- WSS ueber produktiven Proxy
- Reconnect nach App-Resume
- Filterung nach `user_id`
## Mobile UX Prioritaeten
Die App sollte nicht nur ein Desktop-Layout in einer WebView zeigen. Phase 1 braucht mindestens diese UX-Haertung:
- Header/Navigation auf kleinen Viewports pruefen
- Dialoge auf 360px Breite testen
- Tabellen und breite Falukant-Views horizontal oder responsiv absichern
- Touch-Ziele mindestens ca. 44px
- Keyboard-Verhalten im Login/Register testen
- Safe Area Insets fuer Statusbar/Navigationbar beachten
- Android Back Button: Dialog schliessen, sonst Router zurueck, sonst App minimieren
Aktueller Stand 2026-07-08:
- Hauptnavigation ist auf kleinen Viewports zu einer kompakten Menueleiste mit aufklappbarem, scrollbarem Menue umgebaut.
- Header ist auf Smartphone-Breite kompakter, Statusanzeigen laufen zweispaltig statt als lange Desktop-Leiste.
- Footer blendet leere System-/Fensterbereiche auf Smartphone-Breite aus und reserviert Safe-Area-Abstand nach unten.
- App-Shell nutzt `100dvh` als Android-WebView-freundlichere Viewport-Hoehe.
## Datenschutz, Content und Store-Risiken
Das Projekt enthaelt Social-, Chat-, Galerie-, Erotik-/Adult- und Moderationsbereiche. Fuer Play Store sind diese Punkte kritisch:
- Altersfreigabe und Adult-Content-Gating
- UGC-Moderation, Meldefunktion, Blockieren
- Datenschutzrichtlinie in der App und im Store Listing
- Account-Loeschung oder klare Anleitung
- Sichere Uebertragung nur per HTTPS/WSS
- Keine unsicheren Debug-Endpunkte im Release-Build
- Keine Secrets im Android-Bundle
Vor Play-Store-Release muss ein eigener Compliance-Check erfolgen.
## Teststrategie
### Lokale Tests
- Android Emulator mit Debug-Build
- Echtes Android-Geraet im gleichen Netz
- Produktions-API mit Testnutzer
- Offline/Online-Wechsel
- App Kill/Restart/Resume
### Kern-Testmatrix
- Login mit Username/Passwort
- Logout
- Registrierung
- Passwort vergessen
- OAuth Login je Provider, soweit konfiguriert
- Menu-Load nach Login
- Falukant Overview laden
- Falukant Realtime-Update empfangen
- Vokabeltrainer Lesson starten und abschliessen
- Chat verbinden und Nachricht empfangen
- Galerie/Bild-Upload, falls mobil zunaechst erlaubt
- Minigames Touch-Steuerung
- Admin-Bereiche entweder nutzbar oder bewusst ausgeblendet
### Build-Checks
- `npm run build` im Frontend
- Android Web-Build mit `.env.android`
- `npx cap sync android`
- `./gradlew assembleDebug`
- `./gradlew lint`
- Release-Build mit Signing-Konfiguration
## Verbleibende offene Punkte
- Produktivdomain final technisch testen: voraussichtlich `https://www.your-part.de`.
- Daemon-WebSocket-URL und Pfad final gegen Deploy-/Proxy-Konfiguration testen.
- Mindest-Android-Version aus Capacitor-Default uebernehmen und nach erstem Scaffold im Gradle-Projekt dokumentieren.
- Play-Store-Entscheidung bleibt nachgelagert bis Compliance-Pruefung abgeschlossen ist.
## TODO
### 1. Grundsatzentscheidungen
- [x] App-ID festlegen: `de.yourpart.app`.
- [x] App-Name und Launcher-Label festlegen: `YourPart`.
- [x] Ziel-Distribution festlegen: zuerst interne Debug-/Test-APK.
- [x] Entscheiden, ob Admin-Routen in der App sichtbar bleiben: nicht priorisiert, nicht aktiv entfernt.
- [x] Entscheiden, wie Adult-/Erotikbereiche in Android behandelt werden: bestehendes Web-Gating, kein Play Store ohne Compliance-Check.
- [x] Entscheiden, ob Backend Teil des Android-Starts ist: nein, nur Kompatibilitaetstests.
- [x] Entscheiden, ob Push Teil des ersten Scaffolds ist: nein.
- [x] Entscheiden, ob OAuth erster Blocker ist: nein, Username/Passwort-Login zuerst.
### 2. Android-Projekt scaffolden
- [x] In `/android` eigenes `package.json` anlegen.
- [x] Capacitor installieren: `@capacitor/core`, `@capacitor/cli`, `@capacitor/android`.
- [x] `capacitor.config.ts` mit App-ID `de.yourpart.app`, App-Name `YourPart` und `webDir` auf `../frontend/dist` konfigurieren.
- [x] Android-Plattform generieren: `npx cap add android`.
- [x] `/android/README.md` mit Build-Kommandos anlegen.
- [x] Entscheiden, ob generiertes `/android/android` versioniert wird: ja.
### 3. Frontend Android-Build
- [x] `frontend/.env.android.example` anlegen.
- [x] `VITE_API_BASE_URL` fuer Android explizit setzen.
- [x] `VITE_SOCKET_IO_URL` fuer Android explizit setzen.
- [x] `VITE_DAEMON_SOCKET` fuer Android explizit setzen.
- [x] Root- oder Android-Script fuer `build:android:web` ergaenzen.
- [x] Android-Web-Build mit produktiver Origin statt lokaler Dev-URL bauen.
- [ ] Release-Build-Gate ergaenzen, das lokale Dev-URLs automatisiert verhindert.
### 4. Backend-Kompatibilitaet
- [ ] Android-Origin im CORS-Verhalten messen.
- [x] Fehlerhafte Android-Request-Basis `/api/api` identifizieren und durch Origin-only-Config beheben.
- [x] Capacitor-Hostname-Kollision mit Backend-Host vermeiden; `server.hostname` bleibt Default.
- [x] `CORS_ORIGINS` fuer Capacitor als bestehenden Backend-Konfigurationspunkt notieren: `https://localhost`.
- [ ] Produktiv-/Testbackend mit `CORS_ORIGINS` inklusive `https://localhost` neu starten und Android-Requests erneut pruefen.
- [ ] Custom Header `userid`/`authcode` auf Android testen.
- [ ] Socket.IO-Verbindung von Android testen.
- [ ] Daemon-WebSocket ueber Android testen.
- [ ] Produktionsproxy fuer HTTPS/WSS pruefen.
- [ ] Keine Backend-Aenderung ohne konkreten fehlgeschlagenen Android-Test einplanen.
### 5. Auth und OAuth
- [ ] Username/Passwort-Login in Android testen.
- [ ] Persistenz nach App-Neustart testen.
- [ ] Logout inklusive Socket-Cleanup testen.
- [ ] OAuth-Login-Flow je Provider testen.
- [ ] Entscheiden: OAuth per externem Browser plus App Links oder innerhalb bestehender WebView.
- [ ] Android App Links einrichten, falls OAuth nativ zurueck in die App fuehren soll.
- [ ] Authdaten spaeter in Secure Storage migrieren.
### 6. Native App-Verhalten
- [ ] Android Back Button behandeln.
- [ ] Splash Screen konfigurieren.
- [ ] App Icons erzeugen.
- [ ] Statusbar/Safe-Area pruefen; aktueller Test zeigt nicht-blockierende Safe-Area-CSS-Console-Fehler.
- [x] WebView-Textfeld-Eingabe fuer Emulator reparieren: `android.captureInput` nicht aktivieren.
- [x] Android-Studio-Projektpfad dokumentieren: `/android/android`.
- [x] Android-Studio-Run-Configuration `YourPart Debug` anlegen.
- [ ] Deep-Link-Handling vorbereiten.
- [ ] App Resume/Pause Events fuer Socket-Reconnect nutzen.
### 7. Mobile UI-Haertung
- [ ] Login/Register auf 360px Breite testen.
- [x] Login-Screen im Emulator visuell pruefen.
- [x] Parameterlisten-Handling gegen Nicht-Array-Antworten haerten, damit Backend-Fehler keine UI-Exception ausloesen.
- [x] 3D-Modelle fuer Android-Debug per `VITE_DISABLE_3D=true` deaktivieren, damit Login/Onboarding stabil bleibt.
- [x] Hauptnavigation fuer kleine Viewports umbauen: kompakte Menueleiste plus scrollbares Menue statt voller Desktop-Navigation.
- [ ] Hauptnavigation mobil mit mehreren Rollen/Berechtigungssets testen.
- [ ] Dialoge auf kleinen Screens pruefen.
- [ ] Falukant-Views mit breiten Tabellen pruefen.
- [ ] Vokabeltrainer Touch- und Keyboard-Verhalten testen.
- [ ] Minigames separat auf Touch-Performance testen.
- [ ] Bild-/Dateiupload auf Android pruefen.
### 8. Push Notifications
- [ ] Entscheiden, ob Push in Phase 1 oder spaeter kommt.
- [ ] Event-Kandidaten definieren: Chat, Friend Login, Falukant, Vocab Reminder.
- [ ] Backend-Device-Token-Modell planen.
- [ ] FCM-Projekt konfigurieren.
- [ ] Opt-in und Settings-UI planen.
### 9. Store/Compliance
- [ ] Datenschutzseite in App erreichbar machen.
- [ ] Impressum in App erreichbar machen.
- [ ] Account-Loeschung/Anfrageprozess klaeren.
- [ ] Adult Content Policy pruefen.
- [ ] UGC-Moderation fuer Store Review dokumentieren.
- [ ] Release-Build ohne Debug-Konfiguration pruefen.
### 10. CI/CD
- [x] Android-Build-Script anlegen.
- [x] Debug-Build lokal reproduzierbar machen.
- [ ] Release-Signing-Konzept festlegen.
- [ ] Keystore sicher ausserhalb des Repos verwalten.
- [ ] Optional CI-Job fuer `frontend build` + `cap sync` + Gradle Build einrichten.
## Empfohlene erste Umsetzungsschritte
1. `/android` als Capacitor-Projekt initialisieren.
2. `frontend/.env.android.example` und Android-Build-Script anlegen.
3. Debug-APK mit produktiver Test-API bauen.
4. Login, Menu, Falukant Overview und Socket.IO testen.
5. Erst danach OAuth, Deep Links und Push angehen.
## Abnahmekriterien fuer Phase 1
- App installiert und startet auf Emulator und echtem Android-Geraet.
- Login/Logout funktionieren.
- Persistierter Login funktioniert nach App-Neustart.
- API-Requests senden `userid` und `authcode` korrekt.
- Socket.IO verbindet nach Login und reconnectet nach Resume.
- Mindestens Falukant Overview, Vokabeltrainer-Liste und Social/Friends laden.
- Android Back Button fuehrt nicht zu kaputten Zustanden.
- Build ist reproduzierbar dokumentiert.
Aktueller Stand:
- Android/Capacitor-Projekt ist erzeugt.
- Android-Web-Build ist erfolgreich.
- Capacitor Sync ist erfolgreich.
- Debug-APK-Build ist erfolgreich.
- Installation und Laufzeittests auf Emulator/Geraet stehen noch aus.

View File

@@ -0,0 +1,625 @@
# Native Android App Plan fuer YourPart3
Stand: 2026-07-08
## Zielbild
Dieses Dokument plant eine komplette native Android-App fuer YourPart3 als langfristige Ablösung bzw. Ergänzung der aktuellen Capacitor-Hybrid-App.
Ziel ist eine echte Android-App mit:
- Kotlin
- Jetpack Compose
- MVVM bzw. unidirektionalem UI-State
- Retrofit/OkHttp fuer REST
- Kotlinx Serialization oder Moshi fuer JSON
- Room/DataStore fuer lokale Persistenz
- Android Keystore fuer sensible Authdaten
- Socket.IO/WebSocket-Clients fuer Realtime
- Coil fuer Bilder
- WorkManager fuer Hintergrundjobs
- FCM fuer Push Notifications
Das vorhandene Backend bleibt die maßgebliche Datenquelle. Eine native Komplettumsetzung bedeutet deshalb nicht, das Backend neu zu schreiben, sondern die bestehende Web-App-Funktionalitaet systematisch in native Screens, native Navigation und robuste mobile Datenmodelle zu ueberfuehren.
## Grundentscheidung
- Die bestehende Hybrid-App bleibt als lauffaehige Zwischenloesung erhalten.
- Die native App wird parallel aufgebaut.
- Nicht als Big Bang migrieren. Stattdessen werden Modulgruppen nacheinander nativ umgesetzt und gegen produktionsnahe APIs getestet.
- Admin- und Adult-Bereiche werden nicht im ersten nativen MVP umgesetzt.
- Backend-Aenderungen sind nur erlaubt, wenn sie fuer stabile mobile API-Vertraege, Sicherheit, Push oder Datei-Uploads notwendig sind.
## Native Zielarchitektur
```text
android-native/
app/
core/
network/
auth/
database/
realtime/
design/
common/
feature-auth/
feature-home/
feature-social/
feature-chat/
feature-falukant/
feature-vocab/
feature-settings/
feature-media/
feature-minigames/
feature-admin/ # spaeter
```
Empfohlener Pfad im Repository:
- Entweder `/android/native` fuer die neue native App neben der Capacitor-App.
- Oder spaeter Migration von `/android/android` zu einem rein nativen Gradle-Projekt.
Empfehlung: `/android/native`, damit die Hybrid-App weiter testbar bleibt.
## Technische Zielentscheidungen
- Sprache: Kotlin.
- UI: Jetpack Compose, Material 3, eigene YourPart-Design-Tokens.
- Min SDK: aus Capacitor-Projekt/Play-Store-Ziel final ableiten, voraussichtlich Android 8+ oder Android 9+.
- Navigation: Compose Navigation mit typed Routes.
- Dependency Injection: Hilt.
- REST: Retrofit + OkHttp Interceptors.
- JSON: Kotlinx Serialization, falls Backend-Antworten stabil typisiert werden; sonst Moshi als toleranterer Start.
- Lokale Einstellungen: DataStore Preferences.
- Lokale Daten: Room fuer Cache, Entitaeten, Outbox.
- Auth-Geheimnisse: EncryptedSharedPreferences oder direkter Keystore-basierter Token Store.
- Bilder: Coil.
- Datei-Uploads: OkHttp Multipart, Android Photo Picker.
- Realtime: Socket.IO Android Client plus separater OkHttp WebSocket fuer Daemon.
- Push: Firebase Cloud Messaging.
- Tests: JUnit, Turbine, MockWebServer, Compose UI Tests.
## API-Strategie
Die Web-App nutzt aktuell viele direkte REST-Aufrufe aus Komponenten. Fuer native Android muss daraus ein klarer API-Client entstehen.
Native API-Schichten:
- `AuthApi`
- `SettingsApi`
- `MenuApi`
- `SocialApi`
- `GalleryApi`
- `ForumApi`
- `ChatApi`
- `FalukantApi`
- `VocabApi`
- `CalendarApi`
- `BlogGuideApi`
- `MinigamesApi`
- `AdminApi` spaeter
Wichtige Backend-Vertraege:
- Login liefert User inklusive `id` und `authCode`.
- REST-Requests brauchen Header `userid` und `authcode`.
- Socket.IO registriert User per `setUserId`.
- Daemon-WebSocket nutzt eigene Events und User-Kontext.
- Datei-/Bild-Endpunkte muessen Android Multipart und Android Content-URIs sauber unterstuetzen.
## Migrationsprinzip
Jedes Modul wird in vier Schritten umgesetzt:
1. API-Vertrag erfassen: Endpunkte, Payloads, Fehler, Rechte.
2. Domain-Modelle definieren: Kotlin DTOs, Mapping, UI-State.
3. Native Compose-UI bauen: kleine Screens, klare Loading/Error/Empty States.
4. Gegen Backend testen: Emulator, echtes Geraet, Offline/Resume, Realtime.
## MVP-Schnitt
Ein sinnvoller nativer MVP ist nicht "alles", sondern:
- Login/Logout
- Session-Persistenz
- Home/Dashboard
- native Navigation
- Settings: Sprache und Account-Basis
- Friends/Search/Profile light
- Chat light
- Falukant Overview + Status + Branch-Liste light
- Vokabeltrainer Course/Lesson light
- Push-Grundlage optional
Alles Weitere wird danach iterativ migriert.
## Nicht-Ziele fuer den nativen MVP
- Kein vollstaendiger Admin-Bereich.
- Keine vollstaendige Falukant-Wirtschaftssimulation in Version 1.
- Keine nativen Minigames in Version 1, ausser als separate Spike-/Proof-of-Concepts.
- Keine 3D-Charakterdarstellung in Version 1.
- Keine Offline-First-Synchronisation fuer alle Module.
- Keine Store-Verteilung vor Datenschutz-/UGC-/Adult-Compliance.
## Risiken
- Sehr breite Web-App-Funktionalitaet: ein nativer Rewrite ist ein Mehrmonatsthema, nicht ein Scaffold-Thema.
- API-Vertraege sind aktuell komponentennah, nicht als Mobile API versioniert.
- Auth nutzt `userid`/`authcode` statt standardisiertem Bearer Token.
- Viele Screens erwarten Web-Layout, Dialoge und dynamische Menues.
- Falukant ist daten- und realtime-intensiv.
- Chat, Galerie, Adult Content und UGC erfordern Store-Compliance.
- Native 3D/Minigames brauchen eigene Performance-Entscheidungen.
## Abhakbare Roadmap
### 0. Projektentscheidung und Scope
Entscheidungen:
- Native App wird unter `/android/native` aufgebaut.
- Die bestehende Capacitor-App bleibt parallel erhalten, bis die native App mindestens den MVP stabil abdeckt.
- Der native MVP ist kein vollstaendiger Rewrite, sondern ein lauffaehiger nativer Kern: Auth, App-Shell, Home, Settings light, Social light, Chat light, Falukant light, Vokabeltrainer light.
- Admin wird aus dem nativen MVP ausgeschlossen.
- Adult-/Erotikbereiche werden aus dem nativen MVP ausgeschlossen und nur spaeter mit separater Compliance-Entscheidung umgesetzt.
- Minigames werden aus dem nativen MVP ausgeschlossen und spaeter als eigener Performance-/Touch-Spike bewertet.
- 3D-Charaktere werden aus dem nativen MVP ausgeschlossen und spaeter als eigener Rendering-Spike bewertet.
- Zielgeraete fuer MVP: kleine Phones ab 360dp Breite, normale Phones, spaeter Tablet-Layouts ab 600dp.
- Mindest-Android fuer MVP: Android 8.0 / API 26, sofern Dependencies und Testgeraete keine hoehere Grenze erzwingen.
- Distribution fuer MVP: interne Debug-/Test-APK. Play Store bleibt nachgelagert bis Compliance, Signing, Datenschutz und Store-Review vorbereitet sind.
Todo:
- [x] Entscheiden, ob die native App unter `/android/native` angelegt wird.
- [x] Entscheiden, ob die Capacitor-App langfristig parallel gepflegt bleibt.
- [x] Native MVP-Funktionsumfang final freigeben.
- [x] Admin-Bereich aus MVP ausschliessen oder explizit aufnehmen.
- [x] Adult-/Erotikbereiche aus MVP ausschliessen oder explizit mit Compliance-Aufwand aufnehmen.
- [x] Minigames aus MVP ausschliessen oder als separaten Spike aufnehmen.
- [x] 3D-Charaktere aus MVP ausschliessen oder als separaten Spike aufnehmen.
- [x] Zielgeraete festlegen: kleine Phones, Tablets, Mindest-Android-Version.
- [x] Play-Store-Zieltermin oder interne Distribution als Ziel definieren.
### 1. Native Projektbasis
- [ ] Neues natives Gradle-Projekt unter `/android/native` erstellen.
- [ ] Kotlin DSL fuer Gradle verwenden.
- [ ] App-ID `de.yourpart.app` oder separate Dev-ID `de.yourpart.native.dev` entscheiden.
- [ ] Produktflavors anlegen: `local`, `staging`, `production`.
- [ ] Build Types anlegen: `debug`, `release`.
- [ ] Versionierung definieren: `versionCode`, `versionName`, Git-Hash im Build.
- [ ] Compose aktivieren.
- [ ] Material 3 aktivieren.
- [ ] Hilt einrichten.
- [ ] Retrofit/OkHttp einrichten.
- [ ] JSON-Library festlegen und einrichten.
- [ ] Room einrichten.
- [ ] DataStore einrichten.
- [ ] Coil einrichten.
- [ ] WorkManager einrichten.
- [ ] FCM Dependency vorbereiten, aber noch nicht aktiv schalten.
- [ ] Lint, Detekt oder Ktlint einrichten.
- [ ] CI-Build-Script fuer native App definieren.
### 2. Design System
- [ ] YourPart-Farbpalette aus Web-App ableiten.
- [ ] Typography fuer Android definieren.
- [ ] Spacing-Skala definieren.
- [ ] Shape-/Radius-System definieren.
- [ ] Button-Komponenten definieren.
- [ ] TextField-Komponenten definieren.
- [ ] Dialog-Komponenten definieren.
- [ ] Error-/Info-/Success-Komponenten definieren.
- [ ] Loading/Empty-State-Komponenten definieren.
- [ ] Avatar-/Image-Komponenten definieren.
- [ ] Status-Chips fuer Backend/Daemon definieren.
- [ ] Light Theme implementieren.
- [ ] Dark Theme bewusst entscheiden: sofort, spaeter oder nicht.
- [ ] Kleine Displaybreiten 360dp und 393dp als Design-Baseline testen.
### 3. App Shell und Navigation
- [ ] Root Compose App mit Theme erstellen.
- [ ] Top App Bar definieren.
- [ ] Bottom Navigation fuer Hauptbereiche definieren.
- [ ] Navigation Drawer fuer Sekundaerbereiche definieren.
- [ ] Typed Routes fuer Auth, Home, Social, Falukant, Vocab, Settings anlegen.
- [ ] Rollen-/Rechte-basierte Menueeintraege modellieren.
- [ ] Backend-Menue-Response analysieren und native Menue-Policy definieren.
- [ ] Deep-Link-Struktur definieren.
- [ ] Android Back Button Verhalten definieren.
- [ ] Dialog-Back-Handling implementieren.
- [ ] Session-expired Navigation implementieren.
- [ ] Offline-Banner implementieren.
- [ ] Backend-/Daemon-Status sichtbar, aber kompakt darstellen.
### 4. Konfiguration und Environments
- [ ] API Base URLs fuer `local`, `staging`, `production` definieren.
- [ ] Socket.IO URLs je Flavor definieren.
- [ ] Daemon WebSocket URLs je Flavor definieren.
- [ ] Lokale Emulator-Regel dokumentieren: Host-Rechner ist `10.0.2.2`.
- [ ] Release-Build gegen lokale URLs blockieren.
- [ ] Network Security Config fuer Debug und Release definieren.
- [ ] TLS-only fuer Release sicherstellen.
- [ ] Secrets aus APK fernhalten.
- [ ] Feature Flags definieren: Admin, Adult, 3D, Minigames, Push.
### 5. Auth und Session
- [ ] Login-Endpunkt dokumentieren.
- [ ] Login DTOs erstellen.
- [ ] Login Repository implementieren.
- [ ] Auth Interceptor fuer `userid` und `authcode` implementieren.
- [ ] Session Store mit sicherer Speicherung implementieren.
- [ ] Auto-Login beim App-Start implementieren.
- [ ] Logout implementieren.
- [ ] Session-expired Handling implementieren.
- [ ] User-Aktivstatus pruefen.
- [ ] Account gesperrt Handling implementieren.
- [ ] Registrierung API-Vertrag erfassen.
- [ ] Registrierung Screen implementieren.
- [ ] Account-Aktivierung Flow bewerten.
- [ ] Passwort-Reset Flow implementieren.
- [ ] OAuth-Provider-Liste laden.
- [ ] OAuth per Custom Tabs planen.
- [ ] App Links fuer OAuth Callback planen.
- [ ] OAuth erst nach Username/Passwort stabil aktivieren.
### 6. Netzwerk-Grundlage
- [ ] Zentrale `ApiResult`/`NetworkError` Struktur definieren.
- [ ] Fehlercodes und Backend-Fehlerformate erfassen.
- [ ] Retry-Policy definieren.
- [ ] Timeout-Policy definieren.
- [ ] Request Logging nur fuer Debug aktivieren.
- [ ] Auth Header Tests mit MockWebServer schreiben.
- [ ] CORS ist nativ irrelevant, aber Backend-Origin-Checks gegen mobile Clients pruefen.
- [ ] Multipart Upload Helper bauen.
- [ ] Download Helper fuer Bilder/Dateien bauen.
- [ ] Pagination Pattern definieren.
- [ ] Refresh Pattern definieren.
### 7. Lokale Persistenz und Cache
- [ ] DataStore fuer UI-Sprache verwenden.
- [ ] DataStore fuer Feature Flags verwenden.
- [ ] Room Schema fuer User/Profile Cache definieren.
- [ ] Room Schema fuer Friends/Search Cache definieren.
- [ ] Room Schema fuer Falukant Status light definieren.
- [ ] Room Schema fuer Vocab Course/Lesson Cache definieren.
- [ ] Cache-Invalidation Regeln definieren.
- [ ] Offline-Anzeige statt Offline-First fuer MVP festlegen.
- [ ] Outbox fuer spaetere Offline-Aktionen nur planen, nicht im MVP erzwingen.
### 8. Realtime
- [ ] Socket.IO Android Client evaluieren.
- [ ] Verbindung nach Login aufbauen.
- [ ] `setUserId` nach Verbindungsaufbau senden.
- [ ] Events erfassen: `forumschanged`, `friendloginchanged`, `reloadmenu`, `adultVerificationChanged`, `moderationReportChanged`, `userAccessChanged`.
- [ ] Falukant-Events erfassen: `falukantUpdateStatus`, `falukantUpdateFamily`, `falukantUpdateChurch`, `falukantUpdateDebt`, `children_update`, `falukantUpdateProductionCertificate`, `falukantBranchUpdate`, `stock_change`, `familychanged`.
- [ ] Socket Lifecycle an App Foreground/Background koppeln.
- [ ] Reconnect Policy definieren.
- [ ] Daemon-WebSocket Client implementieren.
- [ ] Daemon-Message Parsing robust gegen unbekannte Events machen.
- [ ] Realtime Events in Repositories einspeisen.
- [ ] UI-State bei Events gezielt invalidieren.
- [ ] Realtime Debug Screen fuer interne Builds planen.
### 9. Home und Dashboard
- [ ] Home API-Vertraege erfassen.
- [ ] Eingeloggt/Nicht-eingeloggt Home getrennt modellieren.
- [ ] Native Startseite fuer nicht eingeloggte Nutzer bauen.
- [ ] Native Startseite fuer eingeloggte Nutzer bauen.
- [ ] Dashboard Widget API-Vertraege erfassen.
- [ ] Termine/Upcoming Events als native Cards umsetzen.
- [ ] Falukant Kurzstatus als native Card umsetzen.
- [ ] News/Blog/Guide Kurzlisten bewerten.
- [ ] Backend-/Daemon-Status light anzeigen.
### 10. Settings
- [ ] Settings API-Vertraege erfassen: `/api/settings/filter`, `/api/settings/update`, `/api/settings/account`.
- [ ] Spracheinstellung nativ implementieren.
- [ ] Account-Basisdaten nativ implementieren.
- [ ] Sichtbarkeitseinstellungen modellieren.
- [ ] Personal/View/Sexuality/Flirt Settings priorisieren.
- [ ] Interessen-Settings implementieren.
- [ ] Language Assistant Settings bewerten.
- [ ] Account-Loeschung oder Anfrageprozess fuer Store-Compliance klaeren.
### 11. Social Basis
- [ ] Friends API-Vertraege erfassen.
- [ ] Friends Screen implementieren: bestehend, angefragt, offen, abgelehnt.
- [ ] User Search API-Vertraege erfassen.
- [ ] User Search Screen implementieren.
- [ ] User Profile API-Vertraege erfassen.
- [ ] Profile Light Screen implementieren.
- [ ] Guestbook API-Vertraege erfassen.
- [ ] Guestbook light implementieren.
- [ ] Friend Request Aktionen implementieren.
- [ ] Blockieren/Melden UX fuer Store-Compliance planen.
- [ ] Privacy/Visibility Regeln aus Backend nativ abbilden.
### 12. Chat
- [ ] Aktuellen Chat-Mechanismus erfassen: Dialoge, Raeume, Random Chat, MultiChat.
- [ ] Chat Backend-/WebSocket-Vertraege dokumentieren.
- [ ] Chat Room Liste implementieren.
- [ ] 1:1 Chat MVP implementieren.
- [ ] MultiChat MVP implementieren oder bewusst verschieben.
- [ ] RandomChat bewusst verschieben oder implementieren.
- [ ] Message Input mit Keyboard-Verhalten testen.
- [ ] Neue Nachrichten per Realtime anzeigen.
- [ ] Push-Kandidaten fuer Chat definieren.
- [ ] Melden/Blockieren im Chat implementieren oder als Release-Blocker markieren.
### 13. Galerie und Medien
- [ ] Galerie API-Vertraege erfassen.
- [ ] Folder-Struktur nativ modellieren.
- [ ] Bildliste mit Coil implementieren.
- [ ] Bilddetail implementieren.
- [ ] Android Photo Picker fuer Upload implementieren.
- [ ] Multipart Upload testen.
- [ ] Bildbearbeitung aus Web-App bewerten: MVP ja/nein.
- [ ] Sichtbarkeiten laden und setzen.
- [ ] Adult-Galerie aus MVP ausschliessen oder Compliance-Aufwand planen.
- [ ] Video-Unterstuetzung separat planen.
### 14. Forum
- [ ] Forum-Liste API-Vertrag erfassen.
- [ ] Topic-Liste API-Vertrag erfassen.
- [ ] Topic-Detail API-Vertrag erfassen.
- [ ] Forum-Liste native umsetzen.
- [ ] Topic-Liste native umsetzen.
- [ ] Topic-Detail native umsetzen.
- [ ] Antwort erstellen implementieren.
- [ ] Moderation Report fuer Forum implementieren.
- [ ] Realtime `forumschanged` integrieren.
### 15. Falukant MVP
- [ ] Falukant API-Endpunkte aus Web-App inventarisieren.
- [ ] `StatusBar` Datenmodell nativ definieren.
- [ ] Overview Screen implementieren.
- [ ] Character/Familien-Basisdaten implementieren.
- [ ] Branch-Liste implementieren.
- [ ] Branch-Detail light implementieren.
- [ ] Bank light implementieren.
- [ ] Messages/Notifications light implementieren.
- [ ] Realtime Falukant Events integrieren.
- [ ] Create Falukant Flow implementieren oder bewusst verschieben.
- [ ] Family View light implementieren.
- [ ] Church/Reputation/Health/Nobility als spaetere Phase markieren.
- [ ] Production/Storage/Sale/Director als spaetere Phase markieren.
- [ ] Karten-/Regionen-Features als spaetere Phase markieren.
### 16. Falukant Vollausbau
- [ ] Branch Detail vollstaendig umsetzen.
- [ ] Production Section umsetzen.
- [ ] Storage Section umsetzen.
- [ ] Sale Section umsetzen.
- [ ] Director Info umsetzen.
- [ ] Transport Routes umsetzen.
- [ ] Bank vollstaendig umsetzen.
- [ ] Family vollstaendig umsetzen.
- [ ] Health umsetzen.
- [ ] Reputation umsetzen.
- [ ] Church umsetzen.
- [ ] Nobility umsetzen.
- [ ] Politics umsetzen.
- [ ] Underground umsetzen.
- [ ] House umsetzen.
- [ ] Education umsetzen.
- [ ] Money History umsetzen.
- [ ] Performance fuer grosse Falukant-Datenmengen testen.
### 17. Vokabeltrainer MVP
- [ ] Vocab Languages API-Vertrag erfassen.
- [ ] Course List API-Vertrag erfassen.
- [ ] Course Detail API-Vertrag erfassen.
- [ ] Lesson API-Vertrag erfassen.
- [ ] Review API-Vertrag erfassen.
- [ ] Vocab Landing native umsetzen.
- [ ] Course List native umsetzen.
- [ ] Course Detail native umsetzen.
- [ ] Lesson Player MVP implementieren.
- [ ] Lesson Review implementieren.
- [ ] Dictionary light implementieren.
- [ ] Progress/Completion speichern.
- [ ] Keyboard-/Audio-/Touch-Verhalten testen.
- [ ] Offline Cache fuer aktive Lektion planen.
### 18. Vokabeltrainer Vollausbau
- [ ] Neue Sprache anlegen implementieren.
- [ ] Subscribe Flow implementieren.
- [ ] Chapter View implementieren.
- [ ] Dictionary vollstaendig implementieren.
- [ ] Practice Dialog nativ ersetzen.
- [ ] SRS-/Review-Logik gegen Backend validieren.
- [ ] Offline Lesson Cache implementieren.
- [ ] Sync-Konflikte definieren.
### 19. Kalender und Persoenliches
- [ ] Calendar API-Vertraege erfassen.
- [ ] Monats-/Wochen-/Listenansicht entscheiden.
- [ ] Termine laden.
- [ ] Termin erstellen.
- [ ] Termin bearbeiten.
- [ ] Termin loeschen.
- [ ] Date/Time Picker nativ einsetzen.
- [ ] Reminder/Push spaeter planen.
- [ ] Diary API-Vertrag erfassen.
- [ ] Diary light umsetzen oder verschieben.
### 20. Public Content
- [ ] Blog List API-Vertrag erfassen.
- [ ] Blog Detail API-Vertrag erfassen.
- [ ] Guide List API-Vertrag erfassen.
- [ ] Guide Detail API-Vertrag erfassen.
- [ ] Public Landing Screens nativ priorisieren oder aus App entfernen.
- [ ] Rich Text Rendering nativ loesen.
- [ ] Blog Editor aus MVP ausschliessen.
- [ ] Guide/Marketing Content als WebView-Fallback pruefen oder nativ rendern.
### 21. Minigames
- [ ] Match3 Game als native Compose/Canvas Machbarkeit pruefen.
- [ ] Taxi Game als native Canvas/OpenGL Machbarkeit pruefen.
- [ ] WebView-Fallback fuer Minigames als Zwischenloesung bewerten.
- [ ] Touch-Steuerung definieren.
- [ ] Performance auf Emulator und echtem Geraet testen.
- [ ] Leaderboard/Score API-Vertraege erfassen.
- [ ] Admin-Tools fuer Minigames aus nativer App ausschliessen.
### 22. Admin spaeter
- [ ] Entscheiden, ob Admin ueberhaupt in native App gehoert.
- [ ] Admin Users API-Vertraege erfassen.
- [ ] Admin Rights API-Vertraege erfassen.
- [ ] Moderation Reports API-Vertraege erfassen.
- [ ] Adult Verification API-Vertraege erfassen.
- [ ] Erotic Moderation API-Vertraege erfassen.
- [ ] Forum Admin API-Vertraege erfassen.
- [ ] Falukant Admin API-Vertraege erfassen.
- [ ] Services Status Screen fuer interne Builds planen.
- [ ] Admin nur per Feature Flag und Rollencheck sichtbar machen.
### 23. Adult Content und Store-Compliance
- [ ] Adult Content aus MVP entfernen oder per Feature Flag deaktivieren.
- [ ] Altersverifikation nativ modellieren.
- [ ] UGC-Melden nativ in Chat, Galerie, Forum, Profil implementieren.
- [ ] Blockieren nativ implementieren.
- [ ] Moderationserreichbarkeit dokumentieren.
- [ ] Datenschutzseite nativ erreichbar machen.
- [ ] Impressum nativ erreichbar machen.
- [ ] Kontakt nativ erreichbar machen.
- [ ] Account-Loeschung oder klare Anleitung nativ erreichbar machen.
- [ ] Play Store Content Rating vorbereiten.
- [ ] Store-Review-Risiko fuer Adult Content separat entscheiden.
### 24. Push Notifications
- [ ] Firebase Projekt klaeren.
- [ ] FCM in native App integrieren.
- [ ] Device Token Backend-Modell planen.
- [ ] Device Token Registration API definieren.
- [ ] Opt-in UI implementieren.
- [ ] Notification Settings implementieren.
- [ ] Chat Push definieren.
- [ ] Friend Login Push definieren.
- [ ] Falukant Event Push definieren.
- [ ] Vocab Reminder Push definieren.
- [ ] Deep Links aus Notifications implementieren.
- [ ] Token Refresh Handling implementieren.
### 25. Deep Links und OAuth
- [ ] App Links Domain festlegen.
- [ ] `assetlinks.json` planen.
- [ ] OAuth Redirect URIs fuer Android planen.
- [ ] Custom Tabs Flow implementieren.
- [ ] OAuth Callback Handling implementieren.
- [ ] Deep Links fuer Profile, Forum, Falukant, Vocab, Blog definieren.
- [ ] Deep Link Auth Guard implementieren.
- [ ] Nicht eingeloggte Deep Links nach Login fortsetzen.
### 26. Sicherheit
- [ ] Authdaten nicht im Klartext speichern.
- [ ] Release Logging sensibler Daten verhindern.
- [ ] Certificate Pinning bewerten, nicht vorschnell erzwingen.
- [ ] Network Security Config fuer Release restriktiv halten.
- [ ] Root/Jailbreak Detection bewusst entscheiden.
- [ ] Screenshot-Schutz fuer Adult/Private Bereiche bewerten.
- [ ] Datei-Uploads auf MIME/Größe pruefen.
- [ ] WebView-Fallbacks minimieren.
- [ ] Dependency-Scanning fuer Android einrichten.
### 27. Testing
- [ ] Unit Tests fuer Auth Repository.
- [ ] Unit Tests fuer Settings Repository.
- [ ] Unit Tests fuer Error Mapping.
- [ ] MockWebServer Tests fuer Auth Header.
- [ ] MockWebServer Tests fuer API-Fehler.
- [ ] Room Migration Tests.
- [ ] Compose Tests fuer Login.
- [ ] Compose Tests fuer Navigation.
- [ ] Compose Tests fuer Home.
- [ ] Compose Tests fuer Vocab Lesson.
- [ ] Realtime Tests mit Testserver planen.
- [ ] Emulator-Testmatrix definieren: kleines Phone, grosses Phone, Tablet.
- [ ] Echtes Android-Geraet in Testmatrix aufnehmen.
- [ ] Offline/Online-Wechsel testen.
- [ ] App Kill/Restart/Resume testen.
### 28. Build, Release und Betrieb
- [ ] Debug APK Build einrichten.
- [ ] Release AAB Build einrichten.
- [ ] Signing-Konzept definieren.
- [ ] Keystore sicher ablegen.
- [ ] Internal App Sharing oder interne Testspur planen.
- [ ] Crashlytics oder alternatives Crash Reporting entscheiden.
- [ ] Analytics bewusst entscheiden: ja/nein, Datenschutz.
- [ ] App Version Check implementieren oder planen.
- [ ] Rollback-Strategie definieren.
- [ ] Hybrid-App und Native-App Parallelbetrieb dokumentieren.
### 29. Backend-Vorbereitung fuer Native
- [ ] Mobile API-Inventar aus allen Web-Komponenten erstellen.
- [ ] API-Versionierung bewerten: `/api/mobile/v1` ja/nein.
- [ ] Einheitliches Fehlerformat definieren.
- [ ] Einheitliches Pagination-Format definieren.
- [ ] Auth auf Bearer Token/JWT oder bestehendes `userid`/`authcode` final entscheiden.
- [ ] Refresh Token Konzept bewerten.
- [ ] Device Token API fuer Push planen.
- [ ] Datei-Upload-Limits dokumentieren.
- [ ] Image Thumbnail Endpunkte fuer mobile Listen planen.
- [ ] Falukant Summary Endpunkte fuer mobile Screens planen.
- [ ] Vocab Lesson Endpunkte fuer mobile Offline-Caches planen.
### 30. Abnahmekriterien MVP
- [ ] App startet kalt unter 2 Sekunden auf Testgeraet oder Zielwert begruendet anpassen.
- [ ] Login funktioniert gegen production/staging.
- [ ] Session ueberlebt App-Neustart.
- [ ] Logout entfernt lokale Session und trennt Realtime.
- [ ] Home laedt ohne WebView.
- [ ] Navigation ist vollstaendig nativ.
- [ ] Mindestens ein Social-Basisflow funktioniert.
- [ ] Mindestens ein Falukant-Basisflow funktioniert.
- [ ] Mindestens ein Vocab-Lesson-Flow funktioniert.
- [ ] Fehler werden nativ und verstaendlich angezeigt.
- [ ] Offline-Zustand wird erkannt und blockiert keine App.
- [ ] Keine lokalen Dev-URLs im Release-Build.
- [ ] Keine Secrets im APK/AAB.
- [ ] Datenschutz, Impressum und Kontakt sind erreichbar.
## Empfohlene erste Umsetzungsschritte
1. `/android/native` als neues Kotlin/Compose-Projekt anlegen.
2. Core Module fuer Network, Auth, Design und Navigation erstellen.
3. Login komplett nativ implementieren.
4. Session Store und Auth Interceptor stabilisieren.
5. Native App Shell mit Home und Navigation bauen.
6. Danach Social light, Falukant light und Vocab light nacheinander umsetzen.
## Realistische Einordnung
Die native Komplettumsetzung ist erheblich groesser als die Hybrid-App. Die Hybrid-App ist sinnvoll als lauffaehige Zwischenloesung und Referenzimplementierung. Die native App sollte als paralleles Produkt mit klarem MVP gestartet werden, sonst entsteht ein langer Rewrite ohne nutzbaren Zwischenstand.

101
android/README.md Normal file
View File

@@ -0,0 +1,101 @@
# YourPart Android
Android-App-Shell fuer YourPart auf Basis der bestehenden Vue/Vite-App und Capacitor.
## Entscheidungen
- App-ID: `de.yourpart.app`
- App-Name: `YourPart`
- Technologie: Capacitor mit lokal gebuendeltem `frontend/dist`
- Backend: bestehendes Backend wird verwendet, keine Backend-Implementierung in diesem Android-Start
- Erstes Ziel: interne Debug-/Test-APK
## Vorbereitung
1. Frontend-Env-Vorlage kopieren und Werte pruefen:
```bash
cp ../frontend/.env.android.example ../frontend/.env.android
```
2. Android-Dependencies installieren:
```bash
npm install
```
3. Web-Bundle fuer Android bauen:
```bash
npm run build:web
```
4. Android-Projekt erzeugen:
```bash
npm run add:android
```
5. Danach synchronisieren:
```bash
npm run sync
```
## Debug-Build
Nach `npm run add:android`:
```bash
npm run build:debug
```
Das erzeugte APK liegt danach unter `android/app/build/outputs/apk/debug/`.
Innerhalb dieses Repositorys ist das der Pfad `/android/android/app/build/outputs/apk/debug/`.
## Android Studio
In Android Studio muss das native Gradle-Projekt geoeffnet werden:
```text
/home/torsten/Programs/YourPart3/android/android
```
Nicht `/home/torsten/Programs/YourPart3/android` oeffnen. Dieser Ordner ist nur die Capacitor-Projektwurzel mit `package.json` und `capacitor.config.ts`; die Android-Studio-App liegt eine Ebene tiefer in `/android/android`.
Nach dem Oeffnen:
1. Gradle Sync abwarten.
2. Run Configuration `YourPart Debug` auswaehlen.
3. Emulator auswaehlen.
4. Starten.
Wenn Android Studio die Konfiguration nicht sofort anzeigt, `File > Sync Project with Gradle Files` ausfuehren oder das Projektfenster neu laden.
## Emulator-Eingabe
Die App verwendet die normale Android-WebView-Eingabe. `android.captureInput` ist bewusst nicht aktiviert, weil diese Capacitor-Option die WebView-InputConnection ersetzt und im Emulator verhindern kann, dass Textfelder normal beschrieben werden.
## Backend-CORS fuer Android-Debug
Capacitor laedt die lokale Android-App standardmaessig unter:
```text
https://localhost
```
Die API-Requests gehen weiterhin an `https://www.your-part.de/api/...`. Deshalb muss das Backend `https://localhost` in `CORS_ORIGINS` erlauben:
```env
CORS_ORIGINS=https://www.your-part.de,https://localhost,http://localhost:5173,http://127.0.0.1:5173
```
`server.hostname` in `capacitor.config.ts` darf nicht auf `www.your-part.de` gesetzt werden. Sonst interpretiert Capacitor Backend- und Model-URLs wie `/api/models/...glb` als lokale App-Assets.
## Wichtige Hinweise
- `frontend/.env.android` darf echte produktive URLs enthalten, aber keine Secrets.
- `VITE_DISABLE_3D=true` ist fuer Android-Debug absichtlich gesetzt. Das verhindert WebGL/GLB-Last auf der Login-Seite, bis CORS und 3D-Performance separat freigegeben sind.
- OAuth ist im ersten Debug-APK nicht der Blocker; Username/Passwort-Login ist die Pflichtfunktion.
- Push Notifications werden erst nach stabiler Shell geplant.
- Play Store ist vorerst kein Ziel, bis Datenschutz, UGC, Moderation und Adult-Content separat geprueft sind.

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

10
android/android/.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

9
android/android/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -0,0 +1,68 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="YourPart Debug" type="AndroidRunConfigurationType" factoryName="Android App">
<option name="ANDROID_RUN_CONFIGURATION_SCHEMA_VERSION" value="1" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
<option name="DEPLOY_AS_INSTANT" value="false" />
<option name="ARTIFACT_NAME" value="" />
<option name="PM_INSTALL_OPTIONS" value="" />
<option name="ALL_USERS" value="false" />
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
<option name="ALLOW_ASSUME_VERIFIED" value="false" />
<option name="CLEAR_APP_STORAGE" value="false" />
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" />
<option name="RESTORE_ENABLED" value="false" />
<option name="RESTORE_FILE" value="" />
<option name="RESTORE_FRESH_INSTALL_ONLY" value="false" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
<option name="DEBUGGER_TYPE" value="Auto" />
<module name="android.app.main" />
<Auto>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
</Auto>
<Hybrid>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
</Hybrid>
<Java>
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
</Java>
<Native>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
</Native>
<Profilers>
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
<option name="STARTUP_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Java/Kotlin Method Sample (legacy)" />
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY" value="" />
<option name="ACTIVITY_CLASS" value="" />
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -0,0 +1,54 @@
apply plugin: 'com.android.application'
android {
namespace = "de.yourpart.app"
compileSdk = rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "de.yourpart.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
repositories {
flatDir{
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation project(':capacitor-android')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation project(':capacitor-cordova-android-plugins')
}
apply from: 'capacitor.build.gradle'
try {
def servicesJSON = file('google-services.json')
if (servicesJSON.text) {
apply plugin: 'com.google.gms.google-services'
}
} catch(Exception e) {
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}

View File

@@ -0,0 +1,19 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
}
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}

21
android/android/app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,26 @@
package de.yourpart.app;
import static org.junit.Assert.*;
import android.content.Context;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("de.yourpart.app", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -0,0 +1,5 @@
package de.yourpart.app;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="app_name">YourPart</string>
<string name="title_activity_main">YourPart</string>
<string name="package_name">de.yourpart.app</string>
<string name="custom_url_scheme">de.yourpart.app</string>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:background">@null</item>
</style>
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
<item name="android:background">@drawable/splash</item>
</style>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="." />
<cache-path name="my_cache_images" path="." />
</paths>

View File

@@ -0,0 +1,18 @@
package de.yourpart.app;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View File

@@ -0,0 +1,30 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
// Trigger sync
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.13.0'
classpath 'com.google.gms:google-services:4.4.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
apply from: "variables.gradle"
allprojects {
repositories {
google()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -0,0 +1,6 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')

View File

@@ -0,0 +1,22 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true

Binary file not shown.

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

251
android/android/gradlew vendored Executable file
View File

@@ -0,0 +1,251 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

94
android/android/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,94 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,5 @@
include ':app'
include ':capacitor-cordova-android-plugins'
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
apply from: 'capacitor.settings.gradle'

View File

@@ -0,0 +1,16 @@
ext {
minSdkVersion = 24
compileSdkVersion = 36
targetSdkVersion = 36
androidxActivityVersion = '1.11.0'
androidxAppCompatVersion = '1.7.1'
androidxCoordinatorLayoutVersion = '1.3.0'
androidxCoreVersion = '1.17.0'
androidxFragmentVersion = '1.8.9'
coreSplashScreenVersion = '1.2.0'
androidxWebkitVersion = '1.14.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.3.0'
androidxEspressoCoreVersion = '3.7.0'
cordovaAndroidVersion = '14.0.1'
}

View File

@@ -0,0 +1,22 @@
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'de.yourpart.app',
appName: 'YourPart',
webDir: '../frontend/dist',
bundledWebRuntime: false,
server: {
androidScheme: 'https'
},
plugins: {
SplashScreen: {
launchAutoHide: true
}
},
android: {
allowMixedContent: false,
webContentsDebuggingEnabled: true
}
};
export default config;

1190
android/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

22
android/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "yourpart-android",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build:web": "bash scripts/build-android-web.sh",
"sync": "bash scripts/sync-android.sh",
"open": "npx cap open android",
"add:android": "npx cap add android",
"build:debug": "bash scripts/build-android-debug.sh"
},
"dependencies": {
"@capacitor/android": "8.4.1",
"@capacitor/app": "8.1.0",
"@capacitor/core": "8.4.1"
},
"devDependencies": {
"@capacitor/cli": "8.4.1",
"typescript": "6.0.3"
}
}

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ANDROID_PROJECT_DIR="$ROOT_DIR/android/android"
if [[ ! -x "$ANDROID_PROJECT_DIR/gradlew" ]]; then
echo "Android-Projekt fehlt. Fuehre zuerst aus: cd android && npm run add:android" >&2
exit 1
fi
cd "$ANDROID_PROJECT_DIR"
./gradlew assembleDebug

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR/frontend"
npm run build -- --mode android

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR/android"
npx cap sync android