Refactor code structure for improved readability and maintainability; optimize performance across multiple modules.
All checks were successful
Deploy to production / deploy (push) Successful in 2m56s

This commit is contained in:
Torsten Schulz (local)
2026-07-21 09:08:15 +02:00
parent 75b52de282
commit 1ab9407e79
1400 changed files with 22278 additions and 485 deletions

0
android/.idea/android.iml generated Normal file → Executable file
View File

36
android/.idea/caches/deviceStreaming.xml generated Normal file → Executable file
View File

@@ -591,6 +591,18 @@
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="samsung" />
<option name="codename" value="b0qksx" />
<option name="id" value="b0qksx" />
<option name="labId" value="google" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S22 Ultra" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2316" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="samsung" />
@@ -705,6 +717,18 @@
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="c2qksw" />
<option name="id" value="c2qksw" />
<option name="labId" value="google" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Note20 Ultra 5G" />
<option name="screenDensity" value="560" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
@@ -1119,6 +1143,18 @@
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="samsung" />
<option name="codename" value="gta4lwifi" />
<option name="id" value="gta4lwifi" />
<option name="labId" value="google" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab A7" />
<option name="screenDensity" value="240" />
<option name="screenX" value="1200" />
<option name="screenY" value="2000" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />

0
android/.idea/deviceManager.xml generated Normal file → Executable file
View File

0
android/.idea/markdown.xml generated Normal file → Executable file
View File

0
android/.idea/misc.xml generated Normal file → Executable file
View File

0
android/.idea/modules.xml generated Normal file → Executable file
View File

0
android/.idea/vcs.xml generated Normal file → Executable file
View File

0
android/ANDROID_APP_PLAN.md Normal file → Executable file
View File

58
android/APP_LINKS.md Normal file
View File

@@ -0,0 +1,58 @@
# Android App Links und OAuth
## Verbindliche Domain
Die Produktions-App verwendet ausschließlich `https://www.your-part.de`.
Staging und lokale Builds öffnen diese URLs weiterhin im Browser und beanspruchen keine
Domain-Verknüpfung.
## Unterstützte Pfade
| Web-Pfad | Native Route | Anmeldung |
| --- | --- | --- |
| `/` | `home` | ja |
| `/socialnetwork/*` | Community, Suche, Galerie, Forum oder Vokabeln | ja |
| `/falukant/*` | `falukant` | ja |
| `/settings/*` | `settings` | ja |
| `/blogs/*` | `blogs` | nein |
| `/guides/*` | `guides` | nein |
| `/android/oauth/callback` | OAuth-Callback | nein |
Geschützte Links bleiben im Speicher erhalten. Nach erfolgreichem Login navigiert die App
automatisch zur ursprünglich angeforderten Route.
## OAuth
Die native App startet `/api/auth/oauth/{provider}/start?client=android` in einer Android
Custom Tab. Der Server erzeugt PKCE und `state`, speichert beides in Redis und nutzt als feste
Redirect-URI `https://www.your-part.de/android/oauth/callback`. Die App sendet nur `code`,
`state` und optional `iss` an `/api/auth/oauth/exchange`; Tokens von OAuth-Providern gelangen
nicht in die App.
In jedem aktivierten Provider muss diese URI als Redirect URI hinterlegt sein:
```text
https://www.your-part.de/android/oauth/callback
```
Optional kann das Backend die URL mittels `OAUTH_ANDROID_CALLBACK_URL` überschreiben. Der Wert
muss HTTPS verwenden und exakt den Pfad `/android/oauth/callback` haben.
## assetlinks.json
Nach Erzeugung des Release-Keystores den SHA-256-Fingerprint ermitteln:
```bash
keytool -list -v -keystore release.jks -alias <alias>
```
`frontend/public/.well-known/assetlinks.json.example` nach
`frontend/public/.well-known/assetlinks.json` kopieren, den Platzhalter durch den Fingerprint
ersetzen und mit dem Frontend ausliefern. Die finale Datei muss unter dieser URL ohne Redirect
und mit `Content-Type: application/json` abrufbar sein:
```text
https://www.your-part.de/.well-known/assetlinks.json
```
Erst dann kann Android `android:autoVerify` erfolgreich abschließen.

799
android/NATIVE_ANDROID_APP_PLAN.md Normal file → Executable file
View File

@@ -215,368 +215,599 @@ Stand 2026-07-09:
### 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.
Stand 2026-07-09:
- Die Web-Farbpalette ist in native Tokens uebertragen.
- Typography, Spacing und Shapes sind als Theme-Tokens angelegt.
- Wiederverwendbare Compose-Bausteine existieren fuer Buttons, Textfelder, Dialoge, Info-/Loading-/Empty-States, Avatar und Status-Chips.
- Das Light Theme ist aktiv und die Demo-Shell nutzt die neuen Komponenten bereits.
- Ein minimales Dark-Theme-Grundgeruest existiert technisch, die Produktentscheidung dafuer bleibt aber offen.
- [x] YourPart-Farbpalette aus Web-App ableiten.
- [x] Typography fuer Android definieren.
- [x] Spacing-Skala definieren.
- [x] Shape-/Radius-System definieren.
- [x] Button-Komponenten definieren.
- [x] TextField-Komponenten definieren.
- [x] Dialog-Komponenten definieren.
- [x] Error-/Info-/Success-Komponenten definieren.
- [x] Loading/Empty-State-Komponenten definieren.
- [x] Avatar-/Image-Komponenten definieren.
- [x] Status-Chips fuer Backend/Daemon definieren.
- [x] Light Theme implementieren.
- [x] Dark Theme bewusst entscheiden: nein, nicht Teil des MVP.
- [x] Kleine Displaybreiten 360dp und 393dp als Design-Baseline testen: nein, nicht Teil des MVP.
### 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.
Stand 2026-07-09:
- Die Demo-App ist zu einer nativen Shell mit Navigation ausgebaut.
- Top App Bar, Bottom Navigation und Drawer existieren.
- Primaere und sekundaere Bereiche sind als Route-Objekte modelliert.
- Eine erste Menue-Policy auf Basis von Session/Rollen ist vorhanden.
- Drawer-Back-Handling und Session-expired Rueckfuehrung zur Auth-Route sind umgesetzt.
- Offline-Banner sowie kompakte Backend-/Daemon-Status-Chips sind sichtbar.
- [x] Root Compose App mit Theme erstellen.
- [x] Top App Bar definieren.
- [x] Bottom Navigation fuer Hauptbereiche definieren.
- [x] Navigation Drawer fuer Sekundaerbereiche definieren.
- [x] Typed Routes fuer Auth, Home, Social, Falukant, Vocab, Settings anlegen.
- [x] Rollen-/Rechte-basierte Menueeintraege modellieren.
- [x] Backend-Menue-Response analysieren und native Menue-Policy definieren.
- [x] Android Back Button Verhalten definieren.
- [x] Dialog-Back-Handling implementieren.
- [x] Session-expired Navigation implementieren.
- [x] Offline-Banner implementieren.
- [x] 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.
Stand 2026-07-09:
- Flavor-spezifische URLs fuer `local`, `staging`, `production` sind im Build hinterlegt.
- `local` nutzt bewusst `10.0.2.2` fuer Emulator-Zugriff.
- Release-Builds validieren automatisch, dass `staging` und `production` keine lokalen oder unverschluesselten URLs verwenden.
- Debug und Release nutzen getrennte Network-Security-Configs.
- Release verbietet Cleartext komplett.
- Feature Flags fuer `Admin`, `Adult`, `3D`, `Minigames` und `Push` sind als BuildConfig-Felder angelegt.
- Eine zentrale `AppConfig` liest die Flavor-/Build-Konfiguration aus `BuildConfig`.
- [x] API Base URLs fuer `local`, `staging`, `production` definieren.
- [x] Socket.IO URLs je Flavor definieren.
- [x] Daemon WebSocket URLs je Flavor definieren.
- [x] Lokale Emulator-Regel dokumentieren: Host-Rechner ist `10.0.2.2`.
- [x] Release-Build gegen lokale URLs blockieren.
- [x] Network Security Config fuer Debug und Release definieren.
- [x] TLS-only fuer Release sicherstellen.
- [x] Secrets aus APK fernhalten.
- [x] 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.
Stand 2026-07-09:
- Login, Logout und Session-Persistenz sind nativ angebunden.
- REST-Requests setzen automatisch `userid` und `authcode`.
- 401-Antworten fuehren zu Session-Loeschung und Session-expired-Hinweis.
- Registrierung, Passwort-Reset und OAuth-Provider-Liste sind als native Auth-Bausteine vorhanden.
- [x] Login-Endpunkt dokumentieren.
- [x] Login DTOs erstellen.
- [x] Login Repository implementieren.
- [x] Auth Interceptor fuer `userid` und `authcode` implementieren.
- [x] Session Store mit sicherer Speicherung implementieren.
- [x] Auto-Login beim App-Start implementieren.
- [x] Logout implementieren.
- [x] Session-expired Handling implementieren.
- [x] User-Aktivstatus pruefen.
- [x] Account gesperrt Handling implementieren.
- [x] Registrierung API-Vertrag erfassen.
- [x] Registrierung Screen implementieren.
- [ ] Account-Aktivierung Flow bewerten.
- [ ] Passwort-Reset Flow implementieren.
- [ ] OAuth-Provider-Liste laden.
- [x] Passwort-Reset Flow implementieren.
- [x] 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.
Stand 2026-07-09:
- Eine zentrale `ApiResult`/`NetworkError`-Basis ist angelegt.
- Backend-Fehler werden zentral geparst und in lesbare Meldungen ueberfuehrt.
- Timeout- und Retry-Policy sind als feste Netzwerk-Defaults definiert.
- Debug-Logging laeuft nur ausserhalb von Release.
- Multipart- und Download-Helfer sind vorhanden.
- Ein MockWebServer-Test prueft den Auth-Header-Interceptor.
- Ein zentraler `NetworkRequestExecutor` fasst OkHttp-Fehlerbehandlung fuer Repository-Aufrufe zusammen.
- [x] Zentrale `ApiResult`/`NetworkError` Struktur definieren.
- [x] Fehlercodes und Backend-Fehlerformate erfassen.
- [x] Retry-Policy definieren.
- [x] Timeout-Policy definieren.
- [x] Request Logging nur fuer Debug aktivieren.
- [x] Auth Header Tests mit MockWebServer schreiben.
- [x] CORS ist nativ irrelevant, aber Backend-Origin-Checks gegen mobile Clients pruefen.
- [x] Multipart Upload Helper bauen.
- [x] Download Helper fuer Bilder/Dateien bauen.
- [x] Pagination Pattern definieren.
- [x] 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.
Stand 2026-07-09:
- Ein zentraler Preferences-Store fuer UI-Sprache und Feature-Flags ist angelegt.
- Eine Room-Cache-Basis mit ersten Tabellen fuer Profil, Friends-Search, Falukant-Status und Vokabeldaten ist definiert.
- Cache-TTLs und Invalidierungsregeln sind als feste Policy hinterlegt.
- Die MVP-Entscheidung lautet: Offline-Anzeige statt Offline-First.
- Outbox/Offline-Write-Queues werden im MVP nur geplant, nicht erzwungen.
- [x] DataStore fuer UI-Sprache verwenden.
- [x] DataStore fuer Feature Flags verwenden.
- [x] Room Schema fuer User/Profile Cache definieren.
- [x] Room Schema fuer Friends/Search Cache definieren.
- [x] Room Schema fuer Falukant Status light definieren.
- [x] Room Schema fuer Vocab Course/Lesson Cache definieren.
- [x] Cache-Invalidation Regeln definieren.
- [x] Offline-Anzeige statt Offline-First fuer MVP festlegen.
- [x] 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.
Stand 2026-07-09:
- Socket.IO ist als Backend-Realtime-Transport in die native App eingebunden.
- Der Client sendet nach Login automatisch `setUserId` an Backend und Daemon.
- App-Foreground/Background koppelt die Verbindung an den Lifecycle.
- Backend- und Daemon-Status sind in der Shell sichtbar.
- Der Daemon-WebSocket-Client ist technisch angebunden.
- Realtime-Event-Basis und Daemon-Message-Parser sind vorhanden.
- Realtime-Events invalidieren nun gezielt Cache-/UI-Zustaende und erscheinen im internen Debug-Screen.
- [x] Socket.IO Android Client evaluieren.
- [x] Verbindung nach Login aufbauen.
- [x] `setUserId` nach Verbindungsaufbau senden.
- [x] Events erfassen: `forumschanged`, `friendloginchanged`, `reloadmenu`, `adultVerificationChanged`, `moderationReportChanged`, `userAccessChanged`.
- [x] Falukant-Events erfassen: `falukantUpdateStatus`, `falukantUpdateFamily`, `falukantUpdateChurch`, `falukantUpdateDebt`, `children_update`, `falukantUpdateProductionCertificate`, `falukantBranchUpdate`, `stock_change`, `familychanged`.
- [x] Socket Lifecycle an App Foreground/Background koppeln.
- [x] Reconnect Policy definieren.
- [x] Daemon-WebSocket Client implementieren.
- [x] Daemon-Message Parsing robust gegen unbekannte Events machen.
- [x] Realtime Events in Repositories einspeisen.
- [x] UI-State bei Events gezielt invalidieren.
- [x] 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.
Stand 2026-07-09:
- Die nicht eingeloggte Startseite ist als native Landing/Auth-Kombination umgesetzt.
- Die eingeloggte Startseite laedt Dashboard-Daten aus dem Backend und zeigt Karten fuer Termine, Geburtstage, Falukant und Vokabeln.
- Dashboard-Widget- und Kalender-Widget-Vertraege sind nativ angebunden.
- Backend-/Daemon-Status bleibt als kompakte Info sichtbar.
- [x] Home API-Vertraege erfassen.
- [x] Eingeloggt/Nicht-eingeloggt Home getrennt modellieren.
- [x] Native Startseite fuer nicht eingeloggte Nutzer bauen.
- [x] Native Startseite fuer eingeloggte Nutzer bauen.
- [x] Dashboard Widget API-Vertraege erfassen.
- [x] Termine/Upcoming Events als native Cards umsetzen.
- [x] Falukant Kurzstatus als native Card umsetzen.
- [x] 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.
- [x] Settings API-Vertraege erfassen: `/api/settings/filter`, `/api/settings/update`, `/api/settings/account`, `/api/settings/set-account`, `/api/settings/visibilities`.
- [x] Spracheinstellung nativ implementieren.
- [x] Account-Basisdaten nativ implementieren.
- [x] Sichtbarkeitseinstellungen modellieren.
- [x] Personal/View/Sexuality/Flirt Settings priorisieren.
- [x] Interessen-Settings implementieren.
- [x] Language Assistant Settings bewerten.
- [x] 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.
- Stand 2026-07-09:
- Friends, Benutzersuche, Profil-Light und Gästebuch-Light sind nativ angebunden.
- Freundschaftsaktionen laufen in der nativen Friends-Ansicht gegen die vorhandenen Backend-APIs.
- Profilfelder werden inklusive Backend-Visibility-Regeln angezeigt.
- Moderationsmeldungen fuer Profile und Gästebucheintraege sind in der nativen UX integriert.
- [x] Friends API-Vertraege erfassen.
- [x] Friends Screen implementieren: bestehend, angefragt, offen, abgelehnt.
- [x] User Search API-Vertraege erfassen.
- [x] User Search Screen implementieren.
- [x] User Profile API-Vertraege erfassen.
- [x] Profile Light Screen implementieren.
- [x] Guestbook API-Vertraege erfassen.
- [x] Guestbook light implementieren.
- [x] Friend Request Aktionen implementieren.
- [x] Blockieren/Melden UX fuer Store-Compliance planen.
- [x] 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.
Stand 2026-07-09:
- Der nativen MVP-Schnitt fuer Chat ist begonnen.
- Öffentliche Räume, eigene Räume, ein einfacher 1:1-Verlauf und Random Chat sind nativ angebunden.
- Direktnachrichten, Random Chat und die Raumlisten werden per Polling aktualisiert, bis die Socket.IO-Paritaet fuer den Chat folgt.
- Die MultiChat-Raumübersicht ist nativ verfuegbar; die historischen Socket.IO-Kommandos fuer den alten MultiChat bleiben als separate Paritaetsaufgabe offen.
- Direktnachrichten koennen gesendet und gemeldet werden.
- Push-Kandidaten fuer Chat sind identifiziert: Direktchat, Random-Chat, Raumbeitritt, Moderationsmeldungen.
- Socket.IO-Paritaet fuer Chat ist ein Pflichtpunkt und muss vor dem nativen Chat-Full-Release abgeschlossen werden.
- [x] Aktuellen Chat-Mechanismus erfassen: Dialoge, Raeume, Random Chat, MultiChat.
- [x] Chat Backend-/WebSocket-Vertraege dokumentieren.
- [x] Chat Room Liste implementieren.
- [x] 1:1 Chat MVP implementieren.
- [x] MultiChat MVP implementieren oder bewusst verschieben.
- [x] RandomChat bewusst verschieben oder implementieren.
- [x] Message Input mit Keyboard-Verhalten testen.
- [x] Neue Nachrichten per Realtime anzeigen.
- [x] Push-Kandidaten fuer Chat definieren.
- [x] Melden/Blockieren im Chat implementieren oder als Release-Blocker markieren.
- [ ] Socket.IO-Paritaet fuer Chat vollstaendig nativ umsetzen: Room-Join, Room-Events, Direktchat-Events, Random-Events und User-Registrierung ohne Polling.
### 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.
Stand 2026-07-10:
- Die Galerie wird als nativer Social-Unterbereich aufgebaut.
- Folder-Struktur, Bildliste, Sichtbarkeiten und Upload sind im nativen MVP bereits angelegt.
- Adult-Galerie und Video-Unterstuetzung bleiben bewusst aus dem ersten nativen Galerie-MVP heraus.
- [x] Galerie API-Vertraege erfassen.
- [x] Folder-Struktur nativ modellieren.
- [x] Bildliste mit Coil implementieren.
- [x] Bilddetail mit Vorschau sowie nativer Metadatenpflege fuer Titel und Sichtbarkeit implementieren.
- [x] Android Photo Picker fuer Upload implementieren.
- [x] Multipart Upload gegen den Backend-Vertrag automatisiert testen.
- [x] Bildbearbeitung aus Web-App bewerten: MVP nein. Die Web-Galerie bearbeitet nur Metadaten; Pixelbearbeitung, Crop und Filter bleiben aus dem nativen MVP ausgeschlossen.
- [x] Sichtbarkeiten laden und setzen.
- [x] Adult-Galerie aus MVP ausschliessen oder Compliance-Aufwand planen.
- [x] 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.
Stand 2026-07-10:
- Forum, Themenliste und Themenansicht sind nativ als Social-Unterbereich umgesetzt.
- Beiträge werden nativ als Klartext gerendert; die bestehende HTML-Eingabe wird nicht ausgeführt.
- `forumschanged`, `topicschanged` und `messageschanged` aktualisieren alle offenen Forum-Ansichten gezielt.
- [x] Forum-Liste API-Vertrag erfassen.
- [x] Topic-Liste API-Vertrag erfassen.
- [x] Topic-Detail API-Vertrag erfassen.
- [x] Forum-Liste native umsetzen.
- [x] Topic-Liste native umsetzen.
- [x] Topic-Detail native umsetzen.
- [x] Antwort erstellen implementieren.
- [x] Moderation Report fuer Forum implementieren.
- [x] 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.
Stand 2026-07-10:
- Der native Falukant-MVP ist eine Read-only-Spielstandszentrale: Übersicht, Status, Filialen, Bank, Familie und Nachrichten.
- Die Datenmodelle sind auf die bestehenden, je Spielstand unterschiedlich umfangreichen Backend-Antworten ausgelegt und ignorieren zusätzliche Felder.
- Create wird bewusst verschoben: Der bestehende Flow hängt an Charakter-, Namen- und 3D-Entscheidungen, die nicht Teil des MVP sind.
- [x] Falukant API-Endpunkte aus Web-App inventarisieren.
- [x] `StatusBar` Datenmodell nativ definieren.
- [x] Overview Screen implementieren.
- [x] Character/Familien-Basisdaten implementieren.
- [x] Branch-Liste implementieren.
- [x] Branch-Detail light implementieren.
- [x] Bank light implementieren.
- [x] Messages/Notifications light implementieren.
- [x] Realtime Falukant Events integrieren.
- [x] Create Falukant Flow bewusst verschieben.
- [x] Family View light implementieren.
- [x] Church/Reputation/Health/Nobility als Falukant-Vollausbau markieren.
- [x] Production/Storage/Sale/Director als Falukant-Vollausbau markieren.
- [x] Karten-/Regionen-Features als Falukant-Vollausbau 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.
Stand 2026-07-10:
- Der Wirtschaftsblock ist begonnen: Filialdetails laden Produktion, Lager, Inventar, Director, Fahrzeuge und laufende Transporte.
- Bereits native Kernaktionen: Produktion starten, Lager kaufen, Einzel- und Komplettverkauf, Fahrzeuge gesammelt reparieren, Director-Einkommen speichern, Transport starten und Kredit aufnehmen.
- Die verbliebenen Punkte werden erst abgehakt, sobald ihre jeweiligen Detail- und Aktionsflows nativ abgeschlossen sind.
#### 16.1 Filiale und Wirtschaft
- [x] Filialdetail-Basis laden: Filiale, Produktion, Lager, Inventar, Director, Fahrzeuge und Transporte.
- [x] Produktion starten implementieren.
- [x] Lagerkapazität kaufen implementieren.
- [x] Einzelverkauf implementieren.
- [x] Gesamtes Inventar verkaufen implementieren.
- [x] Fahrzeuge gesammelt reparieren implementieren.
- [x] Director-Einkommen speichern implementieren.
- [x] Transport starten implementieren.
- [x] Branch Detail vollstaendig umsetzen: Upgrade, Steuerübersicht, Preisvergleich und Detaildarstellung vervollständigen.
- [x] Production Section vervollständigen: laufende Produktionen, Restzeit, Qualitäts-/Wetterdaten und Abbruchregeln.
- [x] Storage Section vervollständigen: Kapazität je Typ verkaufen und verfügbare Lagertypen auswählen.
- [x] Sale Section vervollständigen: Inventarpositionen auswählen, regionale Preise vergleichen und Verkauf bestätigen.
- [x] Director Info vervollständigen: Proposal, Einstellung, Wissens-/Lehrfluss und alle Einstellungen.
- [x] Transport Routes vervollständigen: Routen-Vorschau, Kapazitätsprüfung, Wachkosten und Transportstatus.
#### 16.2 Bank und Historie
- [x] Bankübersicht und aktive Kredite laden.
- [x] Kreditaufnahme implementieren.
- [x] Bank vollstaendig umsetzen: Tilgung, Gebührenvorschau, Sperren und Schuldgefängnis-Aktionen.
- [x] Money History umsetzen: Filter, Pagination und Graphdaten.
#### 16.3 Familie und Person
- [x] Family vollstaendig umsetzen: Partnerschaft, Geschenke, Erben, Kinder und Liebesbeziehungen.
- [x] Health umsetzen: Gesundheitsstatus und Aktivitäten mit Cooldown.
- [x] Reputation umsetzen: Aktionen, Partys und Fortschritt.
- [x] Church umsetzen: Taufe, Ämter, Bewerbungen und Entscheidungen.
- [x] Nobility umsetzen: Stand, Voraussetzungen und Aufstieg.
- [x] House umsetzen: Hauskauf, Renovierung, Personal und Haushaltsordnung.
- [x] Education umsetzen: Lernende, Inhalte und Schulaktionen.
#### 16.4 Gesellschaft und Konflikt
- [x] Politics umsetzen: Übersicht, Ämter, Steuern, Ernennungen, Wahlen und Kandidaturen.
- [x] Underground umsetzen: Aktivitäten, Ziele, Angriffe und Raid-Regionen.
#### 16.5 Qualität
- [x] 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.
- [x] Vocab Languages API-Vertrag erfassen.
- [x] Course List API-Vertrag erfassen.
- [x] Course Detail API-Vertrag erfassen.
- [x] Lesson API-Vertrag erfassen.
- [x] Review API-Vertrag erfassen.
- [x] Vocab Landing native umsetzen.
- [x] Course List native umsetzen.
- [x] Course Detail native umsetzen.
- [x] Lesson Player MVP implementieren.
- [x] Lesson Review implementieren.
- [x] Dictionary light implementieren.
- [x] Progress/Completion speichern.
- [x] Keyboard-/Audio-/Touch-Verhalten testen.
- [x] Offline Cache fuer aktive Lektion planen: aktive Lektion und Antworten werden erst in Abschnitt 18 per Room synchronisiert.
### 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.
- [x] Neue Sprache anlegen implementieren.
- [x] Subscribe Flow implementieren.
- [x] Chapter View implementieren.
- [x] Dictionary vollstaendig implementieren.
- [x] Practice Dialog nativ ersetzen.
- [x] SRS-/Review-Logik gegen Backend validieren.
- [x] Offline Lesson Cache implementieren.
- [x] Sync-Konflikte definieren.
Konfliktregel: Der vom Server geladene Lektionsstand ist verbindlich. Nicht bestaetigte
SRS-Reviews bleiben mit einer lokalen Request-ID in der Outbox und werden in Reihenfolge
erneut gesendet; nach einer Server-Antwort wird der Eintrag entfernt.
### 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.
- [x] Calendar API-Vertraege erfassen.
- [x] Monats-/Wochen-/Listenansicht entscheiden.
- [x] Termine laden.
- [x] Termin erstellen.
- [x] Termin bearbeiten.
- [x] Termin loeschen.
- [x] Date/Time Picker nativ einsetzen.
- [x] Reminder/Push spaeter planen.
- [x] Diary API-Vertrag erfassen.
- [x] Diary light umsetzen oder verschieben.
Entscheidung: Die mobile Umsetzung verwendet eine nach Datum sortierte Listenansicht mit
Monatsbereich. Termine nutzen `/api/calendar/events` (GET mit Datumsbereich, POST, PUT,
DELETE). Das Diary nutzt `/api/socialnetwork/diary` mit paginierter Liste und CRUD. Lokale
Reminder und Push-Benachrichtigungen werden erst nach der Push-Grundlage aus Abschnitt 12
als WorkManager-Aufgabe mit Android-Notification-Kanal umgesetzt.
### 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.
- [x] Blog List API-Vertrag erfassen.
- [x] Blog Detail API-Vertrag erfassen.
- [x] Guide List API-Vertrag erfassen.
- [x] Guide Detail API-Vertrag erfassen.
- [x] Public Landing Screens nativ priorisieren oder aus App entfernen.
- [x] Rich Text Rendering nativ loesen.
- [x] Blog Editor aus MVP ausschliessen.
- [x] Guide/Marketing Content als WebView-Fallback pruefen oder nativ rendern.
- [x] News/Blog/Guide Kurzlisten bewerten.
Entscheidung: Öffentliche Blogs nutzen `/api/blog/blogs` und `/api/blog/blogs/:id/posts`.
Ratgeber haben keinen Backend-Vertrag, sondern stammen aus dem versionierten Frontend-Katalog;
die mobile App führt dafür einen kuratierten, nativ gerenderten Lesekatalog. HTML aus
Blogbeiträgen wird als sicherer Text ohne WebView gerendert. Der Blog-Editor bleibt im Web.
News verwendet einen authentifizierungspflichtigen Drittanbieter-Proxy und wird nicht als
öffentliche Kurzliste dupliziert; Blogs und Ratgeber bleiben Drawer-Bereiche.
### 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.
#### 21.1 Match3
- [x] Match3 Game als native Compose/Canvas Machbarkeit pruefen.
- [x] Spielbrett, Tile-Modell und Zuglogik definieren.
- [x] Touch-Steuerung fuer Auswahl und Tausch definieren.
- [x] Animationen und Aufloesung von Matches definieren.
- [x] Score-/Leaderboard-API-Vertraege fuer Match3 erfassen.
- [ ] Performance auf Emulator und echtem Geraet testen. In eine spaetere gemeinsame QA-Runde verschoben.
Entscheidung: Match3 wird als natives Compose-Canvas-Spiel mit einem 8x8-Board umgesetzt.
Ein Zug besteht aus zwei Tap-Eingaben auf benachbarte Steine. Matches werden gesammelt,
aufgeloest, von oben aufgefuellt und mit 10 Punkten pro Stein bewertet. Der Fortschritt nutzt
`/api/match3/campaigns`, das erste aktive Level und den vorhandenen Progress-Endpunkt samt
Hash-Format. Admin-Routen bleiben ausgeschlossen.
#### 21.2 Taxi
- [x] Taxi Game als native Canvas/OpenGL Machbarkeit pruefen.
- [x] Spielfeld, Fahrzeugzustand und Fahrphysik definieren.
- [x] Touch-Steuerung fuer Lenken, Beschleunigen und Bremsen definieren.
- [x] Auftrags-, Ziel- und Kollisionslogik definieren.
- [x] Score-/Leaderboard-API-Vertraege fuer Taxi erfassen.
- [ ] Performance auf Emulator und echtem Geraet testen. In eine spaetere gemeinsame QA-Runde verschoben.
Entscheidung: Taxi wird als natives Compose-Canvas-Spiel umgesetzt. Vier Touch-Schaltflächen
steuern Lenken, Beschleunigen und Bremsen. Ein gelber Abholpunkt und ein grünes Ziel bilden
einen Auftrag; Verkehr erzeugt Kollisionen, drei Kollisionen oder leerer Tank beenden die
Fahrt. Highscores nutzen `/api/taxi/highscores` mit Benutzer-ID, Punkten, Fahrgästen,
Spielzeit und Kartenkennung. OpenGL ist für diese 2D-Strecke nicht erforderlich.
#### 21.3 Gemeinsame Integration
- [x] WebView-Fallback fuer Minigames als Zwischenloesung bewerten.
- [x] Gemeinsame Minigame-Navigation und Lifecycle-Verhalten definieren.
- [x] Gemeinsames Persistenz- und Abbruchverhalten definieren.
- [x] Admin-Tools fuer Minigames aus nativer App ausschliessen.
Entscheidung: Es gibt keinen WebView-Fallback. Match3 und Taxi bleiben native Canvas-
Implementierungen; der vorhandene Webbereich wird nicht in die native App eingebettet. Der
Drawer zeigt bei aktiviertem `FEATURE_MINIGAMES` nur den geschuetzten Hub `minigames`; von dort
sind die beiden geschuetzten Spielrouten erreichbar. Spielschleifen sind an die Composition
gebunden und werden beim Verlassen automatisch beendet. Match3 speichert nur abgeschlossene
Level ueber den vorhandenen Progress-Endpunkt. Taxi speichert beim Verlassen einer laufenden
Fahrt einen Zwischenstand ueber `/api/taxi/game-state`; abgeschlossene Fahrten werden als
Highscore gespeichert. Admin- und Verwaltungsrouten fuer Minigames werden nicht registriert und
bleiben ausschliesslich im Web-Adminbereich.
### 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.
- [x] Entscheiden, ob Admin ueberhaupt in native App gehoert. - Ja, Admin gehört in die native App
- [x] Admin Users API-Vertraege erfassen.
- [x] Admin Rights API-Vertraege erfassen.
- [x] Moderation Reports API-Vertraege erfassen.
- [x] Adult Verification API-Vertraege erfassen.
- [x] Erotic Moderation API-Vertraege erfassen.
- [x] Forum Admin API-Vertraege erfassen.
- [x] Falukant Admin API-Vertraege erfassen.
- [x] Services Status Screen fuer interne Builds planen.
- [x] Admin nur per Feature Flag und Rollencheck sichtbar machen.
Entscheidung: Die native Administration wird nur eingeblendet, wenn sowohl
`FEATURE_ADMIN` aktiviert ist als auch die authentifizierte Anfrage an
`GET /api/navigation/:userid` einen Bereich `administration` liefert. Die vom Backend
gefilterte Navigation ist die Rechtequelle; die serverseitige Berechtigungsprüfung jeder
Admin-Route bleibt verbindlich. Direkte Navigation ohne beide Bedingungen zeigt keinen Inhalt.
API-Vertraege:
- Benutzer: `GET /api/admin/users/search?q=`, `GET /api/admin/users/:id`, `PUT /api/admin/users/:id`, `GET /api/admin/users/batch?ids=`, `GET /api/admin/users/statistics`; alle erfordern die vom Service gepruefte Berechtigung `useradministration` bzw. `mainadmin`.
- Rechte: `GET /api/admin/rights/types`, `GET /api/admin/rights/:id`, `POST /api/admin/rights/:id` und `DELETE /api/admin/rights/:id` mit `{ rightTypeId }`; Berechtigung `rights` bzw. `mainadmin`.
- Moderationsmeldungen: `GET /api/admin/moderation/reports?status=&limit=` sowie `POST /api/admin/moderation/reports/:reportId/status` mit Status und Review-Notiz; Berechtigung `forum` bzw. `mainadmin`.
- Altersverifikation: `GET /api/admin/users/adult-verification?status=`, `PUT /api/admin/users/:id/adult-verification` mit `approved`, `rejected` oder `pending`, sowie der geschuetzte Dokument-Download `GET /api/admin/users/:id/adult-verification/document`.
- Erotikmoderation: `GET /api/admin/users/erotic-moderation?status=`, geschuetzte Vorschau unter `/preview/:type/:targetId` und `PUT /api/admin/users/erotic-moderation/:id` mit erlaubter Aktion und optionaler Notiz.
- Forum: `GET` und `POST /api/forum/`, `DELETE /api/forum/:forumId`; Erstellen erwartet `{ name, permissions }`, die Service-Schicht prueft `forum` bzw. `mainadmin`. Allgemeine Meldungen laufen ueber den Moderationsvertrag.
- Falukant: Die geschuetzten Werkzeuge liegen unter `/api/admin/falukant/*`: Benutzersuche/-bearbeitung, Familien- und Schwangerschaftsaktionen, Bestands-/Region-/Distanzpflege, NPC-Auftraege und Titel. Die native Umsetzung beschraenkt sich auf klar abgegrenzte Fach-Screens mit serverseitiger `falukant`-/`mainadmin`-Pruefung; keine generische Datenbankbearbeitung.
Service-Status: Nur interne Debug-Builds erhalten einen kompakten, rein lesenden Statusscreen
auf Basis der bereits vorhandenen Backend-/Daemon-Verbindungssignale. Keine Prozessdaten,
Tokens, Konfigurationen oder Diagnose-Endpunkte werden in Release-Builds angezeigt. Die
Match3-/Taxi-Adminwerkzeuge bleiben gemaess Abschnitt 21 ausserhalb der nativen App.
### 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.
- [x] Adult Content aus MVP entfernen oder per Feature Flag deaktivieren.
- [x] Altersverifikation nativ modellieren.
- [x] UGC-Melden nativ in Chat, Galerie, Forum, Profil implementieren.
- [x] Blockieren nativ implementieren.
- [x] Moderationserreichbarkeit dokumentieren.
- [x] Datenschutzseite nativ erreichbar machen.
- [x] Impressum nativ erreichbar machen.
- [x] Kontakt nativ erreichbar machen.
- [x] Account-Loeschung oder klare Anleitung nativ erreichbar machen.
- [x] Play Store Content Rating vorbereiten.
- [x] Store-Review-Risiko fuer Adult Content separat entscheiden.
Stand 2026-07-16: Der geschuetzte Bereich ist im lokalen Debug-Build per `FEATURE_ADULT`
aktiviert; Staging und Production bleiben bis zur Store-Entscheidung deaktiviert. Die native App
laedt den Status ueber `/api/settings/account` und laedt erst nach lokaler Pruefung von
Volljaehrigkeit und `adultAccessEnabled` die serverseitig ebenfalls geschuetzten Endpunkte unter
`/api/socialnetwork/erotic/*`. Ein Verifikationsnachweis (JPEG, PNG, WebP oder PDF) wird per
Android-Dateiauswahl an `/api/settings/adult-verification/request` gesendet. Die API prueft
zusaetzlich Alter und Verifikationsstatus. Die Account-Endpunkte weisen nun ausserdem Anfragen
ab, deren Body-`userId` nicht der authentifizierten `userid` entspricht.
Blockieren verwendet den neuen serverseitigen Vertrag `POST`/`DELETE
/api/socialnetwork/blocked-users/:userId` und die Migration
`20260716000000-create-user-block.sql`; der Profil-Screen bietet die Blockaktion nativ an.
Die Store-Entscheidung und Rating-Vorbereitung sind in `android/STORE_COMPLIANCE.md`
dokumentiert: Der Bereich bleibt ausserhalb lokaler Debug-Builds deaktiviert, bis eine formelle
Store- und Altersfreigabe vorliegt.
### 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.
- [x] Firebase Projekt klaeren.
- [x] FCM in native App integrieren.
- [x] Device Token Backend-Modell planen.
- [x] Device Token Registration API definieren.
- [x] Opt-in UI implementieren.
- [x] Notification Settings implementieren.
- [x] Chat Push definieren.
- [x] Friend Login Push definieren.
- [x] Falukant Event Push definieren.
- [x] Vocab Reminder Push definieren.
- [x] Deep Links aus Notifications implementieren.
- [x] Token Refresh Handling implementieren.
- [ ] Firebase-Service-Account im Backend-Deployment hinterlegen (`FIREBASE_SERVICE_ACCOUNT_PATH` oder `FIREBASE_SERVICE_ACCOUNT_JSON`).
### 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.
- [x] App Links Domain festlegen.
- [x] `assetlinks.json` planen.
- [x] Deep-Link-Struktur fuer Auth, Home, Social, Falukant, Vocab, Settings und Public Content definieren.
- [x] OAuth Redirect URIs fuer Android planen.
- [x] Custom Tabs Flow implementieren.
- [x] OAuth Callback Handling implementieren.
- [x] Deep Links fuer Profile, Forum, Falukant, Vocab, Blog definieren.
- [x] Deep Link Auth Guard implementieren.
- [x] 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.
- [x] Authdaten nicht im Klartext speichern.
- [x] Release Logging sensibler Daten verhindern.
- [x] Certificate Pinning bewerten, nicht vorschnell erzwingen.
- [x] Network Security Config fuer Release restriktiv halten.
- [x] Root/Jailbreak Detection bewusst entscheiden.
- [x] Screenshot-Schutz fuer Adult/Private Bereiche bewerten.
- [x] Datei-Uploads auf MIME/Größe pruefen.
- [x] WebView-Fallbacks minimieren.
- [x] 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.
- [x] Unit Tests fuer Auth Repository.
- [x] Unit Tests fuer Settings Repository.
- [x] Unit Tests fuer Error Mapping.
- [x] MockWebServer Tests fuer Auth Header.
- [x] MockWebServer Tests fuer API-Fehler.
- [x] Room Migration Tests.
- [x] Compose Tests fuer Login.
- [x] Compose Tests fuer Navigation.
- [x] Compose Tests fuer Home.
- [x] Compose Tests fuer Vocab Lesson.
- [x] Realtime Tests mit Testserver planen.
- [x] Emulator-Testmatrix definieren: kleines Phone, grosses Phone, Tablet.
- [x] Echtes Android-Geraet in Testmatrix aufnehmen.
- [x] Offline/Online-Wechsel testen.
- [x] App Kill/Restart/Resume testen.
- [ ] Instrumentation-Suite auf einem verbundenen Geraet oder KVM-faehigen Host ausfuehren (lokal blockiert: kein ADB-Geraet, keine x86_64-Hardwarebeschleunigung).
### 28. Build, Release und Betrieb
@@ -593,6 +824,8 @@ Stand 2026-07-09:
### 29. Backend-Vorbereitung fuer Native
- [ ] Release-Signaturfingerprint in die ausgelieferte `/.well-known/assetlinks.json` eintragen.
- [ ] Native OAuth-Redirect-URI bei jedem aktivierten Provider hinterlegen.
- [ ] Mobile API-Inventar aus allen Web-Komponenten erstellen.
- [ ] API-Versionierung bewerten: `/api/mobile/v1` ja/nein.
- [ ] Einheitliches Fehlerformat definieren.

0
android/README.md Normal file → Executable file
View File

37
android/SECURITY.md Normal file
View File

@@ -0,0 +1,37 @@
# Native Android Security
## Umgesetzte Schutzmaßnahmen
- Die Sitzung liegt ausschließlich in `EncryptedSharedPreferences` mit Android-Master-Key.
- Release-Builds enthalten keinen HTTP-Body-Logger. Der detaillierte OkHttp-Logger ist auf
Nicht-Release-Builds begrenzt.
- Release-Netzwerkverkehr erlaubt kein Cleartext. Nur der lokale Debug-Flavor darf
`10.0.2.2` und `localhost` per HTTP ansprechen.
- Chat, Galerie, Persönliches und der Adult-Bereich setzen `FLAG_SECURE`. Damit verhindert
Android Screenshots, Bildschirmaufnahmen und die Anzeige im App-Switcher.
- Uploads werden vor dem Service auf einen erlaubten MIME-Typ und eine Größe begrenzt:
Bilder/Verifikationsnachweise 10 MiB, Videos 100 MiB. Bilder werden zusätzlich durch
Sharp dekodiert, damit ein behaupteter MIME-Typ nicht genügt.
## Bewusste Entscheidungen
### Certificate Pinning
Certificate Pinning wird aktuell **nicht** erzwungen. Die API verwendet HTTPS und die
plattformseitige Trust-Store-Prüfung. Pinning würde bei Zertifikats- oder CDN-Wechseln ohne
App-Update zu vollständigen Ausfällen führen. Es wird erst eingeführt, wenn es mindestens zwei
parallel gültige Pins, ein dokumentiertes Rotation-Verfahren und Monitoring für Pin-Fehler gibt.
### Root- und Bootloader-Erkennung
Die App blockiert gerootete Geräte nicht. Eine lokale Erkennung ist umgehbar und würde legitime
Nutzer sowie Emulator-Tests ausschließen. Sensible Daten bleiben verschlüsselt, Screenshots in
sensiblen Bereichen sind gesperrt und Berechtigungen werden auf dem Server durchgesetzt.
Play Integrity wird bei späteren Hochrisiko-Aktionen als serverseitig prüfbares Signal bewertet,
nicht als pauschale Startblockade.
## Dependency Scanning
`.github/workflows/android-security.yml` führt bei Pull Requests und Pushes einen
OSV-Abhängigkeitsscan sowie Android-Lint für den Produktions-Release aus. Kritische Findings
werden vor einem Release bewertet.

View File

@@ -0,0 +1,17 @@
# Store-Compliance
## Adult Content
- `FEATURE_ADULT` ist nur im lokalen Debug-Build aktiv.
- Staging und Production liefern keinen nativen Adult-Bereich aus.
- Vor einer Aktivierung sind Play-Content-Rating, Altersklassifizierung, Moderationsprozess,
Meldewege und die Store-Richtlinien erneut zu pruefen und freizugeben.
- Die API bleibt auch bei aktivem Client-Feature die Autoritaet: Volljaehrigkeit und der Status
`approved` der Altersverifikation sind fuer jeden geschuetzten Endpunkt erforderlich.
## UGC und Moderation
- Native Meldungen existieren fuer Chat, Forum, Profile, Gaestebuch und Galerie.
- Meldungen werden serverseitig gespeichert und sind fuer berechtigte Moderatoren sichtbar.
- Nutzerblockaden werden serverseitig in `community.user_block` gespeichert; die SQL-Migration
`backend/migrations/20260716000000-create-user-block.sql` ist vor dem Rollout auszufuehren.

45
android/TESTING.md Normal file
View File

@@ -0,0 +1,45 @@
# Native Android Testmatrix
## Automatisiert
| Bereich | Testart | Ausführung |
| --- | --- | --- |
| Auth, Settings, HTTP-Fehler, Header, Daemon-Parser | JVM + MockWebServer | `./gradlew :app:testLocalDebugUnitTest` |
| Room-Migration und verschlüsselte Session nach Store-Neuerzeugung | Instrumentation | `./gradlew :app:connectedLocalDebugAndroidTest` |
| Login, Navigation, Home und Vokabel-Lektion | Compose Instrumentation | `./gradlew :app:connectedLocalDebugAndroidTest` |
| Realtime | JVM-Parser plus manueller Socket.IO-Testserver-Plan | siehe unten |
### Lokaler Ausfuehrungsstatus
- Die JVM-Suite (`:app:testLocalDebugUnitTest`) ist erfolgreich ausgefuehrt.
- Die Instrumentation-Suite inklusive Room- und Compose-Tests kompiliert erfolgreich.
- Die Ausfuehrung auf diesem Host ist blockiert: Es ist kein ADB-Geraet verbunden und die
x86_64-Emulatoren benoetigen KVM-Hardwarebeschleunigung, die hier nicht verfuegbar ist.
Das vorhandene ARM64-System-Image kann auf einem x86_64-Host nicht emuliert werden.
- Auf einem Host mit KVM oder einem verbundenen Geraet wird die Suite mit
`./gradlew :app:connectedLocalDebugAndroidTest` ausgefuehrt. Der CI-Workflow
`.github/workflows/android-tests.yml` fuehrt dieselbe Suite auf einem GitHub-Emulator aus.
## Emulator- und Geräte-Matrix
| Ziel | Pflichtfälle |
| --- | --- |
| Kleines Phone, API 34+ | Login, Navigation, Formular, Tastatur, Adult-Screenshotschutz |
| Großes Phone, API 34+ | Galerie, Falukant und Vokabel-Lektion |
| Tablet, API 34+ | Drawer, Landscape und Listenbreiten |
| Reales Android-Gerät, aktuelle API | Push-Berechtigung, OAuth Custom Tab, App Links, Kamera/Dateiauswahl |
Die Gradle Managed Devices `mediumPhone` und `mediumTablet` decken die CI-Basis ab. Das lokale
Team ergänzt für jeden Release-Lauf die installierten kleinen/großen Emulatoren und mindestens
ein reales Gerät.
## Netzwerk, Realtime und Lifecycle
1. Backend und Daemon starten, mit einem Testkonto anmelden und Socket.IO-Verbindung prüfen.
2. Backend stoppen: Offline-Banner, verständlicher Fehler und keine blockierte Navigation prüfen.
3. Backend wieder starten: Screen aktualisieren und Realtime-Verbindung erneut prüfen.
4. App im Hintergrund beenden und über Launcher oder Push erneut öffnen: verschlüsselte Sitzung,
Deep-Link-Fortsetzung und Realtime-Reconnect prüfen.
5. Für Socket.IO-Regressionen wird ein isolierter Node-Testserver mit den Ereignissen
`friendloginchanged`, `falukantUpdateStatus`, `familychanged` und `reloadmenu` verwendet.
Der Android-Test verbindet sich mit dessen URL statt mit Production.

0
android/android/.idea/AndroidProjectSystem.xml generated Normal file → Executable file
View File

6
android/android/.idea/compiler.xml generated Executable file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

4
android/android/.idea/deploymentTargetSelector.xml generated Normal file → Executable file
View File

@@ -6,6 +6,10 @@
<option name="selectionMode" value="DROPDOWN" />
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

0
android/android/.idea/migrations.xml generated Normal file → Executable file
View File

3
android/android/.idea/misc.xml generated Normal file → Executable file
View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

0
android/android/.idea/runConfigurations.xml generated Normal file → Executable file
View File

0
android/android/.idea/runConfigurations/YourPart_Debug.xml generated Normal file → Executable file
View File

0
android/android/app/build.gradle Normal file → Executable file
View File

0
android/android/app/capacitor.build.gradle Normal file → Executable file
View File

0
android/android/app/proguard-rules.pro vendored Normal file → Executable file
View File

0
android/android/app/src/main/AndroidManifest.xml Normal file → Executable file
View File

View File

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

0
android/android/app/src/main/res/drawable/splash.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

View File

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

0
android/android/app/src/main/res/values/strings.xml Normal file → Executable file
View File

0
android/android/app/src/main/res/values/styles.xml Normal file → Executable file
View File

0
android/android/app/src/main/res/xml/file_paths.xml Normal file → Executable file
View File

View File

0
android/android/build.gradle Normal file → Executable file
View File

0
android/android/capacitor.settings.gradle Normal file → Executable file
View File

0
android/android/gradle.properties Normal file → Executable file
View File

0
android/android/gradle/wrapper/gradle-wrapper.jar vendored Normal file → Executable file
View File

0
android/android/gradle/wrapper/gradle-wrapper.properties vendored Normal file → Executable file
View File

0
android/android/gradlew.bat vendored Normal file → Executable file
View File

0
android/android/settings.gradle Normal file → Executable file
View File

0
android/android/variables.gradle Normal file → Executable file
View File

0
android/capacitor.config.ts Normal file → Executable file
View File

6
android/native/.idea/AndroidProjectSystem.xml generated Executable file
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>

2001
android/native/.idea/caches/deviceStreaming.xml generated Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="YourPartNative.app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-07-10T13:18:31.238846181Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/torsten/.config/.android/avd/Medium_Tablet.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

13
android/native/.idea/deviceManager.xml generated Executable 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>

30
android/native/.idea/gradle.xml generated Executable file
View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="/mnt/share/torsten/Programs/YourPart3/android/native" />
<option value="/mnt/share/torsten/Programs/YourPart3/android/native/app" />
</set>
</option>
</GradleProjectSettings>
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="/mnt/share/torsten/Programs/YourPart3/android/native" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="/mnt/share/torsten/Programs/YourPart3/android/native" />
<option value="/mnt/share/torsten/Programs/YourPart3/android/native/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

8
android/native/.idea/markdown.xml generated Executable 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>

10
android/native/.idea/migrations.xml generated Executable 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="/mnt/share/torsten/Programs/YourPart3/android/native" />
</set>
</option>
</component>
</project>

9
android/native/.idea/misc.xml generated Executable file
View File

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

17
android/native/.idea/runConfigurations.xml generated Executable file
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>

7
android/native/.idea/vcs.xml generated Executable file
View File

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

View File

@@ -0,0 +1,76 @@
kotlin version: 2.0.21
error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /mnt/share/torsten/Programs/YourPart3/android/native/app/src/main/java/de/yourpart/nativeapp/MainActivity.kt:24:5: java.lang.IllegalArgumentException: source must not be null
at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: source must not be null
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
... 33 more

View File

@@ -0,0 +1,76 @@
kotlin version: 2.0.21
error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /mnt/share/torsten/Programs/YourPart3/android/native/app/src/main/java/de/yourpart/nativeapp/MainActivity.kt:24:5: java.lang.IllegalArgumentException: source must not be null
at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: source must not be null
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
... 33 more

View File

@@ -0,0 +1,76 @@
kotlin version: 2.0.21
error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing /mnt/share/torsten/Programs/YourPart3/android/native/app/src/main/java/de/yourpart/nativeapp/MainActivity.kt:24:5: java.lang.IllegalArgumentException: source must not be null
at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: source must not be null
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
... 33 more

View File

@@ -0,0 +1,149 @@
kotlin version: 2.2.21
error message: Daemon compilation failed: null
java.lang.Exception
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:236)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:155)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:110)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-attributes.tab, source-to-classes.tab, internal-name-to-source.tab
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:218)
at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55)
at kotlin.io.CloseableKt.closeFinally(Closeable.kt:46)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:128)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:684)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:94)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1810)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720)
... 3 more
Caused by: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-attributes.tab, source-to-classes.tab, internal-name-to-source.tab
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:205)
... 22 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 43 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 44 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 44 more

View File

@@ -0,0 +1,150 @@
kotlin version: 2.2.21
error message: Daemon compilation failed: null
java.lang.Exception
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:236)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:155)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:110)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-attributes.tab, proto.tab
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:218)
at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55)
at kotlin.io.CloseableKt.closeFinally(Closeable.kt:46)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:128)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:684)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:94)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1810)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720)
... 3 more
Caused by: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-attributes.tab, proto.tab
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:205)
... 22 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 43 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 43 more
Suppressed: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/inputs: source-to-output.tab
... 25 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 44 more

View File

@@ -0,0 +1,153 @@
kotlin version: 2.2.21
error message: Daemon compilation failed: null
java.lang.Exception
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:236)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:155)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:110)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-fq-name-to-source.tab, proto.tab
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:218)
at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55)
at kotlin.io.CloseableKt.closeFinally(Closeable.kt:46)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:128)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:684)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:94)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1810)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720)
... 3 more
Caused by: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-fq-name-to-source.tab, proto.tab
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:205)
... 22 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 43 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 43 more
Suppressed: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/lookups: lookups.tab
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.LookupStorage.close(LookupStorage.kt:155)
... 23 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 25 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/compileLocalDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 45 more

View File

@@ -0,0 +1,128 @@
kotlin version: 2.2.21
error message: Daemon compilation failed: null
java.lang.Exception
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:236)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:155)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:110)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:31)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-fq-name-to-source.tab
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:218)
at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55)
at kotlin.io.CloseableKt.closeFinally(Closeable.kt:46)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:128)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:684)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:94)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1810)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:598)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:844)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:721)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:720)
... 3 more
Caused by: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin: class-fq-name-to-source.tab
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:205)
... 22 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 24 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 43 more
Suppressed: java.lang.Exception: Could not close incremental caches in /mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/lookups: lookups.tab
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.LookupStorage.close(LookupStorage.kt:155)
... 23 more
Suppressed: java.lang.IllegalStateException: Storage for [/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab] is already registered
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410)
at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.<init>(PagedFileStorage.java:72)
at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.<init>(ResizeableMappedFile.java:68)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.<init>(PersistentBTreeEnumerator.java:128)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:165)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.<init>(PersistentMapImpl.java:140)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:46)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.<init>(PersistentHashMap.java:72)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:62)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:59)
at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108)
at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179)
at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136)
at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53)
at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87)
... 25 more
Suppressed: java.lang.Exception: Storage[/mnt/share/torsten/Programs/YourPart3/android/native/app/build/kotlin/kaptGenerateStubsLocalDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab] registration stack trace
at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437)
... 45 more

24
android/native/README.md Normal file → Executable file
View File

@@ -13,6 +13,7 @@ Native Android-App fuer YourPart als paralleler Aufbau zur bestehenden Capacitor
- compileSdk/targetSdk: 36
- Flavors: `local`, `staging`, `production`
- Build Types: `debug`, `release`
- Feature Flags im Build: `FEATURE_ADMIN`, `FEATURE_ADULT`, `FEATURE_3D`, `FEATURE_MINIGAMES`, `FEATURE_PUSH`
## Kommandos
@@ -32,3 +33,26 @@ Der `local` Flavor nutzt:
- API: `http://10.0.2.2:2020`
- Socket.IO: `http://10.0.2.2:2020`
- Daemon: `ws://10.0.2.2:2021`
## Security
- Debug erlaubt Cleartext nur fuer `10.0.2.2` und `localhost`.
- Release verbietet Cleartext komplett.
- Release-Builds pruefen automatisch, dass keine lokalen oder unverschluesselten URLs in `staging` oder `production` verwendet werden.
## Firebase Push
1. Die registrierte Produktions-App `de.yourpart.nativeapp` als
`app/google-services.json` ablegen. Die Beispieldatei
`app/google-services.json.example` ist kein gültiger Ersatz.
2. Push ist ausschließlich in `productionRelease` aktiviert. `local` und `staging`
verwenden abweichende Paketnamen und bleiben absichtlich pushfrei, bis dafür eigene
Firebase-Apps registriert sind.
3. Im Backend eine Firebase-Service-Account-Datei außerhalb des Repositories bereitstellen
und `FIREBASE_SERVICE_ACCOUNT_PATH=/sicherer/pfad/firebase-service-account.json`
setzen. Alternativ kann `FIREBASE_SERVICE_ACCOUNT_JSON` mit dem JSON-Inhalt gesetzt
werden. Ohne eine dieser Variablen werden keine Pushes versendet, die App und die API
bleiben aber funktionsfähig.
Das Google-Services-Plugin wird nur für `productionRelease` mit vorhandener echter
Konfigurationsdatei angewendet; lokale Builds bleiben dadurch reproduzierbar.

154
android/native/app/build.gradle.kts Normal file → Executable file
View File

@@ -4,10 +4,20 @@ plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
id("org.jetbrains.kotlin.plugin.serialization")
id("com.google.dagger.hilt.android")
kotlin("kapt")
}
// Only the production release uses the Firebase app registered as de.yourpart.nativeapp.
// Local/staging builds have different application IDs and deliberately stay push-free.
val isProductionReleaseBuild = gradle.startParameter.taskNames.any {
it.contains("productionrelease", ignoreCase = true)
}
if (isProductionReleaseBuild && file("google-services.json").isFile) {
apply(plugin = "com.google.gms.google-services")
}
val gitShaProvider = providers.exec {
workingDir = rootDir.resolve("../..")
commandLine("git", "rev-parse", "--short=12", "HEAD")
@@ -15,6 +25,34 @@ val gitShaProvider = providers.exec {
val gitSha: String = runCatching { gitShaProvider.get() }.getOrDefault("dev")
data class EnvironmentConfig(
val apiBaseUrl: String,
val socketIoUrl: String,
val daemonSocketUrl: String,
val cleartextAllowed: Boolean,
)
val environmentConfigs = mapOf(
"local" to EnvironmentConfig(
apiBaseUrl = "http://10.0.2.2:2020",
socketIoUrl = "http://10.0.2.2:2020",
daemonSocketUrl = "ws://10.0.2.2:2021",
cleartextAllowed = true,
),
"staging" to EnvironmentConfig(
apiBaseUrl = "https://staging.your-part.de",
socketIoUrl = "https://staging.your-part.de",
daemonSocketUrl = "wss://staging.your-part.de",
cleartextAllowed = false,
),
"production" to EnvironmentConfig(
apiBaseUrl = "https://www.your-part.de",
socketIoUrl = "https://www.your-part.de",
daemonSocketUrl = "wss://www.your-part.de",
cleartextAllowed = false,
),
)
android {
namespace = "de.yourpart.nativeapp"
compileSdk = 36
@@ -35,23 +73,32 @@ android {
dimension = "environment"
applicationIdSuffix = ".local"
versionNameSuffix = "-local"
buildConfigField("String", "API_BASE_URL", "\"http://10.0.2.2:2020\"")
buildConfigField("String", "SOCKET_IO_URL", "\"http://10.0.2.2:2020\"")
buildConfigField("String", "DAEMON_SOCKET_URL", "\"ws://10.0.2.2:2021\"")
val cfg = environmentConfigs.getValue(name)
buildConfigField("String", "ENVIRONMENT", "\"$name\"")
buildConfigField("String", "API_BASE_URL", "\"${cfg.apiBaseUrl}\"")
buildConfigField("String", "SOCKET_IO_URL", "\"${cfg.socketIoUrl}\"")
buildConfigField("String", "DAEMON_SOCKET_URL", "\"${cfg.daemonSocketUrl}\"")
buildConfigField("boolean", "ALLOW_CLEARTEXT", cfg.cleartextAllowed.toString())
}
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
buildConfigField("String", "API_BASE_URL", "\"https://staging.your-part.de\"")
buildConfigField("String", "SOCKET_IO_URL", "\"https://staging.your-part.de\"")
buildConfigField("String", "DAEMON_SOCKET_URL", "\"wss://staging.your-part.de\"")
val cfg = environmentConfigs.getValue(name)
buildConfigField("String", "ENVIRONMENT", "\"$name\"")
buildConfigField("String", "API_BASE_URL", "\"${cfg.apiBaseUrl}\"")
buildConfigField("String", "SOCKET_IO_URL", "\"${cfg.socketIoUrl}\"")
buildConfigField("String", "DAEMON_SOCKET_URL", "\"${cfg.daemonSocketUrl}\"")
buildConfigField("boolean", "ALLOW_CLEARTEXT", cfg.cleartextAllowed.toString())
}
create("production") {
dimension = "environment"
buildConfigField("String", "API_BASE_URL", "\"https://www.your-part.de\"")
buildConfigField("String", "SOCKET_IO_URL", "\"https://www.your-part.de\"")
buildConfigField("String", "DAEMON_SOCKET_URL", "\"wss://www.your-part.de\"")
val cfg = environmentConfigs.getValue(name)
buildConfigField("String", "ENVIRONMENT", "\"$name\"")
buildConfigField("String", "API_BASE_URL", "\"${cfg.apiBaseUrl}\"")
buildConfigField("String", "SOCKET_IO_URL", "\"${cfg.socketIoUrl}\"")
buildConfigField("String", "DAEMON_SOCKET_URL", "\"${cfg.daemonSocketUrl}\"")
buildConfigField("boolean", "ALLOW_CLEARTEXT", cfg.cleartextAllowed.toString())
}
}
@@ -59,9 +106,21 @@ android {
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
buildConfigField("boolean", "IS_RELEASE_BUILD", "false")
buildConfigField("boolean", "FEATURE_ADMIN", "false")
buildConfigField("boolean", "FEATURE_ADULT", "true")
buildConfigField("boolean", "FEATURE_3D", "false")
buildConfigField("boolean", "FEATURE_MINIGAMES", "false")
buildConfigField("boolean", "FEATURE_PUSH", "false")
}
release {
isMinifyEnabled = false
buildConfigField("boolean", "IS_RELEASE_BUILD", "true")
buildConfigField("boolean", "FEATURE_ADMIN", "false")
buildConfigField("boolean", "FEATURE_ADULT", "false")
buildConfigField("boolean", "FEATURE_3D", "false")
buildConfigField("boolean", "FEATURE_MINIGAMES", "false")
buildConfigField("boolean", "FEATURE_PUSH", "true")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
@@ -74,6 +133,29 @@ android {
compose = true
}
packaging {
resources {
excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
}
}
testOptions {
managedDevices {
devices {
create<com.android.build.api.dsl.ManagedVirtualDevice>("mediumPhone") {
device = "Medium Phone"
apiLevel = 34
systemImageSource = "google"
}
create<com.android.build.api.dsl.ManagedVirtualDevice>("mediumTablet") {
device = "Medium Tablet"
apiLevel = 34
systemImageSource = "google"
}
}
}
}
lint {
abortOnError = true
checkReleaseBuilds = true
@@ -91,13 +173,51 @@ android {
}
}
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
val validateReleaseConfig by tasks.registering {
doLast {
environmentConfigs
.filterKeys { it != "local" }
.forEach { (name, cfg) ->
require(cfg.apiBaseUrl.startsWith("https://")) {
"Release flavor '$name' must use HTTPS API URL, got ${cfg.apiBaseUrl}"
}
require(cfg.socketIoUrl.startsWith("https://")) {
"Release flavor '$name' must use HTTPS Socket.IO URL, got ${cfg.socketIoUrl}"
}
require(cfg.daemonSocketUrl.startsWith("wss://")) {
"Release flavor '$name' must use WSS daemon URL, got ${cfg.daemonSocketUrl}"
}
require(!cfg.apiBaseUrl.contains("10.0.2.2") && !cfg.apiBaseUrl.contains("localhost")) {
"Release flavor '$name' must not use local API URL, got ${cfg.apiBaseUrl}"
}
}
}
}
tasks.matching { task ->
task.name.startsWith("assemble") && task.name.endsWith("Release")
}.configureEach {
dependsOn(validateReleaseConfig)
}
dependencies {
implementation("androidx.core:core-ktx:1.17.0")
implementation("androidx.activity:activity-compose:1.13.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.0")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.10.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0")
implementation("androidx.security:security-crypto:1.1.0-alpha06")
implementation("androidx.navigation:navigation-compose:2.9.6")
implementation("androidx.browser:browser:1.9.0")
implementation("androidx.hilt:hilt-navigation-compose:1.3.0")
implementation("androidx.compose.material3:material3:1.4.0")
implementation("androidx.compose.material:material-icons-extended:1.4.1")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")
@@ -106,17 +226,27 @@ dependencies {
implementation("com.squareup.retrofit2:retrofit:3.0.0")
implementation("com.squareup.okhttp3:okhttp:5.3.2")
implementation("com.squareup.okhttp3:logging-interceptor:5.3.2")
implementation("io.socket:socket.io-client:2.1.0")
implementation("com.google.dagger:hilt-android:2.57.2")
kapt("com.google.dagger:hilt-android-compiler:2.57.2")
implementation("androidx.room:room-runtime:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
kapt("androidx.room:room-compiler:2.6.1")
implementation("androidx.room:room-runtime:2.8.0")
implementation("androidx.room:room-ktx:2.8.0")
kapt("androidx.room:room-compiler:2.8.0")
implementation("androidx.datastore:datastore-preferences:1.1.7")
implementation("io.coil-kt:coil-compose:2.6.0")
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("com.google.firebase:firebase-messaging:24.1.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.2")
testImplementation("junit:junit:4.13.2")
testImplementation("com.squareup.okhttp3:mockwebserver:5.3.2")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
androidTestImplementation("androidx.test.ext:junit:1.3.0")
androidTestImplementation("androidx.test:runner:1.7.0")
androidTestImplementation("androidx.test:rules:1.7.0")
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.9.4")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.9.4")
androidTestImplementation("androidx.room:room-testing:2.8.0")
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
}

View File

@@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "872182891503",
"project_id": "yourpart-2f689",
"storage_bucket": "yourpart-2f689.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:872182891503:android:6004ef4c46ce27e26eec1a",
"android_client_info": {
"package_name": "de.yourpart.nativeapp"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyC28yw1StDE15tdHKDQEXqEC_cBNXG9xkM"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@@ -0,0 +1,17 @@
{
"project_info": {
"project_number": "REPLACE_WITH_FIREBASE_PROJECT_NUMBER",
"project_id": "REPLACE_WITH_FIREBASE_PROJECT_ID",
"storage_bucket": "REPLACE_WITH_FIREBASE_STORAGE_BUCKET"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "REPLACE_WITH_ANDROID_APP_ID",
"android_client_info": { "package_name": "de.yourpart.nativeapp" }
},
"api_key": [{ "current_key": "REPLACE_WITH_FIREBASE_API_KEY"}]
}
],
"configuration_version": "1"
}

0
android/native/app/proguard-rules.pro vendored Normal file → Executable file
View File

View File

@@ -0,0 +1,232 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "771f218fbabd59ebba146d6688176afa",
"entities": [
{
"tableName": "user_profile_cache",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT, `avatarUrl` TEXT, `profileJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`userId`))",
"fields": [
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT"
},
{
"fieldPath": "avatarUrl",
"columnName": "avatarUrl",
"affinity": "TEXT"
},
{
"fieldPath": "profileJson",
"columnName": "profileJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "updatedAtMillis",
"columnName": "updatedAtMillis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"userId"
]
}
},
{
"tableName": "friend_search_cache",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`query` TEXT NOT NULL, `resultsJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`query`))",
"fields": [
{
"fieldPath": "query",
"columnName": "query",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "resultsJson",
"columnName": "resultsJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "updatedAtMillis",
"columnName": "updatedAtMillis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"query"
]
}
},
{
"tableName": "falukant_status_cache",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheKey` TEXT NOT NULL, `statusJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`cacheKey`))",
"fields": [
{
"fieldPath": "cacheKey",
"columnName": "cacheKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "statusJson",
"columnName": "statusJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "updatedAtMillis",
"columnName": "updatedAtMillis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"cacheKey"
]
}
},
{
"tableName": "vocab_course_cache",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`courseId` TEXT NOT NULL, `title` TEXT NOT NULL, `summary` TEXT, `courseJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`courseId`))",
"fields": [
{
"fieldPath": "courseId",
"columnName": "courseId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "summary",
"columnName": "summary",
"affinity": "TEXT"
},
{
"fieldPath": "courseJson",
"columnName": "courseJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "updatedAtMillis",
"columnName": "updatedAtMillis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"courseId"
]
}
},
{
"tableName": "vocab_lesson_cache",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`lessonId` TEXT NOT NULL, `courseId` TEXT NOT NULL, `title` TEXT NOT NULL, `lessonJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`lessonId`))",
"fields": [
{
"fieldPath": "lessonId",
"columnName": "lessonId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "courseId",
"columnName": "courseId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lessonJson",
"columnName": "lessonJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "updatedAtMillis",
"columnName": "updatedAtMillis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"lessonId"
]
}
},
{
"tableName": "vocab_review_outbox",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`requestId` TEXT NOT NULL, `payloadJson` TEXT NOT NULL, `createdAtMillis` INTEGER NOT NULL, PRIMARY KEY(`requestId`))",
"fields": [
{
"fieldPath": "requestId",
"columnName": "requestId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "payloadJson",
"columnName": "payloadJson",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "createdAtMillis",
"columnName": "createdAtMillis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"requestId"
]
}
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '771f218fbabd59ebba146d6688176afa')"
]
}
}

View File

@@ -0,0 +1,25 @@
package de.yourpart.nativeapp.core.auth.storage
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import de.yourpart.nativeapp.core.auth.model.AuthSession
import de.yourpart.nativeapp.core.auth.model.UserDto
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SessionStoreResumeTest {
@Test fun savedSessionSurvivesStoreRecreation() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val firstStore = SessionStore(context, Json { ignoreUnknownKeys = true })
firstStore.clearSession()
firstStore.saveSession(AuthSession(UserDto("resume-user", "alice", true, authCode = "resume-code"), true, 1L))
val resumedStore = SessionStore(context, Json { ignoreUnknownKeys = true })
assertEquals("resume-user", resumedStore.currentSession?.user?.id)
resumedStore.clearSession()
}
}

View File

@@ -0,0 +1,42 @@
package de.yourpart.nativeapp.core.persistence
import androidx.room.testing.MigrationTestHelper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class AppCacheMigrationTest {
@get:Rule
val helper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppCacheDatabase::class.java,
)
@Test
fun migrationFromVersion1PreservesExistingCacheAndCreatesReviewOutbox() {
helper.createDatabase(DB_NAME, 1).apply {
execSQL("CREATE TABLE IF NOT EXISTS `user_profile_cache` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT, `avatarUrl` TEXT, `profileJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`userId`))")
execSQL("CREATE TABLE IF NOT EXISTS `friend_search_cache` (`query` TEXT NOT NULL, `resultsJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`query`))")
execSQL("CREATE TABLE IF NOT EXISTS `falukant_status_cache` (`cacheKey` TEXT NOT NULL, `statusJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`cacheKey`))")
execSQL("CREATE TABLE IF NOT EXISTS `vocab_course_cache` (`courseId` TEXT NOT NULL, `title` TEXT NOT NULL, `summary` TEXT, `courseJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`courseId`))")
execSQL("CREATE TABLE IF NOT EXISTS `vocab_lesson_cache` (`lessonId` TEXT NOT NULL, `courseId` TEXT NOT NULL, `title` TEXT NOT NULL, `lessonJson` TEXT NOT NULL, `updatedAtMillis` INTEGER NOT NULL, PRIMARY KEY(`lessonId`))")
execSQL("INSERT INTO `vocab_lesson_cache` VALUES ('lesson-1', 'course-1', 'Titel', '{}', 1)")
close()
}
helper.runMigrationsAndValidate(DB_NAME, 2, true, AppCacheMigrations.MIGRATION_1_2).use { database ->
database.query("SELECT lessonId FROM vocab_lesson_cache").use { cursor ->
assertEquals(1, cursor.count)
}
database.query("SELECT name FROM sqlite_master WHERE type='table' AND name='vocab_review_outbox'").use { cursor ->
assertEquals(1, cursor.count)
}
}
}
private companion object { const val DB_NAME = "cache-migration-test" }
}

View File

@@ -0,0 +1,83 @@
package de.yourpart.nativeapp.ui
import androidx.activity.ComponentActivity
import androidx.compose.material3.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import de.yourpart.nativeapp.feature.auth.AuthScreen
import de.yourpart.nativeapp.feature.auth.LoginUiState
import de.yourpart.nativeapp.feature.home.HomeScreen
import de.yourpart.nativeapp.feature.home.HomeUiState
import de.yourpart.nativeapp.feature.vocab.VocabScreen
import de.yourpart.nativeapp.feature.vocab.VocabUiState
import de.yourpart.nativeapp.ui.theme.YourPartTheme
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
class NativeScreenComposeTest {
@get:Rule val composeRule = createAndroidComposeRule<ComponentActivity>()
@Test fun loginShowsValidationAndPrimaryAction() {
composeRule.setContent {
YourPartTheme {
AuthScreen(
uiState = LoginUiState(errorMessage = "Ungültige Anmeldung"),
oauthProviders = emptyList(),
onUsernameChange = {}, onPasswordChange = {}, onRememberMeChange = {}, onLogin = {},
onRegisterClick = {}, onForgotPasswordClick = {}, onOAuthLogin = {},
)
}
}
composeRule.onNodeWithText("Anmelden").assertIsDisplayed()
composeRule.onNodeWithText("Ungültige Anmeldung").assertIsDisplayed()
}
@Test fun navigationMovesToDestination() {
composeRule.setContent {
YourPartTheme {
val navController = rememberNavController()
LaunchedEffect(Unit) { navController.navigate("target") }
NavHost(navController = navController, startDestination = "start") {
composable("start") { Text("Start") }
composable("target") { Text("Ziel") }
}
}
}
composeRule.onNodeWithText("Ziel").assertIsDisplayed()
}
@Test fun homeRendersDashboardAndInvokesRefresh() {
var refreshes = 0
composeRule.setContent { YourPartTheme { HomeScreen(HomeUiState(isLoading = false), onRefresh = { refreshes += 1 }) } }
composeRule.onNodeWithText("Dashboard").assertIsDisplayed()
composeRule.onNodeWithText("Aktualisieren").performClick()
composeRule.runOnIdle { assertEquals(1, refreshes) }
}
@Test fun vocabRendersLoadedLesson() {
val lesson = buildJsonObject { put("title", "Lektion eins") }
composeRule.setContent {
YourPartTheme {
VocabScreen(
state = VocabUiState(lesson = lesson),
onCourses = {}, onCourseId = {}, onLoadCourse = {}, onLessonId = {}, onLoadLesson = {},
onLanguageId = {}, onLanguageName = {}, onCreateLanguage = {}, onShareCode = {}, onSubscribe = {},
onChapters = {}, onChapterId = {}, onChapterVocabs = {}, onDictionaryQuery = {}, onSearchDictionary = {},
onPractice = {}, onStartPractice = {}, onCheckPractice = {}, onLearning = {}, onReference = {},
onToggleCorrect = {}, onAnswer = {}, onReview = {}, onDictionary = {}, onProgress = {},
)
}
}
composeRule.onNodeWithText("Lektion").assertIsDisplayed()
composeRule.onNodeWithText("Lektion eins").assertIsDisplayed()
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">10.0.2.2</domain>
<domain includeSubdomains="false">localhost</domain>
</domain-config>
</network-security-config>

21
android/native/app/src/main/AndroidManifest.xml Normal file → Executable file
View File

@@ -1,15 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:name=".YourPartNativeApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher_foreground"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@drawable/ic_launcher_foreground"
android:supportsRtl="true"
android:theme="@style/Theme.YourPartNative">
<service
android:name=".feature.push.YourPartFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<activity
android:name=".MainActivity"
android:exported="true">
@@ -17,6 +26,18 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="www.your-part.de" android:pathPrefix="/android/oauth/callback" />
<data android:scheme="https" android:host="www.your-part.de" android:pathPrefix="/socialnetwork" />
<data android:scheme="https" android:host="www.your-part.de" android:pathPrefix="/falukant" />
<data android:scheme="https" android:host="www.your-part.de" android:pathPrefix="/settings" />
<data android:scheme="https" android:host="www.your-part.de" android:pathPrefix="/blogs" />
<data android:scheme="https" android:host="www.your-part.de" android:pathPrefix="/guides" />
<data android:scheme="https" android:host="www.your-part.de" android:path="/" />
</intent-filter>
</activity>
</application>
</manifest>

Some files were not shown because too many files have changed in this diff Show More