- Full Clean Architecture + MVVM with Hilt DI throughout all layers - Room v6 with SQLCipher encryption and 5 migrations (no destructive) - Items can be placed directly in a room or location (not just in a box) - Reactive detail screens: name changes update instantly via ObserveById flows - Camera permission flow: always-clickable button with proper rationale handling - Soft keyboard: imePadding on AddEditItemScreen so Notes field stays visible - Clickable items in BoxDetailScreen navigating to ItemDetailScreen - FTS4 full-text search, QR code scanning, CameraX photos with UCrop - Google Drive encrypted backup via WorkManager, Excel/PDF export - Biometric + PIN app lock, Google Play Billing freemium model - Home screen widgets: 4x1 search widget and 2x2 recent items widget - Updated docs/PROJECT_OVERVIEW.md to reflect current codebase state Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 KiB
Box Organizer Inventory — Projektöversikt
Uppdaterad: 2026-04-05 Package:
com.roundingmobile.boiMin SDK: 27 (Android 8.1) · Target SDK: 36 Databas: Room v6 · SQLCipher AES-256
Arkitektur
Clean Architecture + MVVM med Single-Activity och Jetpack Compose Navigation.
Presentation (Compose)
20 Screens + ViewModels + UiState
↓ lambdas
Domain (ren Kotlin)
47 UseCases · 8 Repository-interfaces · 12 modeller
↓ Result<T> / Flow<T>
Data (Android)
11 RepositoryImpl · 8 DAOs · AppDatabase v6
↓
SQLite (SQLCipher) + Google Drive + Play Billing + ML Kit
DI: Hilt genomförd i alla lager (6 moduler: App, Database, Preferences, Repository, Backup, WidgetEntryPoint).
Databas
Version 6 — ingen fallbackToDestructiveMigration.
| Migration | Ändring |
|---|---|
| 1 → 2 | photoPath på locations |
| 2 → 3 | photoPath på storage_rooms |
| 3 → 4 | color + photoPath på boxes |
| 4 → 5 | FTS4-tabell items_fts + triggers |
| 5 → 6 | boxId nullable; roomId + locationId FK:ar på items; FTS återskapad |
Entiteter
| Tabell | Nyckelfält |
|---|---|
locations |
id, name, description, photoPath, createdAt, updatedAt |
storage_rooms |
id, locationId (FK→locations), name, description, photoPath |
boxes |
id, roomId (FK→storage_rooms), name, qrCode (UNIQUE), color, photoPath |
items |
id, boxId? (FK), roomId? (FK), locationId? (FK), name, description, quantity, value, unit, notes |
item_photos |
id, itemId (FK), filePath, sortOrder |
tags |
id, name (UNIQUE), colorHex |
item_tags |
itemId + tagId (composite PK, båda CASCADE DELETE) |
items_fts |
FTS4 virtual table — name, description, notes; synkad via triggers |
Exakt ett av boxId, roomId, locationId är non-null per föremål.
Alla FK-relationer har CASCADE DELETE. Index på alla WHERE/ORDER BY-kolumner.
Hierarki
Plats (Location)
└── Rum (StorageRoom)
│ └── Låda (Box)
│ │ └── Föremål (Item) ← item.boxId
│ └── Föremål (Item) ← item.roomId
└── Föremål (Item) ← item.locationId
Föremål kan ligga direkt i en låda, ett rum eller en plats.
Skärmar (20 st)
| Skärm | Route | Funktion |
|---|---|---|
| HomeScreen | home |
Dashboard: platser med rum/föremål-räkningar, PRO-indikator |
| LocationListScreen | locations |
Lista alla platser |
| LocationDetailScreen | location/{id} |
Platsdetaljer: rum-lista + lösa föremål |
| AddEditLocationScreen | add_location, edit_location/{id} |
Skapa/redigera plats (namn, beskrivning, foto) |
| RoomListScreen | rooms/{locationId} |
Rum inom en plats |
| RoomDetailScreen | room/{id} |
Rumsdetaljer: låd-lista + lösa föremål |
| AddEditRoomScreen | add_room/{locationId}, edit_room/{id} |
Skapa/redigera rum |
| BoxListScreen | boxes/{roomId} |
Lådor i ett rum |
| BoxDetailScreen | box/{id} |
Låddetaljer: föremål, QR-kod, etikettgenerering |
| AddEditBoxScreen | add_box/{roomId}, edit_box/{id} |
Skapa/redigera låda (namn, färg, foto) |
| ItemListScreen | items/{boxId} |
Föremål i en låda |
| ItemDetailScreen | item/{id} |
Föremålsdetaljer: foton, taggar, anteckningar, värde |
| AddEditItemScreen | add_item/{boxId}, edit_item/{id}, add_item_to_room/{roomId}, add_item_to_location/{locationId} |
Skapa/redigera föremål |
| CameraScreen | camera |
CameraX-foto, returnerar sökväg via savedStateHandle |
| SearchScreen | search |
Global FTS4-sökning, resultat grupperade per typ |
| QrScannerScreen | qr_scanner |
Skanna QR → navigera direkt till rätt låda |
| ProUpgradeScreen | pro_upgrade |
Google Play Billing-UI |
| RestoreBackupScreen | restore_backup |
Återställ från Google Drive-backup |
| SettingsScreen | settings |
Backup, export/import, app-lås PIN |
| LockScreen | (modal overlay) | Biometrisk/PIN-lås vid återgång till appen |
Deep links: boi://search (sök-widget), boi://item/{id} (senaste-widget).
Animationer: slide + fade 280 ms (framåt/bakåt).
UseCases (47 st)
| Domän | UseCases |
|---|---|
| Location | Add, Update, Delete, GetById, GetAll, GetSummaries, ObserveById |
| StorageRoom | Add, Update, Delete, GetById, GetByLocation, ObserveById |
| Box | Add, Update, Delete, GetById, GetByRoom, GetByQrCode, ObserveById |
| Item | Add, Update, Delete, GetById, GetByBox, GetByRoomDirect, GetByLocationDirect, GetTotalCount |
| ItemPhoto | Add, Delete, GetByItem |
| Tag | Add, Update, Delete, GetAll, AddToItem, RemoveFromItem, GetForItem |
| Search | Search (FTS4) |
| Backup | BackupNow, GetBackupList, RestoreFromBackup |
| Export/Import | ExportInventory, ExportInventoryFile, ImportInventory |
| PRO | GetProStatus, SetProStatus |
Observe*-UseCaserna returnerar Flow<T?> och ser till att detail-skärmar uppdateras i realtid när namn ändras.
Reaktivt namnuppdatering
Varje detail-ViewModel (LocationDetailViewModel, RoomDetailViewModel, BoxDetailViewModel) använder combine(observeEntity(), children...) — inte one-shot suspend fun. Det innebär att namn-ändringar från redigera-skärmen syns direkt utan navigation.
Funktioner
Sökning
- FTS4 full-text sökning på item name/description/notes
- Resultat grupperade: Föremål · Lådor · Platser
SearchRepositoryImplbygger korrekt sökväg oavsett om föremålet ligger i låda, rum eller plats
QR-koder
- Varje låda får en unik QR-kod (ZXing)
- Skanning navigerar direkt till rätt låda
- PDF-etikett med QR-kod för utskrift
Foton & Kamera
- CameraX för att ta foton
- UCrop för bildbeskärning
- Auto-komprimering: max 1080 px, kvalitet 80 %
- Systemkamera via
TakePicture()på plats/rum/låda-skärmar (FileProvider) - Alla foton i
filesDir/photos/— aldrig extern lagring
Kamerabehörighet
- Kameraknappen alltid klickbar (aldrig
enabled = false) - Vid klick: kontrollera behörighet → be om den vid behov
- Mjuk nekad → Snackbar
- Permanent nekad → dialog med länk till app-inställningar
Backup & Restore
- Google Drive — automatisk backup var 24:e timme (WorkManager, WiFi + batteri)
- Manuell backup från Inställningar
- AES-krypterade backup-filer
- Restore: ersätt allt eller slå ihop (merge)
- Push-notiser vid lyckad/misslyckad backup
Export
- Excel (.xlsx) via Apache POI
- PDF — full inventarielista
- PDF-etiketter med QR-koder
App-lås
- BiometricPrompt med PIN-fallback
- Lås aktiveras automatiskt när appen går till bakgrunden
- PIN-inställning i Inställningar
Widgets
| Widget | Storlek | Funktion |
|---|---|---|
| Sökwidget | 4×1 | Öppnar sökskärmen via boi://search |
| Senaste föremål | 2×2 | Visar 4 senast tillagda föremål; uppdateras var 60:e minut |
Freemium & In-App Purchase
- Google Play Billing v7
- Gräns-kontroll i UseCase-lagret — aldrig i UI
- PRO-status sparas i DataStore
Freemium-gränser (AppConfig.kt)
| Funktion | Gratis | Pro |
|---|---|---|
| Föremål totalt | 500 | Obegränsat |
| Foton per föremål | 3 | Obegränsat |
| Excel/PDF-export | Nej | Ja |
| Google Drive-backup | Nej | Ja |
| Avancerade filter | Nej | Ja |
Säkerhet
| Komponent | Mekanism |
|---|---|
| Databas | SQLCipher (AES-256) |
| DB-nyckel | EncryptedSharedPreferences |
| Backup-filer | AES-krypterade |
| Foton | filesDir (ej åtkomlig för andra appar) |
| App-lås | PIN + BiometricPrompt |
| Loggar | if (BuildConfig.DEBUG) — aldrig i release |
| Manifest | allowBackup="false", exported="false" på alla interna komponenter |
Tekniker & Bibliotek
| Kategori | Bibliotek | Version |
|---|---|---|
| Språk | Kotlin | 2.1.10 |
| UI | Jetpack Compose BOM | 2024.12.01 |
| UI | Material3 | via BOM |
| DI | Hilt | 2.59.2 |
| Navigation | Navigation Compose | 2.8.5 |
| ORM | Room | 2.7.1 |
| DB-kryptering | SQLCipher | 4.5.4 |
| Bilder | Coil (Compose) | 2.7.0 |
| Kamera | CameraX | 1.4.2 |
| Bildbeskärning | UCrop | 2.2.8 |
| ML Kit | Barcode Scanning + Image Labeling | 17.3.0 / 17.0.9 |
| QR-koder | ZXing | 3.5.3 |
| Bakgrundsarbete | WorkManager | 2.10.0 |
| Reaktiv data | Kotlin Coroutines + Flow | 1.8.1 |
| Inställningar | DataStore Preferences | 1.1.3 |
| Säker lagring | Security Crypto | 1.1.0-alpha06 |
| Biometri | androidx.biometric | 1.2.0-alpha05 |
| Köp | Google Play Billing KTX | 7.1.1 |
| Backup | Google Drive API v3 + Play Services Auth | v3-rev197 / 21.3.0 |
| Excel | Apache POI | 5.2.3 |
| Lifecycle | ViewModel + Runtime KTX | 2.9.0 |
Filstruktur
| Lager | Filer |
|---|---|
| Presentation (Screens + ViewModels + UiState) | ~65 |
| Domain (UseCases + Models + Interfaces) | ~60 |
| Data (Entities + DAOs + RepositoryImpl) | ~35 |
| DI (Hilt-moduler) | 6 |
| Util | ~10 |
| Navigation | 2 |
| Totalt | ~184 |
Vad man kan göra i appen
- Skapa platser, rum, lådor och föremål i en hierarki
- Lägga föremål direkt i ett rum eller en plats (utan låda)
- Lägga till foton på föremål och platser/rum/lådor
- Sätta färgkod och QR-kod på lådor
- Tagga föremål med valfärgade taggar
- Redigera namn → detaljskärmen uppdateras direkt (reaktivt)
- Söka efter föremål med fulltextsökning
- Skanna QR-kod för att navigera direkt till rätt låda
- Exportera inventariet till Excel eller PDF
- Skriva ut etiketter med QR-koder
- Säkerhetskopiera till Google Drive (automatiskt + manuellt)
- Återställa från backup (ersätt eller slå ihop)
- Skydda appen med PIN + biometri
- Uppgradera till Pro via Google Play
Möjliga nästa steg
- ML Kit auto-taggning från foton (infrastruktur finns i
ImageLabelAnalyzer.kt) - Flytta föremål/lådor mellan rum/platser
- Sortering och filtrering i listor (per datum, värde, antal)
- Statistikskärm (totalt värde, antal per plats)
- Barcode-sökning (EAN/UPC) för produktidentifiering
- Notiser för schemalagda inventariegranskningar
- iCloud/Dropbox som backup-alternativ
- CSV-import
- Dela enskilda lådor/inventarier med andra användare
- Fullständigt flerspråksstöd (i18n)
- Enhetstester för UseCases
- Instrumenterade tester för databas-migrationer