mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Convert ExploreMapController to kotlin
This commit is contained in:
parent
a0214d8ddc
commit
ed6576b385
3 changed files with 220 additions and 215 deletions
|
|
@ -1,213 +0,0 @@
|
|||
package fr.free.nrw.commons.explore.map;
|
||||
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import fr.free.nrw.commons.BaseMarker;
|
||||
import fr.free.nrw.commons.MapController;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.utils.ImageUtils;
|
||||
import fr.free.nrw.commons.utils.LocationUtils;
|
||||
import fr.free.nrw.commons.utils.PlaceUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ExploreMapController extends MapController {
|
||||
|
||||
private final ExploreMapCalls exploreMapCalls;
|
||||
public LatLng latestSearchLocation; // Can be current and camera target on search this area button is used
|
||||
public LatLng currentLocation; // current location of user
|
||||
public double latestSearchRadius = 0; // Any last search radius
|
||||
public double currentLocationSearchRadius = 0; // Search radius of only searches around current location
|
||||
|
||||
|
||||
@Inject
|
||||
public ExploreMapController(ExploreMapCalls explorePlaces) {
|
||||
this.exploreMapCalls = explorePlaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes location as parameter and returns ExplorePlaces info that holds currentLatLng, mediaList,
|
||||
* explorePlaceList and boundaryCoordinates
|
||||
*
|
||||
* @param currentLatLng is current geolocation
|
||||
* @param searchLatLng is the location that we want to search around
|
||||
* @param checkingAroundCurrentLocation is a boolean flag. True if we want to check around
|
||||
* current location, false if another location
|
||||
* @return explorePlacesInfo info that holds currentLatLng, mediaList, explorePlaceList and
|
||||
* boundaryCoordinates
|
||||
*/
|
||||
public ExplorePlacesInfo loadAttractionsFromLocation(LatLng currentLatLng, LatLng searchLatLng,
|
||||
boolean checkingAroundCurrentLocation) {
|
||||
|
||||
if (searchLatLng == null) {
|
||||
Timber.d("Loading attractions explore map, but search is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
ExplorePlacesInfo explorePlacesInfo = new ExplorePlacesInfo();
|
||||
try {
|
||||
explorePlacesInfo.currentLatLng = currentLatLng;
|
||||
latestSearchLocation = searchLatLng;
|
||||
|
||||
List<Media> mediaList = exploreMapCalls.callCommonsQuery(searchLatLng);
|
||||
LatLng[] boundaryCoordinates = {mediaList.get(0).getCoordinates(), // south
|
||||
mediaList.get(0).getCoordinates(), // north
|
||||
mediaList.get(0).getCoordinates(), // west
|
||||
mediaList.get(0).getCoordinates()};// east, init with a random location
|
||||
|
||||
if (searchLatLng != null) {
|
||||
Timber.d("Sorting places by distance...");
|
||||
final Map<Media, Double> distances = new HashMap<>();
|
||||
for (Media media : mediaList) {
|
||||
distances.put(media,
|
||||
computeDistanceBetween(media.getCoordinates(), searchLatLng));
|
||||
// Find boundaries with basic find max approach
|
||||
if (media.getCoordinates().getLatitude()
|
||||
< boundaryCoordinates[0].getLatitude()) {
|
||||
boundaryCoordinates[0] = media.getCoordinates();
|
||||
}
|
||||
if (media.getCoordinates().getLatitude()
|
||||
> boundaryCoordinates[1].getLatitude()) {
|
||||
boundaryCoordinates[1] = media.getCoordinates();
|
||||
}
|
||||
if (media.getCoordinates().getLongitude()
|
||||
< boundaryCoordinates[2].getLongitude()) {
|
||||
boundaryCoordinates[2] = media.getCoordinates();
|
||||
}
|
||||
if (media.getCoordinates().getLongitude()
|
||||
> boundaryCoordinates[3].getLongitude()) {
|
||||
boundaryCoordinates[3] = media.getCoordinates();
|
||||
}
|
||||
}
|
||||
}
|
||||
explorePlacesInfo.mediaList = mediaList;
|
||||
explorePlacesInfo.explorePlaceList = PlaceUtils.mediaToExplorePlace(mediaList);
|
||||
explorePlacesInfo.boundaryCoordinates = boundaryCoordinates;
|
||||
|
||||
// Sets latestSearchRadius to maximum distance among boundaries and search location
|
||||
for (LatLng bound : boundaryCoordinates) {
|
||||
double distance = LocationUtils.calculateDistance(bound.getLatitude(),
|
||||
bound.getLongitude(), searchLatLng.getLatitude(), searchLatLng.getLongitude());
|
||||
if (distance > latestSearchRadius) {
|
||||
latestSearchRadius = distance;
|
||||
}
|
||||
}
|
||||
|
||||
// Our radius searched around us, will be used to understand when user search their own location, we will follow them
|
||||
if (checkingAroundCurrentLocation) {
|
||||
currentLocationSearchRadius = latestSearchRadius;
|
||||
currentLocation = currentLatLng;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return explorePlacesInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads attractions from location for map view, we need to return places in Place data type
|
||||
*
|
||||
* @return baseMarkerOptions list that holds nearby places with their icons
|
||||
*/
|
||||
public static List<BaseMarker> loadAttractionsFromLocationToBaseMarkerOptions(
|
||||
LatLng currentLatLng,
|
||||
final List<Place> placeList,
|
||||
Context context,
|
||||
NearbyBaseMarkerThumbCallback callback,
|
||||
ExplorePlacesInfo explorePlacesInfo) {
|
||||
List<BaseMarker> baseMarkerList = new ArrayList<>();
|
||||
|
||||
if (placeList == null) {
|
||||
return baseMarkerList;
|
||||
}
|
||||
|
||||
VectorDrawableCompat vectorDrawable = null;
|
||||
try {
|
||||
vectorDrawable = VectorDrawableCompat.create(
|
||||
context.getResources(), R.drawable.ic_custom_map_marker_dark, context.getTheme());
|
||||
|
||||
} catch (Resources.NotFoundException e) {
|
||||
// ignore when running tests.
|
||||
}
|
||||
if (vectorDrawable != null) {
|
||||
for (Place explorePlace : placeList) {
|
||||
final BaseMarker baseMarker = new BaseMarker();
|
||||
String distance = formatDistanceBetween(currentLatLng, explorePlace.location);
|
||||
explorePlace.setDistance(distance);
|
||||
|
||||
baseMarker.setTitle(
|
||||
explorePlace.name.substring(5, explorePlace.name.lastIndexOf(".")));
|
||||
baseMarker.setPosition(
|
||||
new fr.free.nrw.commons.location.LatLng(
|
||||
explorePlace.location.getLatitude(),
|
||||
explorePlace.location.getLongitude(), 0));
|
||||
baseMarker.setPlace(explorePlace);
|
||||
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(explorePlace.getThumb())
|
||||
.placeholder(R.drawable.image_placeholder_96)
|
||||
.apply(new RequestOptions().override(96, 96).centerCrop())
|
||||
.into(new CustomTarget<Bitmap>() {
|
||||
// We add icons to markers when bitmaps are ready
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource,
|
||||
@Nullable Transition<? super Bitmap> transition) {
|
||||
baseMarker.setIcon(
|
||||
ImageUtils.addRedBorder(resource, 6, context));
|
||||
baseMarkerList.add(baseMarker);
|
||||
if (baseMarkerList.size()
|
||||
== placeList.size()) { // if true, we added all markers to list and can trigger thumbs ready callback
|
||||
callback.onNearbyBaseMarkerThumbsReady(baseMarkerList,
|
||||
explorePlacesInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCleared(@Nullable Drawable placeholder) {
|
||||
}
|
||||
|
||||
// We add thumbnail icon for images that couldn't be loaded
|
||||
@Override
|
||||
public void onLoadFailed(@Nullable final Drawable errorDrawable) {
|
||||
super.onLoadFailed(errorDrawable);
|
||||
baseMarker.fromResource(context, R.drawable.image_placeholder_96);
|
||||
baseMarkerList.add(baseMarker);
|
||||
if (baseMarkerList.size()
|
||||
== placeList.size()) { // if true, we added all markers to list and can trigger thumbs ready callback
|
||||
callback.onNearbyBaseMarkerThumbsReady(baseMarkerList,
|
||||
explorePlacesInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return baseMarkerList;
|
||||
}
|
||||
|
||||
interface NearbyBaseMarkerThumbCallback {
|
||||
|
||||
// Callback to notify thumbnails of explore markers are added as icons and ready
|
||||
void onNearbyBaseMarkerThumbsReady(List<BaseMarker> baseMarkers,
|
||||
ExplorePlacesInfo explorePlacesInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
package fr.free.nrw.commons.explore.map
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import fr.free.nrw.commons.BaseMarker
|
||||
import fr.free.nrw.commons.MapController
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.utils.ImageUtils.addRedBorder
|
||||
import fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween
|
||||
import fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween
|
||||
import fr.free.nrw.commons.utils.LocationUtils.calculateDistance
|
||||
import fr.free.nrw.commons.utils.PlaceUtils.mediaToExplorePlace
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class ExploreMapController @Inject constructor(
|
||||
private val exploreMapCalls: ExploreMapCalls
|
||||
) : MapController() {
|
||||
// Can be current and camera target on search this area button is used
|
||||
private var latestSearchLocation: LatLng? = null
|
||||
|
||||
// Any last search radius
|
||||
private var latestSearchRadius: Double = 0.0
|
||||
|
||||
// Search radius of only searches around current location
|
||||
private var currentLocationSearchRadius: Double = 0.0
|
||||
|
||||
@JvmField
|
||||
// current location of user
|
||||
var currentLocation: LatLng? = null
|
||||
|
||||
/**
|
||||
* Takes location as parameter and returns ExplorePlaces info that holds currentLatLng, mediaList,
|
||||
* explorePlaceList and boundaryCoordinates
|
||||
*
|
||||
* @param currentLatLng is current geolocation
|
||||
* @param searchLatLng is the location that we want to search around
|
||||
* @param checkingAroundCurrentLocation is a boolean flag. True if we want to check around
|
||||
* current location, false if another location
|
||||
* @return explorePlacesInfo info that holds currentLatLng, mediaList, explorePlaceList and
|
||||
* boundaryCoordinates
|
||||
*/
|
||||
fun loadAttractionsFromLocation(
|
||||
currentLatLng: LatLng?, searchLatLng: LatLng?,
|
||||
checkingAroundCurrentLocation: Boolean
|
||||
): ExplorePlacesInfo? {
|
||||
if (searchLatLng == null) {
|
||||
Timber.d("Loading attractions explore map, but search is null")
|
||||
return null
|
||||
}
|
||||
|
||||
val explorePlacesInfo = ExplorePlacesInfo()
|
||||
try {
|
||||
explorePlacesInfo.currentLatLng = currentLatLng
|
||||
latestSearchLocation = searchLatLng
|
||||
|
||||
val mediaList = exploreMapCalls.callCommonsQuery(searchLatLng)
|
||||
val boundaryCoordinates = arrayOf(
|
||||
mediaList[0].coordinates!!, // south
|
||||
mediaList[0].coordinates!!, // north
|
||||
mediaList[0].coordinates!!, // west
|
||||
mediaList[0].coordinates!!
|
||||
) // east, init with a random location
|
||||
|
||||
Timber.d("Sorting places by distance...")
|
||||
val distances: MutableMap<Media, Double> = HashMap()
|
||||
for (media in mediaList) {
|
||||
distances[media] = computeDistanceBetween(media.coordinates!!, searchLatLng)
|
||||
// Find boundaries with basic find max approach
|
||||
if (media.coordinates!!.latitude
|
||||
< boundaryCoordinates[0]!!.latitude
|
||||
) {
|
||||
boundaryCoordinates[0] = media.coordinates!!
|
||||
}
|
||||
if (media.coordinates!!.latitude
|
||||
> boundaryCoordinates[1]!!.latitude
|
||||
) {
|
||||
boundaryCoordinates[1] = media.coordinates!!
|
||||
}
|
||||
if (media.coordinates!!.longitude
|
||||
< boundaryCoordinates[2]!!.longitude
|
||||
) {
|
||||
boundaryCoordinates[2] = media.coordinates!!
|
||||
}
|
||||
if (media.coordinates!!.longitude
|
||||
> boundaryCoordinates[3]!!.longitude
|
||||
) {
|
||||
boundaryCoordinates[3] = media.coordinates!!
|
||||
}
|
||||
}
|
||||
explorePlacesInfo.mediaList = mediaList
|
||||
explorePlacesInfo.explorePlaceList = mediaToExplorePlace(mediaList)
|
||||
explorePlacesInfo.boundaryCoordinates = boundaryCoordinates
|
||||
|
||||
// Sets latestSearchRadius to maximum distance among boundaries and search location
|
||||
for ((latitude, longitude) in boundaryCoordinates) {
|
||||
val distance = calculateDistance(
|
||||
latitude,
|
||||
longitude, searchLatLng.latitude, searchLatLng.longitude
|
||||
)
|
||||
if (distance > latestSearchRadius) {
|
||||
latestSearchRadius = distance
|
||||
}
|
||||
}
|
||||
|
||||
// Our radius searched around us, will be used to understand when user search their own location, we will follow them
|
||||
if (checkingAroundCurrentLocation) {
|
||||
currentLocationSearchRadius = latestSearchRadius
|
||||
currentLocation = currentLatLng
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
}
|
||||
return explorePlacesInfo
|
||||
}
|
||||
|
||||
interface NearbyBaseMarkerThumbCallback {
|
||||
// Callback to notify thumbnails of explore markers are added as icons and ready
|
||||
fun onNearbyBaseMarkerThumbsReady(
|
||||
baseMarkers: List<BaseMarker>?,
|
||||
explorePlacesInfo: ExplorePlacesInfo?
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Loads attractions from location for map view, we need to return places in Place data type
|
||||
*
|
||||
* @return baseMarkerOptions list that holds nearby places with their icons
|
||||
*/
|
||||
fun loadAttractionsFromLocationToBaseMarkerOptions(
|
||||
currentLatLng: LatLng?,
|
||||
placeList: List<Place>?,
|
||||
context: Context,
|
||||
callback: NearbyBaseMarkerThumbCallback,
|
||||
explorePlacesInfo: ExplorePlacesInfo?
|
||||
): List<BaseMarker> {
|
||||
val baseMarkerList: MutableList<BaseMarker> = ArrayList()
|
||||
|
||||
if (placeList == null) {
|
||||
return baseMarkerList
|
||||
}
|
||||
|
||||
var vectorDrawable: VectorDrawableCompat? = null
|
||||
try {
|
||||
vectorDrawable = VectorDrawableCompat.create(
|
||||
context.resources, R.drawable.ic_custom_map_marker_dark, context.theme
|
||||
)
|
||||
} catch (e: Resources.NotFoundException) {
|
||||
// ignore when running tests.
|
||||
}
|
||||
if (vectorDrawable != null) {
|
||||
for (explorePlace in placeList) {
|
||||
val baseMarker = BaseMarker()
|
||||
val distance = formatDistanceBetween(currentLatLng, explorePlace.location)
|
||||
explorePlace.setDistance(distance)
|
||||
|
||||
baseMarker.title =
|
||||
explorePlace.name.substring(5, explorePlace.name.lastIndexOf("."))
|
||||
baseMarker.position = LatLng(
|
||||
explorePlace.location.latitude,
|
||||
explorePlace.location.longitude, 0f
|
||||
)
|
||||
baseMarker.place = explorePlace
|
||||
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(explorePlace.thumb)
|
||||
.placeholder(R.drawable.image_placeholder_96)
|
||||
.apply(RequestOptions().override(96, 96).centerCrop())
|
||||
.into(object : CustomTarget<Bitmap>() {
|
||||
// We add icons to markers when bitmaps are ready
|
||||
override fun onResourceReady(
|
||||
resource: Bitmap,
|
||||
transition: Transition<in Bitmap>?
|
||||
) {
|
||||
baseMarker.icon = addRedBorder(resource, 6, context)
|
||||
baseMarkerList.add(baseMarker)
|
||||
if (baseMarkerList.size == placeList.size) {
|
||||
// if true, we added all markers to list and can trigger thumbs ready callback
|
||||
callback.onNearbyBaseMarkerThumbsReady(
|
||||
baseMarkerList,
|
||||
explorePlacesInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadCleared(placeholder: Drawable?) = Unit
|
||||
|
||||
// We add thumbnail icon for images that couldn't be loaded
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(errorDrawable)
|
||||
baseMarker.fromResource(context, R.drawable.image_placeholder_96)
|
||||
baseMarkerList.add(baseMarker)
|
||||
if (baseMarkerList.size == placeList.size) {
|
||||
// if true, we added all markers to list and can trigger thumbs ready callback
|
||||
callback.onNearbyBaseMarkerThumbsReady(
|
||||
baseMarkerList,
|
||||
explorePlacesInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return baseMarkerList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -180,8 +180,7 @@ public class ExploreMapPresenter
|
|||
}
|
||||
|
||||
void prepareNearbyBaseMarkers(MapController.ExplorePlacesInfo explorePlacesInfo) {
|
||||
exploreMapController
|
||||
.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng,
|
||||
ExploreMapController.Companion.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng,
|
||||
// Curlatlang will be used to calculate distances
|
||||
(List<Place>) explorePlacesInfo.explorePlaceList,
|
||||
exploreMapFragmentView.getContext(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue