Locations

interface Locations

Locations feature - the member's relationship with places: favorite locations (gyms and retail stores the member chose), map search by viewport or radius, the nomination surface (nominating a missing place, reporting a problem with an existing one, the member's own submissions, the category and type catalogs a nomination form needs, place search and recent searches), automatic gym-visit detection and location sharing.

Reach it with AFCore.locations() (Kotlin) or AFCore.shared.locations() (Swift). It supersedes the deprecated AFCore.facilities() and AFCore.map(), which keep working.

Moving from facilities() and map()

DeprecatedUse instead
facilities().get()getFavorites; filter gyms with FavoriteLocation.isFitness
facilities().update(id, verified = true)addFavorite; isPrimary = true makes it the primary gym
facilities().update(id, verified = false)No replacement yet: keep calling it to exclude a location (muteFavorite is a pause, not an exclusion)
facilities().delete(id)removeFavorite; the legacy club id is accepted
facilities().startMonitoring() / stopMonitoring() / isMonitoringActive()startVisitDetection / stopVisitDetection / isVisitDetectionActive
facilities().geofenceEvents / subscribeToEvents()visitEvents / subscribeToVisitEvents
facilities().subscribeToStatus()subscribeToVisitDetectionStatus
facilities().areLocationServicesEnabled() / openLocationSettings() / openAppSettings()areLocationServicesEnabled / openLocationSettings / openAppSettings
facilities().nominateFacility(...)nominateLocation, with a category, a type and a Google place id
facilities().getNominatedFacilities()getMySubmissions: nominations and problem reports, paged, with their review status
map().getNearbyFacilities(...)getLocationsByRadius
map().getFacilitiesByViewPort(...)getLocationsByViewPort
AFCore.heartbeat / AFCore.heartbeatEnabledlocationSharing / locationSharingEnabled
AFCore.setHeartbeatEnabled(), AFCoreConfig.Builder.heartbeatEnabled()AFCoreConfig.Builder.locationSharingEnabled(true)
AFCore.fireDebugHeartbeat()shareLocationNow

With no predecessor: muteFavorite / unmuteFavorite, reportLocationProblem, searchPlaces, the recent place searches (getRecentPlaceSearches, rememberPlaceSearch, clearRecentPlaceSearches) and the nomination catalogs (getLocationCategories, getLocationTypes).

Error contract

Every function is suspend and throws on failure - network, HTTP and malformed-response errors surface as AFException (with the underlying cause preserved), never as an empty result. An empty list always means the member genuinely has no favorites.

No offline queue

Locations writes - favorites, nominations and problem reports - are never queued offline. Without a connection they throw; catch the error and let the member retry.

Mutations return the fresh list

addFavorite, muteFavorite and unmuteFavorite return the member's complete, post-mutation favorites list as the server sends it - use it to reconcile local state in one pass instead of refetching. removeFavorite is the exception: the server answers 204 with no body.

Presence: visit detection and location sharing

Two independent capabilities, each with its own consent:

  • Visit detection (startVisitDetection) credits gym visits automatically: the device geofences the member's fitness favorites and posts each visit. It needs "Always" location permission and is the successor of facilities().startMonitoring().

  • Location sharing (locationSharing) sends the member's location to the server, which evaluates every place - gyms, retail stores, proximity zones - on its side: offers near a store, journeys, and server-decided visits. It is opt-in through AFCoreConfig.Builder.locationSharingEnabled, never implied by visit detection, and keeps sending in the background when the device moves significantly.

The SDK always sends what it observes; the server decides what it counts. Both are iOS and Android features: on watchOS startVisitDetection throws and shareLocationNow reports a suppressed attempt without sending.

Identifier semantics

Mutations are addressed by the canonical FavoriteLocation.locationId. The server also resolves a FavoriteLocation.legacyClubId passed in its place and answers 409 when the number matches both spaces ambiguously - that 409 surfaces as an AFException with httpCode = 409.

Calling from Swift

Kotlin default arguments do not reach Swift: pass every argument, nil for an optional one (getLocationTypes(categoryId: nil, categoryCode: nil, activeOnly: true)), and every constructor parameter of a model such as AdvancedLocationFilter. A Kotlin Long is an Int64 and an Int an Int32; an optional number is boxed (KotlinInt(int: 7), KotlinDouble(value: 40.7)), and a suspend function or a callback that carries a Boolean hands over a KotlinBoolean (read .boolValue). The subscribeTo... callbacks run on a background thread - hop to the main actor before touching UI.

Android (Kotlin)

lifecycleScope.launch {
try {
// Favorites, muted or not; EXCLUDED is the member's blacklist.
val favorites = AFCore.locations().getFavorites()
.filter { it.favoriteType != LocationFavoriteType.EXCLUDED }
showFavorites(favorites)
} catch (t: Throwable) {
showError(t)
}
}

iOS (Swift)

Task {
do {
let favorites = try await AFCore.shared.locations().getFavorites()
.filter { $0.favoriteType != .excluded }
self.showFavorites(favorites)
} catch {
self.showError(error)
}
}

Properties

Link copied to clipboard

The most recent location-sharing attempt - sent, suppressed (and why), or failed - or null before the first one in this process. The SDK shares on initialization, on every foreground, alongside each visit-detection geofence transition, and in the background whenever the device moves significantly (AFHeartbeatTrigger.SIGNIFICANT_LOCATION_CHANGE). The background trigger runs only when the opt-in came from AFCoreConfig.Builder.locationSharingEnabled(true); an opt-in made with the deprecated heartbeat switches keeps the 1.11 triggers and never shares in the background.

Link copied to clipboard

Whether location sharing is on for this install - the opt-in declared with AFCoreConfig.Builder.locationSharingEnabled. Off by default: a host must collect the member's consent to share a live location separately from location permission.

Link copied to clipboard

Visit-detection events at the member's gyms: Enter, Exit, Dwell and the session's registration / error events.

Functions

Link copied to clipboard
abstract suspend fun addFavorite(locationId: Long, isPrimary: Boolean = false): List<FavoriteLocation>

Adds a location to the member's favorites. The server treats this as a declarative upsert: an excluded location becomes a favorite and a muted one is unmuted - it never answers 409 for a location already favorited.

Link copied to clipboard

Whether the device's system-level Location Services switch is on.

Link copied to clipboard
abstract suspend fun clearRecentPlaceSearches()

Forgets every remembered place search.

Link copied to clipboard
open suspend fun getFavorites(): List<FavoriteLocation>

Retrieves all of the member's favorite locations, each joined with the location's own data (address, coordinates, category, geofence radius), so a list never needs a second fetch per row.

Link copied to clipboard
abstract suspend fun getLocationCategories(activeOnly: Boolean = true): List<LocationCategory>

Lists the categories a nomination can be filed under, driving the form's category picker.

Link copied to clipboard
abstract suspend fun getLocationsByRadius(centerLatitude: Double, centerLongitude: Double, radiusMiles: Double = 5.0, filter: AdvancedLocationFilter = AdvancedLocationFilter()): LocationsPage

Retrieves advanced location markers within a radius of a center point - the full place record, filterable by category, type, amenity and status.

Link copied to clipboard
open suspend fun getLocationsByViewPort(bounds: LocationBounds, filter: AdvancedLocationFilter = AdvancedLocationFilter()): LocationsPage

Retrieves advanced location markers within bounds - the same query as getLocationsByViewPort, addressed by a south-west / north-east box.

abstract suspend fun getLocationsByViewPort(upperLeftLatitude: Double, upperLeftLongitude: Double, lowerRightLatitude: Double, lowerRightLongitude: Double, filter: AdvancedLocationFilter = AdvancedLocationFilter()): LocationsPage

Retrieves advanced location markers within a viewport rectangle - the full place record, filterable by category, type, amenity and status.

Link copied to clipboard
abstract suspend fun getLocationTypes(categoryId: Int? = null, categoryCode: String? = null, activeOnly: Boolean = true): List<LocationTypeDefinition>

Lists the place types a nomination can be filed under, each linked to its category.

Link copied to clipboard
abstract suspend fun getMySubmissions(pageNumber: Int = 1, pageSize: Int = 20, locationCategoryId: Int? = null, sortDirection: LocationSortDirection = LocationSortDirection.DESCENDING): MemberSubmissionsPage

Lists what the member has submitted - nominated places and reported problems - merged into one page ordered by creation date. Rows are the same com.advantahealth.api.facilities.model.MemberSubmission shape the facilities feed renders, so one list serves both.

Link copied to clipboard

The member's recent place searches, most recent first.

Link copied to clipboard
abstract suspend fun isVisitDetectionActive(): Boolean

Whether a monitoring session started with startVisitDetection is currently ACTIVE.

Link copied to clipboard
abstract suspend fun muteFavorite(locationId: Long): List<FavoriteLocation>

Mutes a favorite location - a pause, not an opt-out: it stays in the member's list, but produces neither notifications nor automatic visits until it is unmuted. A running visit-detection session drops its geofence. (Blacklisting is LocationFavoriteType.EXCLUDED, not muting.)

Link copied to clipboard

Nominates a new place on behalf of the member.

Link copied to clipboard
abstract fun openAppSettings()

Opens this app's settings page, where location permission is granted.

Link copied to clipboard
abstract fun openLocationSettings()

Opens the system Location Services settings.

Link copied to clipboard
abstract suspend fun rememberPlaceSearch(suggestion: PlaceSuggestion)

Records a place the member chose, moving it to the front if it is already remembered.

Link copied to clipboard
abstract suspend fun removeFavorite(locationId: Long): AFResult

Removes a location from the member's favorites.

Link copied to clipboard
abstract suspend fun reportLocationProblem(locationId: Long, report: LocationProblemReport): AFResult

Reports a problem about an existing location, carrying the member's corrections as a structured patch (see LocationProblemReport).

Link copied to clipboard
abstract suspend fun searchPlaces(query: String, latitude: Double? = null, longitude: Double? = null, radiusMeters: Double? = null, categoryCode: String? = null): List<PlaceSuggestion>

Searches places matching the query text, optionally biased by a coordinate circle and a category, so a nomination can carry a canonical place id instead of a hand-typed name.

Link copied to clipboard
abstract suspend fun shareLocationNow(): AFHeartbeatStatus

Shares the member's current location right away, outside the automatic triggers - for example after the member opens a map. The opt-in, login, permission and location-fix gates still apply; the throttle does not.

Link copied to clipboard
abstract suspend fun startVisitDetection(): AFGeofencingResult

Starts visit detection: registers a geofence around each of the member's gym favorites and credits automatic visits from them, in the background and across app restarts. Replaces any session already running, including one started with facilities().startMonitoring(). When location sharing is on, each geofence transition also sends the member's location.

Link copied to clipboard
abstract suspend fun stopVisitDetection(): Boolean

Stops visit detection and removes every registered geofence. Location sharing is unaffected.

Link copied to clipboard
abstract fun subscribeToLocationSharing(onStatus: (AFHeartbeatStatus) -> Unit, onError: (Throwable) -> Unit = {}): FlowSubscription

Subscribes to locationSharing with callbacks - the Swift-friendly form. Replays the latest attempt, then each new one; nothing is delivered before the first attempt.

Link copied to clipboard
abstract fun subscribeToLocationSharingEnabled(onState: (Boolean) -> Unit, onError: (Throwable) -> Unit = {}): FlowSubscription

Subscribes to locationSharingEnabled with callbacks - for binding a SwiftUI toggle to the opt-in. Replays the current value, then each change.

Link copied to clipboard
abstract fun subscribeToVisitDetectionStatus(onStatus: (AFGeofencingStatus) -> Unit, onError: (Throwable) -> Unit = {}): FlowSubscription

Subscribes to the monitoring session status. Replays the current value, then emits each distinct change - for example PAUSED to ACTIVE once the member grants Always location.

Link copied to clipboard
abstract fun subscribeToVisitEvents(onEvent: (AFGeofenceEvent) -> Unit, onError: (Throwable) -> Unit = {}): FlowSubscription

Subscribes to visitEvents with callbacks - the Swift-friendly form.

Link copied to clipboard
abstract suspend fun unmuteFavorite(locationId: Long): List<FavoriteLocation>

Unmutes a favorite location - its notifications and automatic visits resume, and a running visit-detection session registers it again.