Skip to main content
GuidesAPI ReferenceExamples

Favourites

|

In this guide you will learn how to insert a landmark into the favourites, and also show to remove a landmark from the favourites.

Initial landmark
Favourite landmark

note

The star icon shows that the landmark is added to the favorites when it is filled, and not added to the favorites when it is just a contour.

In the class MainActivity : AppCompatActivity(), an instance of each of the following is created:

  • var store: LandmarkStore a landmark store, so the favorited landmark(s) can be written into the data folder;
  • val searchService = SearchService() a search service, so that the id of a resulted landmark can be obtained. The search service implements the onStarted and onCompleted callbacks. When the search completes, if the result list is not empty, then the first item in the result list (at index 0) is taken and the camera flies to the location of that result.
MainActivity.kt
private lateinit var store: LandmarkStore
private val searchService = SearchService(
onStarted = {
progressBar.visibility = View.VISIBLE
showStatusMessage("Search service has started!")
},

onCompleted = { results, errorCode, _ ->
progressBar.visibility = View.GONE
showStatusMessage("Search service completed with error code: $errorCode")
a
when (errorCode)
{
GemError.NoError ->
{
if (results.isNotEmpty())
{
val landmark = results[0]
flyTo(landmark)
displayLocationInfo(landmark)
showStatusMessage("The search completed without errors.")
}
else
{
// The search completed without errors, but there were no results found.
showStatusMessage("The search completed without errors, but there were no results found.")
}
}
GemError.Cancel ->
{
// The search action was cancelled.
}
else ->
{
// There was a problem at computing the search operation.
showDialog("Search service error: ${GemError.getMessage(errorCode)}")
}
}
EspressoIdlingResource.decrement()
}
)

The flyTo(landmark) shows on the map the searched landmark. After the search completes and the camera flies to the target, it is up to the user whether to add it to the favorites or not, using the button in the lower right corner of the viewport.

MainActivity.kt
private fun flyTo(landmark: Landmark) = SdkCall.execute {
landmark.geographicArea?.let { area ->
gemSurfaceView.mapView?.let { mainMapView ->
// Center the map on a specific area using the provided animation.
mainMapView.centerOnArea(area)

// Highlights a specific area on the map using the provided settings.
val displaySettings = HighlightRenderSettings(
EHighlightOptions.ShowContour,
Rgba(255, 98, 0, 255),
Rgba(255, 98, 0, 255),
0.75
)
mainMapView.activateHighlightLandmarks(landmark, displaySettings)
}
}
}

The displayLocationInfo() function is called when the search completes with a non-empty result list. The function displays the name and coordinates of the landmark on screen, as well as a yellow star-shaped icon.
A click listener is set for the star-shaped icon, imageView.setOnClickListener, so the landmark is added to the favorites if the icon is clicked and the landmark is not already in the favorites; and conversely, the landmark is removed from the favorites if the icon is clicked and the landmark is already in the favorites.

MainActivity.kt
private fun displayLocationInfo(landmark: Landmark)
{
// Display a view containing the necessary information about the landmark.
var name = ""
var coordinates = ""
EspressoIdlingResource.increment()

SdkCall.execute {
name = landmark.name ?: "Unnamed Location"
landmark.coordinates?.apply { coordinates = "$latitude, $longitude" }
}

Util.postOnMain {
locationDetails.apply {
val nameView = findViewById<TextView>(R.id.name)
val coordinatesView = findViewById<TextView>(R.id.coordinates)
val imageView = findViewById<ImageView>(R.id.favourites_icon)

// Update the favourites icon based on the status of the landmark.
updateFavouritesIcon(imageView, getFavouriteId(landmark) != -1)

// Display the name and coordinates of the landmark.
nameView.text = name
coordinatesView.text = coordinates

// Treat favourites icon click event (Add/ Remove from favourites)
imageView.setOnClickListener {
val landmarkId = getFavouriteId(landmark)
if (landmarkId != -1)
{
deleteFromFavourites(landmarkId)
updateFavouritesIcon(imageView, false)
showStatusMessage("The landmark was deleted from favourites.")
}
else
{
addToFavourites(landmark)
updateFavouritesIcon(imageView, true)
showStatusMessage("The landmark was added to favourites.")
}
}
this.visibility = View.VISIBLE
}

EspressoIdlingResource.decrement()
}
}

Note that to add or remove a landmark from the favorites, the ID of that landmark must be obtained, using the getFavouriteId() function which does a linear search through all landmarks in a specified set, and looks for coordinates that match within a specified threshold.

MainActivity.kt
private fun getFavouriteId(landmark: Landmark): Int = SdkCall.execute {
/*
Get the ID of the landmark saved in the store so we can use it to remove it
or to check if it's already a favourite.
*/
val radius = 5.0 // meters
val area = landmark.coordinates?.let { RectangleGeographicArea(it, radius, radius) }
val landmarks = area?.let { store.getLandmarksByArea(it) } ?: return@execute -1

val threshold = 0.00001
landmarks.forEach {
val itCoordinates = it.coordinates
val landmarkCoordinates = landmark.coordinates

if (itCoordinates != null && landmarkCoordinates != null)
{
if ((itCoordinates.latitude - landmarkCoordinates.latitude < threshold) && (itCoordinates.longitude - landmarkCoordinates.longitude < threshold)) return@execute it.id
}
else return@execute -1
}
-1
} ?: -1

MainActivity overrides the onCreate() function which checks that internet access is available, then calls the createStore() function, which instantiates a Landmark store to for the favorites, and then does a search for a hardcoded target:

  • createStore()
  • val text = "Statue of Liberty New York"
  • val coordinates = Coordinates(0.0, 0.0)
  • searchService.searchByFilter(text, coordinates)
Note

The coordinates of the target are not required for the search and can be set to zero.

MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

imageSize = resources.getDimensionPixelSize(R.dimen.image_size)

progressBar = findViewById(R.id.progressBar)
gemSurfaceView = findViewById(R.id.gem_surface)
locationDetails = findViewById(R.id.location_details)
statusText = findViewById(R.id.status_text)
EspressoIdlingResource.increment()
SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
if (!isReady) return@onMapDataReady

// Defines an action that should be done after the world map is ready.
SdkCall.execute {
createStore()

val text = "Statue of Liberty New York"
val coordinates = Coordinates(40.68925476, -74.04456329)

searchService.searchByFilter(text, coordinates)
}
}

SdkSettings.onApiTokenRejected = {
/*
The TOKEN you provided in the AndroidManifest.xml file was rejected.
Make sure you provide the correct value, or if you don't have a TOKEN,
check the magiclane.com website, sign up/sign in and generate one.
*/
showDialog("TOKEN REJECTED")
}

if (!Util.isInternetConnected(this)) {
showDialog("You must be connected to the internet!")
}

onBackPressedDispatcher.addCallback(this){
finish()
exitProcess(0)
}
}

private fun createStore()
{
store = LandmarkStoreService().createLandmarkStore("Favourites")?.first!!
gemSurfaceView.mapView?.let { mainMapView ->
SdkCall.execute {
mainMapView.preferences?.landmarkStores?.addAllStoreCategories(store.id)
}
}
}