Manage Plan¶
Control the plan and query its state through the presenter instance.
Overview¶
- Use
IExpoFpPlanPresenterto send commands and request information from the loaded plan. - All public APIs are available in two forms:
- Coroutine (suspend) functions — recommended.
- Callback functions — for Java or legacy cases.
- Most commands do not return a value. Requests return
ExpoFpResult<T>.
Step 1. Apply Commands¶
Reload a plan¶
Reload the plan with new or previous settings. If a parameter is null, the previous value is
reused.
presenter.reloadPlan(
planLink = ExpoFpLinkType.ExpoKey("YourExpoKey"),
additionalParams = listOf(
ExpoFpPlanParameter.NoOverlay(true),
ExpoFpPlanParameter.HideHeaderLogo(true)
),
locationProvider = YourLocationProvider(),
messageListener = YourMessageListener()
)
Navigation¶
presenter.activateFloor(floor) // floor: ExpoFpFloor
presenter.findLocation() // show current location if available
presenter.fitBounds() // fit to full plan
presenter.fitBounds(bounds = ExpoFpBounds(leftTop = ExpoFpPoint(x = 996.5, y = 787.0), rightBottom = ExpoFpPoint(x = 1015.5, y = 798.0)))
presenter.fitBounds(bounds = ExpoFpBounds(leftTop = ExpoFpPoint(x = 996.5, y = 787.0), rightBottom = ExpoFpPoint(x = 1015.5, y = 798.0)), options = ExpoFpZoomOptions(padding = 200))
presenter.zoomTo(ExpoFpPOISelectors(booths = listOf(ExpoFpPOISelector(name = "10.1-19"))))
presenter.zoomTo(ExpoFpPOISelectors(exhibitors = listOf(ExpoFpPOISelector(externalId = "exhibitorId"))), ExpoFpZoomOptions(padding = 100))
presenter.getBounds(ExpoFpPOISelectors(booths = listOf(ExpoFpPOISelector(name = "10.1-19")))) // returns ExpoFpResult<ExpoFpBounds?>
presenter.reset() // reset the plan to its original state
Change language¶
presenter.changeLanguage(ExpoFpLanguage.English)
presenter.changeLanguage(ExpoFpLanguage.German)
// ... see ExpoFpLanguage for all available languages
Highlight and selection¶
presenter.highlightBooths(listOf("boothExternalId1", "boothExternalId2"))
presenter.highlightExhibitors(listOf("exhibitorExternalId1"))
presenter.highlightEntities(listOf("entityExternalId1", "entityExternalId2"))
presenter.selectBooth("BoothNameOrExternalId")
presenter.selectCategory("CategoryName")
presenter.selectExhibitor("ExhibitorNameOrExternalId")
val position = ExpoFpPosition(x = 8490.0, y = 8188.0)
presenter.selectCurrentPosition(position, focus = true)
presenter.deselectCurrentPosition() // reset current position
Routing¶
Use ExpoFpRouteWaypoint to describe waypoints.
Build a route:
val route = listOf(
ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8490.0, y = 8188.0)),
ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8515.0, y = 8188.0))
)
presenter.selectRoute(route)
Clear the route:
presenter.deselectRoute()
Build a route with start and/or destination point:
// From current position to a booth
presenter.selectRoute(
from = null, // null means current position
to = ExpoFpRouteWaypoint.BoothName("Booth A")
)
// From one booth to another
presenter.selectRoute(
from = ExpoFpRouteWaypoint.BoothName("Booth A"),
to = ExpoFpRouteWaypoint.BoothName("Booth B")
)
// From a position to an exhibitor
presenter.selectRoute(
from = ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8490.0, y = 8188.0)),
to = ExpoFpRouteWaypoint.ExhibitorName("Acme Corp")
)
Build an accessible route:
val route = listOf(
ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8490.0, y = 8188.0)),
ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8515.0, y = 8188.0))
)
presenter.selectAccessibleRoute(route)
The plan stays in accessible-only mode until the route is cleared. To build a regular route afterward, call deselectRoute() before selectRoute(...).
Bookmarks¶
presenter.setBookmarks(
listOf(
ExpoFpBookmark(
name = "BioCycle Africa",
externalId = "RXhoaWJpdG9yXzE4OTc5NDQ=",
isBookmarked = true
)
)
)
GPS tracking¶
Control built-in GPS tracking. For 3rd party location providers, built-in GPS tracking must be disabled to avoid conflicts.
presenter.setBuiltInGpsTrackingEnabled(false) // disable built-in GPS tracking
presenter.setBuiltInGpsTrackingEnabled(true) // enable built-in GPS tracking
// Check if built-in GPS tracking is enabled
val gpsEnabled: ExpoFpResult<Boolean> = presenter.isBuiltInGpsTrackingEnabled()
Note:
setLocationProvider()automatically disables built-in GPS tracking.removeLocationProvider()automatically re-enables it.
Custom message handlers¶
Subscribe to custom JavaScript callbacks on a plan.
val handler = object : IExpoFpCustomMessageHandler {
override fun onMessage(message: String) {
Log.i("ExpoTest", "Custom callback: $message")
}
}
presenter.setMessageHandler(handler, "onCustomButtonClick")
presenter.removeMessageHandler("onCustomButtonClick")
UI controls¶
presenter.setElementsVisibility(
ExpoFpElementsVisibility(
controls = false,
levels = false,
header = false,
overlay = false
)
)
presenter.switchView() // toggle 2D/3D
presenter.zoomIn()
presenter.zoomOut()
Step 2. Request Information¶
All requests return ExpoFpResult<T>.
val booths: ExpoFpResult<List<ExpoFpBooth>> = presenter.boothsList()
val categories: ExpoFpResult<List<ExpoFpCategory>> = presenter.categoriesList()
val exhibitors: ExpoFpResult<List<ExpoFpExhibitor>> = presenter.exhibitorsList()
val visibility: ExpoFpResult<ExpoFpElementsVisibility> = presenter.getElementsVisibility()
val floors: ExpoFpResult<List<ExpoFpFloor>> = presenter.getFloors()
val geoConfig: ExpoFpResult<ExpoFpGeoConfig?> = presenter.getGeoConfig()
val optimized: ExpoFpResult<List<ExpoFpRouteInfo>> =
presenter.getOptimizedRoutes(
waypoints = listOf(
ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8490.0, y = 8188.0)),
ExpoFpRouteWaypoint.Position(ExpoFpPosition(x = 8515.0, y = 8188.0))
)
)
val search: ExpoFpResult<List<ExpoFpSearchModel>> = presenter.search("coffee")
val gpsEnabled: ExpoFpResult<Boolean> = presenter.isBuiltInGpsTrackingEnabled()
Step 3. Callback Alternatives¶
All requests are also available as callback variants:
presenter.boothsList { result -> /* ... */ }
presenter.categoriesList { result -> /* ... */ }
presenter.exhibitorsList { result -> /* ... */ }
presenter.getElementsVisibility { result -> /* ... */ }
presenter.getFloors { result -> /* ... */ }
presenter.getGeoConfig { result -> /* ... */ }
presenter.getOptimizedRoutes(route) { result -> /* ... */ }
presenter.search("coffee") { result -> /* ... */ }
presenter.isBuiltInGpsTrackingEnabled { result -> /* ... */ }
Recommended: Prefer coroutine APIs for cleaner cancellation, lifecycle scoping, and easier composition.
Step 4. Debug Helpers¶
For development, you may run arbitrary JS in the plan:
val evalResult: ExpoFpResult<Any?> =
presenter.evaluateCustomScript("console.log('ping')")
To run a script that awaits promises, pass the body of an async function and return the value explicitly. The result is the JSON text of the returned value. The script runs at once, without waiting for the plan to be ready, so call it after planStatusFlow reports Ready when it uses ___fp. There is no timeout: a promise that never settles keeps the request pending until the calling coroutine is cancelled, the plan is reloaded or the presenter is disposed. Any main frame navigation also fails the request, including one the script itself triggers:
val searchResult: ExpoFpResult<Any?> =
presenter.evaluatePromiseCustomScript(
"""
const result = await ___fp.search('abc');
return result;
""".trimIndent()
)
Enable debug mode:
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
isDebugModeEnabled = true
)
or
presenter.reloadPlan(
planLink = ExpoFpLinkType.ExpoKey("demo"),
isDebugModeEnabled = true
)
Debug mode may slow down initialization. Use it only in debug builds.
Best Practices¶
- Prefer coroutines: cleaner and safer lifecycle integration.
- Check results: always handle both
successanderrorinExpoFpResult<T>. - Be null-aware: some responses may be
null(e.g., direction reset). - Group UI changes: avoid calling multiple UI-affecting commands in very short intervals.
- Debug mode: enable only during development or troubleshooting.