Structure
Details on architecture, folders, main files, and asset management for the ARShades Android app and its Instant App.
Architectural overview
- Pattern: MVVM + Repository + DI (Hilt)
- UI: Jetpack Compose + XML (hybrid, Compose is progressively adopted)
- Rendering: ARCore + Sceneform
- Data: Firebase (Firestore, Storage, Dynamic Links, Messaging, App Check) with optional Realm cache (full app only)
- Navigation: Jetpack Navigation (Compose + Fragments), side menu
- Instant App: Smaller surface mirroring the Try-On flow with minimal Firebase + model hydration
Top-level layout
ARShades/
├─ app/ # Main Android app module
│ ├─ manifests/ # AndroidManifest + App metadata
│ ├─ kotlin+java/it.spaarkly.arshades/
│ ├─ res/ # XML layouts, drawables, strings, themes
│
├─ arshades_instant/ # Instant App module (lightweight Try-On)
├─ ARShadesFramework/ # Shared framework (contracts, utils, domain models)
├─ ARShadesInterfaces/ # Interfaces across modules
├─ ARShadesUiComponents/ # Shared UI components (Compose & XML)
App module (app/)
Components
Reusable UI building blocks in Compose/XML:
components/→ Buttons, CatalogueComponents, ColorDotComponents, FilterComponents, GlassesCard, etc.general_views/,general_purpose_widgets/→ generic views/widgets
Screens (feature-based)
screens/brand/→ BrandPageFragment, BrandListScreenscreens/catalogue/→ FragmentCatalogue, CatalogueViewModelscreens/contacts/→ ContactsFragment, ContactsScreenViewModelscreens/favourites/→ FavouritesFragment, FavouritesScreenViewModelscreens/filters/→ FiltersViewModelscreens/facial_metric/→ FacialMetricScreenViewModel, Measurementscreens/notification/→ NotificationFragment, NotificationScreenViewModelscreens/try_on/→ TryOnActivity, TryOnScreenViewModel, FacialMetricsControllerscreens/splash/→ SplashScreen.kt, AppConfigViewModelscreens/terms_and_conditions/→ TermsAndConditionsActivity, LegalViewModel
Data & persistence
-
repository/- Firebase/read → AppConfig, Brand, Catalog, Product, Variant, Legal, etc.
- Firebase/write → SessionRepository, CountersRepository
- Realm/ → Local Realm repos for Favorites, Notifications, Brands
-
database/firebaseDB.write.SessionDBrealmDB/+IRealmDB
-
model/→ Core domain: AppConfig, Brand, Catalog, CatalogProduct, CatalogVariant, UserSession, DynamicLinkObject, etc. -
session/→ CurrentSession, GlassesSession, ModelSession, UserDataMetrics
Services & utils
services/FirebaseNotificationService→ handles push notificationsutils/→ NetworkUtils, PermissionManager, SharedPrefs, TakePicsUtility, SideMenuPageSwitcherui.theme/→ Compose theme files (Color.kt,Theme.kt,Type.kt)di/→ Hilt AppModule
Instant App module (arshades_instant/)
Lightweight subset of the app:
- Keeps only Dynamic Link hydration, Try-On, and minimal repositories
- Mirrors models (
UserAr,Brand,Catalog,Occhiale, etc.) andSessionDB - Slimmed-down
repository.firebase.readfor fetching Try-On context - No Realm, reduced UI
Shared modules
- ARShadesFramework → Common contracts, utils, interfaces
- ARShadesInterfaces → Defines module interfaces
- ARShadesUiComponents → Shared Compose widgets & XML components across app/instant
Asset management
- 3D models (GLB/Sceneform) → Downloaded on demand via Firebase Storage, rendered with Sceneform
- Images (PNG/JPG, VectorDrawables) → In
res/drawable/, fetched & cached from Firebase - GIF/Animations → Splash + empty/error states (
res/drawable/) - Layouts → Hybrid Compose + XML (
res/layout/), with gradual Compose migration - Themes & Styles →
res/values/(colors, dimens, strings, themes)
Build setup
- Gradle modules:
app,arshades_instant,ARShadesFramework,ARShadesInterfaces,ARShadesUiComponents - Hilt for DI
- Proguard/R8 configs per module
- Firebase BoM manages Crashlytics, Analytics, Perf, Messaging, Firestore, Storage, Auth, Dynamic Links
- Realm for local caching (full app only)
- Navigation Component for deep link + side menu routing
- Play Core for in-app updates & reviews
- App Signing: Release config via
signingConfigs.releaseinbuild.gradle
Data flow (high level)
-
Startup
- Splash → AppConfig fetch (Firestore)
- Hydrate deep link (
c,m) if present
-
No deep link
- Brands (from AppConfig + Realm-learned) → Try-On
-
Deep link (
c,m)- Hydrate catalogue/variant/product/siblings from Firebase
- If catalogue unknown, persist to Realm for next sessions
-
User interactions
- ViewModels drive UI (Compose/XML)
- Repositories fetch/write to Firebase + Realm
- State persists via Realm + SharedPrefs
-
AR Rendering
- ARCore + Sceneform pipeline for Try-On (glasses fitting, skin metrics)
Naming & conventions
- Kotlin packages follow feature-first naming (
screens/try_on,screens/catalogue,repository/firebase) - ViewModels suffixed with
ViewModel - Repositories suffixed with
Repository(BrandRepository,SessionRepository) - Realm interfaces prefixed with
I*(e.g.,IBrandRepository) - Fragments/Activities map 1:1 with XML layouts (when not Compose)