Explore nearby pictures (#4910)

* Add map fragment for explore and search

* Create structure of explore map by defining view and user action interfaces to presenter

* Add methods to map start, bottom sheet and permission

* Make the simple map visible

* Imitate methods from nearby map for permission needed and non needed map initialisation operations, however, needs to be tested and reactor

* a level of abstraction

* update media params to include coordinates

* Implement pageable presenter to explore

* Create Root fragment for map and media

* Iplement two presenter one for map operations, the other for pageable operations

* Construct general structure for both explore with search query and just by location

* fix injection issue

* Make default explore work with zoom level

* increase offscreen page limit with newly added fragment

* Make two distinct api calls for search with and without query

* Before trying to use same presenter for both search with and without query

* Add notes for Madhur

* Add Madhur's fixes for binding

* Call serch with and without query from the same spot

* partially solve zoom issue

* Make tab view unswipble while map is being used on search activity

* make viewpager unswipable while map is being used

* Code cleanup and reverting unnecessry edits

* Add search this area methods

* Implement search this area button functionality

* Fix search this area button, current location FAB and bottom attribution UI elements

* Add marker click action

* Solve bookmarkdao injection issue

* Make display bottom sheet details on marker click

* remove label and set bottom sheet behavior

* Remove irrelevan buttons like wikidata and article buttons

* Cancel bookmark feature for commons images for know, needs to be thought

* Add search this area button

* Add location off dialog

* Implement back button for explore map fragment while not on search activity

* Make thumbnails visible, they need some styling though

* Make gridle views even more beautiful

* Remove classes added to support query

* Remove query related code from Reach Activity

* Solve two progressbar issue

* Remove query related ekstra codes

* Remove not needed anymore callback

* Make medai details work

* Remove all old removed code dependencies

* Solve initial load takes too long issue

* Solve current position track

* Add placeholder for possible load issues

* Add red stroke to bitmap

* Add borders to rectangles

* Change media details text to details

* Fix file name extension anf File: prefix

* Fix some code style issues

* Fix some style issues

* Fix style issues

* Fix build issue

* Fix test about etMediaListFromSearch

* Fix test issue with Seacrh Activity

* Fix conflict mark
This commit is contained in:
neslihanturan 2022-04-14 11:28:17 +03:00 committed by GitHub
parent 7655562272
commit ee1bf4b5b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 2172 additions and 59 deletions

View file

@ -5,10 +5,12 @@ import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.net.Uri;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.exifinterface.media.ExifInterface;
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.references.CloseableReference;
@ -340,4 +342,19 @@ public class ImageUtils {
return errorMessage.toString();
}
/**
* Adds red border to a bitmap
* @param bitmap
* @param borderSize
* @param context
* @return
*/
public static Bitmap addRedBorder(Bitmap bitmap, int borderSize, Context context) {
Bitmap bmpWithBorder = Bitmap.createBitmap(bitmap.getWidth() + borderSize * 2, bitmap.getHeight() + borderSize * 2, bitmap.getConfig());
Canvas canvas = new Canvas(bmpWithBorder);
canvas.drawColor(ContextCompat.getColor(context, R.color.deleteRed));
canvas.drawBitmap(bitmap, borderSize, borderSize, null);
return bmpWithBorder;
}
}

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.utils;
import fr.free.nrw.commons.location.LatLng;
import timber.log.Timber;
public class LocationUtils {
public static LatLng mapBoxLatLngToCommonsLatLng(com.mapbox.mapboxsdk.geometry.LatLng mapBoxLatLng) {
@ -10,4 +11,36 @@ public class LocationUtils {
public static com.mapbox.mapboxsdk.geometry.LatLng commonsLatLngToMapBoxLatLng(LatLng commonsLatLng) {
return new com.mapbox.mapboxsdk.geometry.LatLng(commonsLatLng.getLatitude(), commonsLatLng.getLongitude());
}
public static LatLng deriveUpdatedLocationFromSearchQuery(String customQuery) {
LatLng latLng = null;
final int indexOfPrefix = customQuery.indexOf("Point(");
if (indexOfPrefix == -1) {
Timber.e("Invalid prefix index - Seems like user has entered an invalid query");
return latLng;
}
final int indexOfSuffix = customQuery.indexOf(")\"", indexOfPrefix);
if (indexOfSuffix == -1) {
Timber.e("Invalid suffix index - Seems like user has entered an invalid query");
return latLng;
}
String latLngString = customQuery.substring(indexOfPrefix+"Point(".length(), indexOfSuffix);
if (latLngString.isEmpty()) {
return null;
}
String latLngArray[] = latLngString.split(" ");
if (latLngArray.length != 2) {
return null;
}
try {
latLng = new LatLng(Double.parseDouble(latLngArray[1].trim()),
Double.parseDouble(latLngArray[0].trim()), 1f);
}catch (Exception e){
Timber.e("Error while parsing user entered lat long: %s", e);
}
return latLng;
}
}

View file

@ -0,0 +1,73 @@
package fr.free.nrw.commons.utils;
import android.content.Context;
import android.content.res.Configuration;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.location.LocationUpdateListener;
import fr.free.nrw.commons.nearby.Place;
import timber.log.Timber;
public class MapUtils {
public static final float ZOOM_LEVEL = 14f;
public static final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.005;
public static final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.004;
public static final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
public static final float ZOOM_OUT = 0f;
public static final LatLng defaultLatLng = new fr.free.nrw.commons.location.LatLng(51.50550,-0.07520,1f);
public static void centerMapToPlace(Place placeToCenter, MapboxMap mapBox, Place lastPlaceToCenter, Context context) {
Timber.d("Map is centered to place");
final double cameraShift;
if(null != placeToCenter){
lastPlaceToCenter = placeToCenter;
}
if (null != lastPlaceToCenter) {
final Configuration configuration = context.getResources().getConfiguration();
if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
cameraShift = CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT;
} else {
cameraShift = CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE;
}
final CameraPosition position = new CameraPosition.Builder()
.target(LocationUtils.commonsLatLngToMapBoxLatLng(
new fr.free.nrw.commons.location.LatLng(lastPlaceToCenter.location.getLatitude() - cameraShift,
lastPlaceToCenter.getLocation().getLongitude(),
0))) // Sets the new camera position
.zoom(ZOOM_LEVEL) // Same zoom level
.build();
mapBox.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000);
}
}
public static void centerMapToDefaultLatLng(MapboxMap mapBox) {
final CameraPosition position = new CameraPosition.Builder()
.target(LocationUtils.commonsLatLngToMapBoxLatLng(defaultLatLng))
.zoom(MapUtils.ZOOM_OUT)
.build();
if(mapBox != null){
mapBox.moveCamera(CameraUpdateFactory.newCameraPosition(position));
}
}
public static void registerUnregisterLocationListener(final boolean removeLocationListener, LocationServiceManager locationManager, LocationUpdateListener locationUpdateListener) {
try {
if (removeLocationListener) {
locationManager.unregisterLocationManager();
locationManager.removeLocationListener(locationUpdateListener);
Timber.d("Location service manager unregistered and removed");
} else {
locationManager.addLocationListener(locationUpdateListener);
locationManager.registerLocationManager();
Timber.d("Location service manager added and registered");
}
}catch (final Exception e){
Timber.e(e);
//Broadcasts are tricky, should be catchedonR
}
}
}

View file

@ -1,5 +1,10 @@
package fr.free.nrw.commons.utils;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.nearby.Sitelinks;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -23,4 +28,27 @@ public class PlaceUtils {
return new LatLng(latitude, longitude, 0);
}
/**
* Turns a Media list to a Place list by creating a new list in Place type
* @param mediaList
* @return
*/
public static List<Place> mediaToExplorePlace( List<Media> mediaList) {
List<Place> explorePlaceList = new ArrayList<>();
for (Media media :mediaList) {
explorePlaceList.add(new Place(media.getFilename(),
media.getFallbackDescription(),
media.getCoordinates(),
media.getCategories().toString(),
new Sitelinks.Builder()
.setCommonsLink(media.getPageTitle().getCanonicalUri())
.setWikipediaLink("") // we don't necessarily have them, can be fetched later
.setWikidataLink("") // we don't necessarily have them, can be fetched later
.build(),
media.getImageUrl(),
media.getThumbUrl()));
}
return explorePlaceList;
}
}