Facility Finder Map
The goal: a map of the gyms and places near the member. The member pans and zooms to explore, opens a place to see its details and get directions, saves it as a favorite and turns on automatic check-in. The whole screen runs on AFCore.locations().
The flow
-
Find the member. Ask for location access to center the map on the member, and offer to turn on Location Services when they are off. APIs:
AFPermissions.requestPermission(FINE_LOCATION),locations().areLocationServicesEnabled,locations().openLocationSettings. -
Load the places around the member. Load the first set of places in a radius around the member. One filter, built once and reused by every load, picks the categories the map shows. APIs:
locations().getLocationCategories,AdvancedLocationFilter,locations().getLocationsByRadius. -
Load more as the member pans. Load the visible area of the map, with a small margin so the next pan is already covered. When more places match than the map can show, ask the member to zoom in. When a load fails, keep the pins on screen and offer Retry instead of an empty map. APIs:
LocationBounds,LocationBounds.expandedBy,LocationBounds.contains,locations().getLocationsByViewPort. -
Show a place. A detail sheet shows the name, address, opening hours and distance from each map pin, and hands off to the platform's maps app for directions. APIs:
LocationMarker(from each page of results). -
Save it. The member adds the place to their favorites. A gym saved this way is one that automatic check-in watches. APIs:
locations().addFavorite,locations().removeFavorite. -
Turn on automatic check-in. A toggle starts and stops visit detection, as in Automatic Gym Check-In. APIs:
locations().startVisitDetection,locations().stopVisitDetection,locations().isVisitDetectionActive.
Example: load the visible area
- Android (Kotlin)
- iOS (Swift)
// Built once; category codes come from getLocationCategories()
private val filter = AdvancedLocationFilter(categoryCodes = listOf("FITNESS"), limit = 200)
fun onCameraIdle(visible: LocationBounds) {
lifecycleScope.launch {
try {
val page = AFCore.locations().getLocationsByViewPort(
bounds = visible.expandedBy(0.25), // prefetch a margin around the view
filter = filter
)
map.showMarkers(page.items)
if (page.truncated) showZoomInHint()
} catch (t: Throwable) {
showRetry(t) // keep the pins already on screen
}
}
}
// Built once; Swift passes every argument
let filter = AdvancedLocationFilter(
categoryCodes: ["FITNESS"], categoryIds: [], includeChildCategories: true,
typeCodes: [], typeIds: [], amenities: [], amenitiesMode: "any", status: [],
favoritesOnly: false, excludeMuted: false, query: nil, limit: 200
)
func onRegionChanged(_ visible: LocationBounds) {
Task { @MainActor in
do {
let page = try await AFCore.shared.locations().getLocationsByViewPort(
bounds: visible.expandedBy(factor: 0.25), // prefetch a margin around the view
filter: filter
)
mapView.showMarkers(page.items)
if page.truncated { showZoomInHint() }
} catch {
showRetry(error) // keep the pins already on screen
}
}
}
Learn more
- Locations -- search, favorites and visit detection.
- Automatic Gym Check-In -- what happens once the member turns on check-in.
- API Reference -- every call named above.
- Complete, step-by-step integration guides are in AIDE Docs.