Structure
Details on architecture, folders, main files, and asset management for the ARShades iOS app and its App Clip.
Architectural overview
- Pattern: MVVM + Interactors (Use-Cases)
- UI: SwiftUI (with small UIKit wrappers where necessary)
- Rendering: ARKit + RealityKit
- Data: Firebase (Firestore, Storage, Dynamic Links, Messaging, App Check), optional Realm cache (full app only)
- Navigation: Side menu; deep links drive state hydration before presenting Try-On
- App Clip: Smaller surface that mirrors core Try-On flow
Top-level layout
Top-level layout
ARShades/
├─ ARShadesFramework/ # Shared domain: ViewModel contracts, LiveData, Utils, Models, Extensions
├─ ARShades/ # Full app target (SwiftUI views, screens, resources)
├─ ARShades Clip/ # App Clip target (mirrors minimal set of app layers)
├─ Packages & Pods # Swift Package Manager + CocoaPods (Firebase, Realm, etc.)
Shared framework (domain & utilities)
ARShadesFramework/
-
ViewModel/
VM_Protocol— common VM interfaces used across screens.
-
Database/ (domain models & persistence helpers live here together with Models below)
-
Utils/
MemoryUtils,ModelUtils,ARDownloadUtils,KeyboardResponder,Reachability- DynamicLinkHelpers/:
DeepLinkKey,DynamicLinksFuncs,DeepLinkHandler ActivityIndicatorView- Protocols/:
IDownloadUsdz(3D asset download abstraction)
-
Live_Data/
TagsLiveData,SystemData,SizesLiveData,SystemLiveData,LineLiveData,ModelLiveData,BrandLiveData,NotificationLiveData,ObservableGlasses- Purpose: observable singletons that hold app-wide reactive state published to SwiftUI.
-
Extensions/
DeviceExtension,ThreadExtension,ViewExtension,StringExtension,ColorConverter,DoubleExtension,DateExtension
-
Model/
- Persistent & domain objects:
Catalogue,Preferito,Metrica,PrivacyPolicy,Notifica,TakePicTemplate,CatalogueProduct,CatalogueVariant,Brand,Occhiale,Tag,Linea,Modello,Taglia,AppConfig,Skin - Models_Interface/: protocol forms (
IOcchiale,ITaglia,IMetrica,IBrand,IModello,ILinea,ITag)
- Persistent & domain objects:
Rendering container
ARViewContainer/
ARViewContainer.swift— SwiftUI ↔ RealityKit bridge. HostsARView, managesARSessionwith aCoordinator.- Responsibilities: face-anchor updates, model load/reload, animation controls, lighting tuning, metrics computation callbacks.
Full app (UI, screens, composition)
ARShades/
-
LiveData/ — app-target specific observable data (
CardsLiveData). -
Extensions/ — UI/image helpers (
ImageExtension). -
Constants/ — app-wide constants.
-
Components/ (reusable SwiftUI building blocks)
- Buttons/ →
ButtonFavouriteCard - Badge/ →
Badge - Notification/ →
NotificationItem - Catalogue/ →
Catalogue_Item - MetricsMenu/ →
MenuMetrics - ColorDots/ →
ColorDot,DotList - GlassesCard/ →
CardList,CardExplore - GeneralViews/ →
GeneralView - SideMenu/ →
SideMenu,SideMenuPageChooser,SideMenuModel,SideMenuOptionView,SideMenuHeader - metrics_menu/ →
WebView3D - GlassesMenu/ →
GlassesMenu,CarouselView - ItemSize/, Buttons/, Filters/, ShareSheet/, ItemSlider/, SearchBar/, IconsMetrics/, MetricRow/
- Buttons/ →
-
Resources/
- Launch assets (e.g.,
splash_ar_shades), shared imagery, App Clip assets.
- Launch assets (e.g.,
-
App_Start/
AppMain(SwiftUI@main),AppDelegate,AppStart,AppDelegateMethods- Handles Firebase config, App Check, notifications, deep-link entry, session updates, and PP/T&C gating.
-
Interactors/
- Interactor_Interfaces/:
GlassesInteractorProtocol,TagsInteractorProtocol,ModelsInteractorProtocol,FirebaseInteractorProtocol,DynamicLinksInteractorProtocol,CardsInteractorProtocol,ISigninInteractor - Implementations:
GlassesInteractor,TagsInteractor,ModelsInteractor,FirebaseInteractor,NotificationInteractor,CardsInteractor,SigninInteractor,InteractorsContainer(DI/locator)
- Interactor_Interfaces/:
-
Repository/
- Firebase/
- signin/:
FirebaseSigninPassword,IFirebaseSigninPassword - protocols_read/:
IRead*Repository(Glasses, Brand, Line, Size, Model, Category, Privacy, AppVersion) - read/:
FirebaseRead*concrete readers (Glasses, Products, Catalogue, Variant, Brand, Line, Size, Model, Category, PrivacyPolicy, AppVersion, AppConfig) - protocols_write/:
SessionFirebaseWrite - write/:
FirebaseServices,FirebaseDownloadUtils
- signin/:
- Purpose: network/data layer mapping Firestore documents & Storage assets to domain models.
- Firebase/
-
Session/
ContatoriBrand,SessionFirebase,UserSession,SessionMethods,GlassesSession,ModelSession- Tracks user sessions, counters, timestamps; writes session docs via
FirebaseServices.
-
Utils/
Permissions,FacialMetricsComputer,RealmUtils,DownloadUsdz,DownloadImage
-
Screens/ (SwiftUI screens grouped by feature)
- NewSkin/ & 2024Skin/ — skin-themed UIs (menus, dots, cards, button sets, etc.)
- ExploreScreen/ →
ExploreScreen - SplashScreen/ →
SplashScreenPage,SplashScreenViewModel - NotSupportedDevice/ →
ViewNotSupported - Notifications/ →
NotificationsPage,NotificationScreenViewModel - WorkInProgress/
- Favourites/ →
FavouritesPage - Catalogue/ →
CataloguePage,CatalogueScreenViewModel - ProductPage/ →
ProductPage,ProductPageFavourite - FacialMetrics/ (+ Controllers/ for UIKit wrappers)
- TermsAndConditions/ →
TermsAndPrivacyPage - ModelViewer/ →
ModelViewer - ContactPage/ →
ContactPage,ContactScreenViewModel - TryOn/ →
TryOnPage,TryOnScreenViewModel - Filters/ →
FilterPage,CategoryPage,TagPage
-
ViewModel/
AppState,MetricsViewModel,VMGlobalInstance,AppConfigViewModel
-
GoogleServiceInfoPlists/ & InfoPlist (localized) — per-environment Firebase configs & Info.plist localizations.
-
Assets/ & Localizable/ — shared resources and translations.
-
ARShadesKit/, Tests/ — frameworks and unit/UI tests (where applicable).
App Clip target
ARShades Clip/
- Repository/Firebase/
- signin/:
FirebaseSigninPassClip - write/:
SessionFirebaseWriteClip - read/: App-Clip-scoped readers (
FirebaseRead*Clip) - FirebaseFunctions: helpers scoped to App Clip
- signin/:
- Model/
- Rest/ (DTOs for lightweight payloads),
Model_Not_Persistent/(session-only structs)
- Rest/ (DTOs for lightweight payloads),
- App_Start/ —
AppStartClip - Interactors_Clip/ —
GlassesClipInteractor,CardsInteractorClip - ViewModel/ —
AppStateClip - Utils/ —
DownloadUsdzRest - Views/
- Composed_Widgets/ (
DotList) - Widgets/ (
AppClip_FAB/Card) - Pages/ (
AppClipGeneralView,SplashScreenAppClip,TryOnClip,ProductPageClip,ViewNotSupported, plus badges, item size, and new-skin components)
- Composed_Widgets/ (
- Localizable/ & InfoPlist/ — localized App Clip plists
The App Clip carries only the minimal sets required for deep-link try-on (parse
c/m, fetch lightweight catalog/variant, render model, present CTA to open the full app).
Asset management
-
3D models (USDZ)
- On-demand downloads via
DownloadUsdz(full app) andDownloadUsdzRest(App Clip). - Retry & attach to RealityKit scene inside
ARViewContainer.Coordinator. - Periodic cleanup: deletion of cached USDZ after a retention window to control disk usage.
- On-demand downloads via
-
Images
- Remote images cached via Kingfisher in lists, cards, and carousels.
- Notification images fetched from Firebase Storage when present.
-
Shared bundles
Assets/,SharedAssets/,ClipAssets/separate full-app vs App Clip resources.
-
Localization
Localizable/and localizedInfoPlistfiles (EN/IT/ES/DE/FR).
Build & targets
- App Groups:
group.arshades.appClipMigrationfor small state sharing between app and App Clip. - Associated Domains:
applinks:safilo.arshades.it,applinks:spaarkly.page.link,appclips:safilo.arshades.itfor Universal Links & App Clip invocation. - Background Modes: Remote notifications enabled in the full app.
- Signing: Team Spaarkly srl, bundle
it.spaarkly.ARShades-demo, automatic signing.
Package dependencies (SPM)
- Firebase (Analytics, Crashlytics, Firestore, Storage, Messaging, Dynamic Links, App Check)
- Realm / RealmSwift (full app only)
- DeviceKit, Kingfisher, swift-markdown-ui, SwiftUIGIF
- Low-level Firebase deps (gRPC, GoogleUtilities, Promises, etc.) are pulled transitively.
Data flow (high level)
- Startup →
AppMain/AppDelegateconfigures Firebase & App Check. - No deep link →
AppConfig(Firestore) defines visible catalogues → Brands → Try-On (first 30 products). - Deep link (
c,m) → hydrate catalogue/variant/product/siblings → Try-On; ifcnot in AppConfig, persist to Realm for future Brands listing. - Interactions → Interactors call Repository readers/writers → LiveData updates → SwiftUI views react.
- AR →
ARViewContainermanages face anchors, model load, lighting, animations.
Naming & conventions
- Files & folders reflect feature areas (
TryOn,Catalogue,Notifications, etc.) and shared components (Components/*). - Protocols prefixed with
I*in domain interfaces;LiveDatasuffix for observable singletons. - Repositories named
FirebaseRead*/FirebaseRead*Clipfor clarity across targets. - ViewModels live under
ViewModel/and are injected viaVMGlobalInstanceor feature initializers.