Align iOS + Android to per-collection repository shape#88
Draft
Brian Plattenburg (bplattenburg) wants to merge 14 commits into
Draft
Align iOS + Android to per-collection repository shape#88Brian Plattenburg (bplattenburg) wants to merge 14 commits into
Brian Plattenburg (bplattenburg) wants to merge 14 commits into
Conversation
Split the monolithic DittoRepository into three collection-focused repositories (Orders, SaleItems, Locations), each owning its own subscription and DQL. Eviction is collection-specific and moves into OrdersRepository. LocationsRepository filters to demo location IDs defensively, matching iOS behavior. DittoRepository remains as a thin delegator for now to keep consumers unchanged; it is retired in a follow-up commit once view models and use cases migrate to the specific repositories.
…ository Introduce SetActiveLocationUseCase as the single point that switches location: it persists the locationId, reconfigures Ditto's routing, and re-registers the orders + sale_items subscriptions. Replaces the old SetCurrentLocationUseCase + DittoRepository flow-collector pattern. Cold start orchestration moves into DittoPOSApplication.onCreate: start the locations subscription, seed + evict, then activate the persisted location. View models and Ditto-instance/permission use cases now depend on the specific repositories or DittoManager directly, no longer on DittoRepository.
DittoManager mirrors Android's DittoManager (`ditto-wrapper` module): it owns the Ditto instance, transport config, sync start/stop, and now also the sync-group / routing-hint configuration. DittoService asks the manager to apply routing when the active location changes rather than touching the Ditto SDK directly.
Mirrors the Android shape. DittoManager owns the SDK instance and transport-level routing config. Three repositories — Orders, SaleItems, Locations — own their collection's subscription, observers, and mutations. LocationsRepository also holds the currently-selected location id and the derived current location (initialized from the persisted Settings value on launch). SetActiveLocationUseCase is the single entry point for switching location: it persists, reconfigures routing, and re-registers the orders + sale_items subscriptions. Cold start runs from `DittoPOSApp.task`: seed demo data, run eviction (now on OrdersRepository), then activate the persisted location. Views and view models get their repositories via @EnvironmentObject; view models that need refs accept them via init. The willUpdate notification used to chain LocationsView -> POS_VM is gone; POS_VM now reacts to LocationsRepository.$currentLocation with `scan` to both reset the outgoing order and start a fresh one at the new location. POSOrderVM and POSOrderTotalVM were folded into their views as computed properties of the shared POS_VM. KDS_VM and KDSOrderVM take OrdersRepository via init.
- POS_VM -> POSViewModel (file + class) - Existing layout-only POSViewModel -> POSLayoutViewModel - KDS_VM -> KDSViewModel (file + class) - KDSOrderVM -> KDSOrderViewModel - Property renames: vm/posVM -> viewModel/layoutViewModel - Local renames: svr -> proxy, f -> formatter, s -> status, ts -> timestamp - Drop unused Fixtures.createdAtStr
POSViewModel exposes orderTitle, orderItems, orderTotalDisplay, orderIsPaid, orderIsEmpty, actionsDisabled, payButtonLabel, and scrollToBottomConfig(). KDSOrderViewModel exposes headerText, statusColor, statusTitle, summaryEntries, isPaid. Views now render those values rather than computing them inline. Brings iOS closer to Android's pre-derived `uiState` pattern.
LocationsRepository becomes the single source of truth and the only writer for the active location on both platforms. setActiveLocation persists the id and applies routing config via DittoManager. OrdersRepository and SaleItemsRepository subscribe to the locations repository's location-id stream in init and re-register their own collection subscriptions on every change. The orchestration use case is gone — UI calls locationsRepository.setActiveLocation directly. Cold start happens automatically: LocationsRepository's init self-restores the persisted id (synchronously on iOS, via a coroutine on Android), which emits through the flow/publisher and downstream repositories react. Dependencies flow one direction: UI -> LocationsRepository, other repos -> LocationsRepository. No cross-repo coupling, no orchestrator.
Owns selectedTab (initial value + persistence), presentSettingsView, and the navbar title. Subscribes to LocationsRepository so picking a location auto-switches to the POS tab and the title follows the active location. ensureLocationSelected() handles the onAppear "no location -> show Locations tab" branch. MainView becomes a render layer over the VM. The view takes LocationsRepository via init (the App constructs it) and creates the VM via StateObject(wrappedValue:) — same pattern POSView and KDSOrdersGridView use.
POSLayoutViewModel gains itemSide(for:) and gridColumns(for:), parameterized on UserInterfaceSizeClass. POSGridView grabs the layout VM from the environment (alongside the data POSViewModel) and asks it for sizes — no more inline size-class branching in the view. Pure functions, testable.
Selection state, derivation, and the "ignore no-op selection" guard move out of LocationsView into a dedicated VM. View just renders the list against viewModel.locations and binds selection to viewModel.selectionBinding.
Matches iOS's MainViewModel naming. The Android class was already the equivalent of a "main activity view model" — owns app-level uiState (currentLocationName, appConfigurationState), drives the shell scaffolding. "Main" reads more naturally than "Core" and makes cross-platform pairing obvious.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #80. Aligns iOS + Android to a per-collection repository shape.
Shape
DittoManager(singleton on both platforms) — owns the Ditto SDK, transport config, routing, permissions.OrdersRepository(subscription + mutations + eviction),SaleItemsRepository,LocationsRepository.LocationsRepositoryis the active-location source of truth. ItssetActiveLocationis the only writer — persists, publishes via@Published/Flow, applies routing. The other repos subscribe to its stream and re-register their own subscriptions when it changes. No orchestrator; dependencies go one way.DI
@Singleton+ constructor injection.DittoManageris.shared. Repositories owned by the App struct via@StateObject, passed via.environmentObject(...).Worth scrutinizing
LocationsRepositorymixes "synced collection" with "active-location state."LocationsRepository.initrestores the persisted id, downstream repos react via their subscriptions.