Made Split to Nearby Query into a fast query for coordinates + a details query for each pin (#5731)

* Splitted the query

* Made changes to the query

* Improvised query

* Improvised query by dividing in the batches

* Fixed failing tests

* Improved batches

* Improved sorting

* Fixes issue caused by search this area button

* Fixed failing tests

* Fixed unnecessary reloads on onResume

* Fixed few pins not loading on changing apps

* Improved zoom level and fixed the pins not loading from the center

* Removed toggle chips and changed pin's color

* Fixed wikidata url

* Fixed unit tests

* Implemented retry with delay of 5000ms

* Fixed exception issue and pins issue

* Added change color icon to pin

* Improved pin clicking

* Removed search this area button

* Implemented caching of places

* Fixed unit test

* Factorized methods

* Changed primary key from location to entity id

* Fixed tests

* Fixed conflicts

* Fixed unit test

* Fixed unit test

* Fixed the bug

* Fixed issue with pin loading on the first launch

* Updated javadocs

* Temporary commit - only for testing

* Replaced Temporary commit

* Temporary commit - Added jcenter

* Made minor changes

* Fixed unit tests

* Fixed unit tests

* Fixed minor bug
This commit is contained in:
Kanahia 2024-08-04 06:05:09 +05:30 committed by GitHub
parent ba6c8fe8d0
commit 2d63f351ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 1147 additions and 814 deletions

View file

@ -6,6 +6,8 @@ import androidx.room.TypeConverters
import fr.free.nrw.commons.contributions.Contribution import fr.free.nrw.commons.contributions.Contribution
import fr.free.nrw.commons.contributions.ContributionDao import fr.free.nrw.commons.contributions.ContributionDao
import fr.free.nrw.commons.customselector.database.* import fr.free.nrw.commons.customselector.database.*
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.nearby.PlaceDao
import fr.free.nrw.commons.review.ReviewDao import fr.free.nrw.commons.review.ReviewDao
import fr.free.nrw.commons.review.ReviewEntity import fr.free.nrw.commons.review.ReviewEntity
import fr.free.nrw.commons.upload.depicts.Depicts import fr.free.nrw.commons.upload.depicts.Depicts
@ -15,10 +17,11 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao
* The database for accessing the respective DAOs * The database for accessing the respective DAOs
* *
*/ */
@Database(entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class], version = 16, exportSchema = false) @Database(entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class], version = 18, exportSchema = false)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
abstract fun contributionDao(): ContributionDao abstract fun contributionDao(): ContributionDao
abstract fun PlaceDao(): PlaceDao
abstract fun DepictsDao(): DepictsDao; abstract fun DepictsDao(): DepictsDao;
abstract fun UploadedStatusDao(): UploadedStatusDao; abstract fun UploadedStatusDao(): UploadedStatusDao;
abstract fun NotForUploadStatusDao(): NotForUploadStatusDao abstract fun NotForUploadStatusDao(): NotForUploadStatusDao

View file

@ -8,8 +8,10 @@ import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.contributions.ChunkInfo; import fr.free.nrw.commons.contributions.ChunkInfo;
import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.Sitelinks;
import fr.free.nrw.commons.upload.WikidataPlace; import fr.free.nrw.commons.upload.WikidataPlace;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import java.lang.reflect.Type;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -134,6 +136,18 @@ public class Converters {
return readObjectWithTypeToken(depictedItems, new TypeToken<List<DepictedItem>>() {}); return readObjectWithTypeToken(depictedItems, new TypeToken<List<DepictedItem>>() {});
} }
@TypeConverter
public static Sitelinks sitelinksFromString(String value) {
Type type = new TypeToken<Sitelinks>() {}.getType();
return new Gson().fromJson(value, type);
}
@TypeConverter
public static String fromSitelinks(Sitelinks sitelinks) {
Gson gson = new Gson();
return gson.toJson(sitelinks);
}
private static String writeObjectToString(Object object) { private static String writeObjectToString(Object object) {
return object == null ? null : getGson().toJson(object); return object == null ? null : getGson().toJson(object);
} }

View file

@ -24,6 +24,7 @@ import fr.free.nrw.commons.data.DBOpenHelper;
import fr.free.nrw.commons.db.AppDatabase; import fr.free.nrw.commons.db.AppDatabase;
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.nearby.PlaceDao;
import fr.free.nrw.commons.review.ReviewDao; import fr.free.nrw.commons.review.ReviewDao;
import fr.free.nrw.commons.settings.Prefs; import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.UploadController; import fr.free.nrw.commons.upload.UploadController;
@ -275,6 +276,11 @@ public class CommonsApplicationModule {
return appDatabase.contributionDao(); return appDatabase.contributionDao();
} }
@Provides
public PlaceDao providesPlaceDao(AppDatabase appDatabase) {
return appDatabase.PlaceDao();
}
/** /**
* Get the reference of DepictsDao class. * Get the reference of DepictsDao class.
*/ */

View file

@ -397,6 +397,54 @@ public class OkHttpJsonApiClient {
throw new Exception(response.message()); throw new Exception(response.message());
} }
/**
* Retrieves a list of places based on the provided list of places and language.
*
* @param placeList A list of Place objects for which to fetch information.
* @param language The language code to use for the query.
* @return A list of Place objects with additional information retrieved from Wikidata, or null
* if an error occurs.
* @throws IOException If there is an issue with reading the resource file or executing the HTTP
* request.
*/
@Nullable
public List<Place> getPlaces(
final List<Place> placeList, final String language) throws IOException {
final String wikidataQuery = FileUtils.readFromResource("/queries/query_for_item.rq");
String qids = "";
for (final Place place : placeList) {
qids += "\n" + ("wd:" + place.getWikiDataEntityId());
}
final String query = wikidataQuery
.replace("${ENTITY}", qids)
.replace("${LANG}", language);
final HttpUrl.Builder urlBuilder = HttpUrl
.parse(sparqlQueryUrl)
.newBuilder()
.addQueryParameter("query", query)
.addQueryParameter("format", "json");
final Request request = new Request.Builder()
.url(urlBuilder.build())
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
final String json = response.body().string();
final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class);
final List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings();
final List<Place> places = new ArrayList<>();
for (final NearbyResultItem item : bindings) {
final Place placeFromNearbyItem = Place.from(item);
places.add(placeFromNearbyItem);
}
return places;
} else {
throw new IOException("Unexpected response code: " + response.code());
}
}
}
/** /**
* Make API Call to get Places * Make API Call to get Places
* *

View file

@ -131,6 +131,17 @@ public class NearbyController extends MapController {
); );
} }
/**
* Retrieves a list of places based on the provided list of places and language.
*
* @param placeList A list of Place objects for which to fetch information.
* @return A list of Place objects obtained from the Wikidata query.
* @throws Exception If an error occurs during the retrieval process.
*/
public List<Place> getPlaces(List<Place> placeList) throws Exception {
return nearbyPlaces.getPlaces(placeList, Locale.getDefault().getLanguage());
}
public static LatLng calculateNorthEast(double latitude, double longitude, double distance) { public static LatLng calculateNorthEast(double latitude, double longitude, double distance) {
double lat1 = Math.toRadians(latitude); double lat1 = Math.toRadians(latitude);
double deltaLat = distance * 0.008; double deltaLat = distance * 0.008;

View file

@ -120,6 +120,22 @@ public class NearbyPlaces {
customQuery); customQuery);
} }
/**
* Retrieves a list of places based on the provided list of places and language.
*
* This method fetches place information from a Wikidata query using the specified language.
*
* @param placeList A list of Place objects for which to fetch information.
* @param lang The language code to use for the query.
* @return A list of Place objects obtained from the Wikidata query.
* @throws Exception If an error occurs during the retrieval process.
*/
public List<Place> getPlaces(final List<Place> placeList,
final String lang) throws Exception {
return okHttpJsonApiClient
.getPlaces(placeList, lang);
}
/** /**
* Runs the Wikidata query to retrieve the KML String * Runs the Wikidata query to retrieve the KML String
* *

View file

@ -3,34 +3,38 @@ package fr.free.nrw.commons.nearby;
import android.net.Uri; import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.room.Entity;
import org.apache.commons.lang3.StringUtils; import androidx.room.PrimaryKey;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.model.NearbyResultItem; import fr.free.nrw.commons.nearby.model.NearbyResultItem;
import fr.free.nrw.commons.utils.LocationUtils;
import fr.free.nrw.commons.utils.PlaceUtils; import fr.free.nrw.commons.utils.PlaceUtils;
import org.apache.commons.lang3.StringUtils;
import timber.log.Timber; import timber.log.Timber;
/** /**
* A single geolocated Wikidata item * A single geolocated Wikidata item
*/ */
@Entity(tableName = "place")
public class Place implements Parcelable { public class Place implements Parcelable {
public final String language; public String language;
public final String name; public String name;
private final Label label; private Label label;
private final String longDescription; private String longDescription;
public final LatLng location; public LatLng location;
private final String category; @PrimaryKey @NonNull
public final String pic; public String entityID;
private String category;
public String pic;
// exists boolean will tell whether the place exists or not, // exists boolean will tell whether the place exists or not,
// For a place to be existing both destroyed and endTime property should be null but it is also not necessary for a non-existing place to have both properties either one property is enough (in such case that not given property will be considered as null). // For a place to be existing both destroyed and endTime property should be null but it is also not necessary for a non-existing place to have both properties either one property is enough (in such case that not given property will be considered as null).
public final Boolean exists; public Boolean exists;
public String distance; public String distance;
public final Sitelinks siteLinks; public Sitelinks siteLinks;
private boolean isMonument; private boolean isMonument;
private String thumb; private String thumb;
@ -44,9 +48,25 @@ public class Place implements Parcelable {
pic = null; pic = null;
exists = null; exists = null;
siteLinks = null; siteLinks = null;
entityID = null;
} }
public Place(String language,String name, Label label, String longDescription, LatLng location, String category, Sitelinks siteLinks, String pic, Boolean exists) { public Place(String language, String name, Label label, String longDescription, LatLng location,
String category, Sitelinks siteLinks, String pic, Boolean exists, String entityID) {
this.language = language;
this.name = name;
this.label = label;
this.longDescription = longDescription;
this.location = location;
this.category = category;
this.siteLinks = siteLinks;
this.pic = (pic == null) ? "" : pic;
this.exists = exists;
this.entityID = entityID;
}
public Place(String language, String name, Label label, String longDescription, LatLng location,
String category, Sitelinks siteLinks, String pic, Boolean exists) {
this.language = language; this.language = language;
this.name = name; this.name = name;
this.label = label; this.label = label;
@ -58,7 +78,8 @@ public class Place implements Parcelable {
this.exists = exists; this.exists = exists;
} }
public Place(String name, String longDescription, LatLng location, String category, Sitelinks siteLinks, String pic, String thumb) { public Place(String name, String longDescription, LatLng location, String category,
Sitelinks siteLinks, String pic, String thumb, String entityID) {
this.name = name; this.name = name;
this.longDescription = longDescription; this.longDescription = longDescription;
this.location = location; this.location = location;
@ -69,6 +90,7 @@ public class Place implements Parcelable {
this.language = null; this.language = null;
this.label = null; this.label = null;
this.exists = true; this.exists = true;
this.entityID = entityID;
} }
public Place(Parcel in) { public Place(Parcel in) {
@ -84,15 +106,23 @@ public class Place implements Parcelable {
String existString = in.readString(); String existString = in.readString();
this.exists = Boolean.parseBoolean(existString); this.exists = Boolean.parseBoolean(existString);
this.isMonument = in.readInt() == 1; this.isMonument = in.readInt() == 1;
this.entityID = in.readString();
} }
public static Place from(NearbyResultItem item) { public static Place from(NearbyResultItem item) {
String itemClass = item.getClassName().getValue(); String itemClass = item.getClassName().getValue();
String classEntityId = ""; String classEntityId = "";
if (!StringUtils.isBlank(itemClass)) { if (!StringUtils.isBlank(itemClass)) {
classEntityId = itemClass.replace("http://www.wikidata.org/entity/", ""); classEntityId = itemClass.replace("http://www.wikidata.org/entity/", "");
} }
String entityId = "";
if (!StringUtils.isBlank(item.getItem().getValue())){
entityId = item.getItem().getValue().replace("http://www.wikidata.org/entity/", "");
}
// Set description when not null and not empty // Set description when not null and not empty
String description = (item.getDescription().getValue() != null && !item.getDescription().getValue().isEmpty()) ? item.getDescription().getValue() : ""; String description =
(item.getDescription().getValue() != null && !item.getDescription().getValue()
.isEmpty()) ? item.getDescription().getValue() : "";
// When description is "?" but we have a valid label, just use the label. So replace "?" by "" in description // When description is "?" but we have a valid label, just use the label. So replace "?" by "" in description
description = (description.equals("?") description = (description.equals("?")
&& (item.getLabel().getValue() != null && (item.getLabel().getValue() != null
@ -121,11 +151,12 @@ public class Place implements Parcelable {
.build(), .build(),
item.getPic().getValue(), item.getPic().getValue(),
// Checking if the place exists or not // Checking if the place exists or not
(item.getDestroyed().getValue() == "") && (item.getEndTime().getValue() == "")); (item.getDestroyed().getValue() == "") && (item.getEndTime().getValue() == ""), entityId);
} }
/** /**
* Gets the language of the caption ie name. * Gets the language of the caption ie name.
*
* @return language * @return language
*/ */
public String getLanguage() { public String getLanguage() {
@ -134,12 +165,27 @@ public class Place implements Parcelable {
/** /**
* Gets the name of the place * Gets the name of the place
*
* @return name * @return name
*/ */
public String getName() { return name; } public String getName() {
return name;
}
/** Gets the label of the place /**
* e.g. "building", "city", etc * Gets the distance between place and curLatLng
*
* @param curLatLng
* @return name
*/
public Double getDistanceInDouble(LatLng curLatLng) {
return LocationUtils.calculateDistance(curLatLng.getLatitude(), curLatLng.getLongitude(),
getLocation().getLatitude(), getLocation().getLongitude());
}
/**
* Gets the label of the place e.g. "building", "city", etc
*
* @return label * @return label
*/ */
public Label getLabel() { public Label getLabel() {
@ -152,6 +198,7 @@ public class Place implements Parcelable {
/** /**
* Gets the long description of the place * Gets the long description of the place
*
* @return long description * @return long description
*/ */
public String getLongDescription() { public String getLongDescription() {
@ -160,12 +207,16 @@ public class Place implements Parcelable {
/** /**
* Gets the Commons category of the place * Gets the Commons category of the place
*
* @return Commons category * @return Commons category
*/ */
public String getCategory() {return category; } public String getCategory() {
return category;
}
/** /**
* Sets the distance of the place from the user's location * Sets the distance of the place from the user's location
*
* @param distance distance of place from user's location * @param distance distance of place from user's location
*/ */
public void setDistance(String distance) { public void setDistance(String distance) {
@ -174,6 +225,7 @@ public class Place implements Parcelable {
/** /**
* Extracts the entity id from the wikidata link * Extracts the entity id from the wikidata link
*
* @return returns the entity id if wikidata link destroyed * @return returns the entity id if wikidata link destroyed
*/ */
@Nullable @Nullable
@ -189,6 +241,7 @@ public class Place implements Parcelable {
/** /**
* Checks if the Wikidata item has a Wikipedia page associated with it * Checks if the Wikidata item has a Wikipedia page associated with it
*
* @return true if there is a Wikipedia link * @return true if there is a Wikipedia link
*/ */
public boolean hasWikipediaLink() { public boolean hasWikipediaLink() {
@ -197,6 +250,7 @@ public class Place implements Parcelable {
/** /**
* Checks if the Wikidata item has a Wikidata page associated with it * Checks if the Wikidata item has a Wikidata page associated with it
*
* @return true if there is a Wikidata link * @return true if there is a Wikidata link
*/ */
public boolean hasWikidataLink() { public boolean hasWikidataLink() {
@ -205,6 +259,7 @@ public class Place implements Parcelable {
/** /**
* Checks if the Wikidata item has a Commons page associated with it * Checks if the Wikidata item has a Commons page associated with it
*
* @return true if there is a Commons link * @return true if there is a Commons link
*/ */
public boolean hasCommonsLink() { public boolean hasCommonsLink() {
@ -213,6 +268,7 @@ public class Place implements Parcelable {
/** /**
* Sets that this place in nearby is a WikiData monument * Sets that this place in nearby is a WikiData monument
*
* @param monument * @param monument
*/ */
public void setMonument(final boolean monument) { public void setMonument(final boolean monument) {
@ -221,6 +277,7 @@ public class Place implements Parcelable {
/** /**
* Returns if this place is a WikiData monument * Returns if this place is a WikiData monument
*
* @return * @return
*/ */
public boolean isMonument() { public boolean isMonument() {
@ -229,6 +286,7 @@ public class Place implements Parcelable {
/** /**
* Check if we already have the exact same Place * Check if we already have the exact same Place
*
* @param o Place being tested * @param o Place being tested
* @return true if name and location of Place is exactly the same * @return true if name and location of Place is exactly the same
*/ */
@ -260,6 +318,7 @@ public class Place implements Parcelable {
", siteLinks='" + siteLinks.toString() + '\'' + ", siteLinks='" + siteLinks.toString() + '\'' +
", pic='" + pic + '\'' + ", pic='" + pic + '\'' +
", exists='" + exists.toString() + '\'' + ", exists='" + exists.toString() + '\'' +
", entityID='" + entityID + '\'' +
'}'; '}';
} }
@ -278,6 +337,7 @@ public class Place implements Parcelable {
dest.writeString(category); dest.writeString(category);
dest.writeParcelable(siteLinks, 0); dest.writeParcelable(siteLinks, 0);
dest.writeString(pic); dest.writeString(pic);
dest.writeString(entityID);
dest.writeString(exists.toString()); dest.writeString(exists.toString());
dest.writeInt(isMonument ? 1 : 0); dest.writeInt(isMonument ? 1 : 0);
} }
@ -298,7 +358,40 @@ public class Place implements Parcelable {
return thumb; return thumb;
} }
/**
* Sets the thumbnail URL for the place.
*
* @param thumb the thumbnail URL to set
*/
public void setThumb(String thumb) { public void setThumb(String thumb) {
this.thumb = thumb; this.thumb = thumb;
} }
/**
* Sets the label for the place.
*
* @param label the label to set
*/
public void setLabel(Label label) {
this.label = label;
}
/**
* Sets the long description for the place.
*
* @param longDescription the long description to set
*/
public void setLongDescription(String longDescription) {
this.longDescription = longDescription;
}
/**
* Sets the Commons category for the place.
*
* @param category the category to set
*/
public void setCategory(String category) {
this.category = category;
}
} }

View file

@ -0,0 +1,45 @@
package fr.free.nrw.commons.nearby;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import fr.free.nrw.commons.location.LatLng;
import io.reactivex.Completable;
/**
* Data Access Object (DAO) for accessing the Place entity in the database.
* This class provides methods for storing and retrieving Place objects,
* utilized for the caching of places in the Nearby Map feature.
*/
@Dao
public abstract class PlaceDao {
/**
* Inserts a Place object into the database.
* If a conflict occurs, the existing entry will be replaced.
*
* @param place The Place object to be inserted.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void saveSynchronous(Place place);
/**
* Retrieves a Place object from the database based on the provided entity ID.
*
* @param entity The entity ID of the Place to be retrieved.
* @return The Place object with the specified entity ID.
*/
@Query("SELECT * from place WHERE entityID=:entity")
public abstract Place getPlace(String entity);
/**
* Saves a Place object asynchronously into the database.
*/
public Completable save(final Place place) {
return Completable
.fromAction(() -> {
saveSynchronous(place);
});
}
}

View file

@ -0,0 +1,39 @@
package fr.free.nrw.commons.nearby;
import fr.free.nrw.commons.location.LatLng;
import io.reactivex.Completable;
import javax.inject.Inject;
/**
* The LocalDataSource class for Places
*/
public class PlacesLocalDataSource {
private final PlaceDao placeDao;
@Inject
public PlacesLocalDataSource(
final PlaceDao placeDao) {
this.placeDao = placeDao;
}
/**
* Fetches a Place object from the database based on the provided entity ID.
*
* @param entityID The entity ID of the Place to be retrieved.
* @return The Place object with the specified entity ID.
*/
public Place fetchPlace(String entityID){
return placeDao.getPlace(entityID);
}
/**
* Saves a Place object asynchronously into the database.
*
* @param place The Place object to be saved.
* @return A Completable that completes once the save operation is done.
*/
public Completable savePlace(Place place) {
return placeDao.save(place);
}
}

View file

@ -0,0 +1,41 @@
package fr.free.nrw.commons.nearby;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.location.LatLng;
import io.reactivex.Completable;
import javax.inject.Inject;
/**
* The PlacesRepository class acts as a repository for Place entities.
* It interacts with the PlacesLocalDataSource to perform database operations.
*/
public class PlacesRepository {
private PlacesLocalDataSource localDataSource;
@Inject
public PlacesRepository(PlacesLocalDataSource localDataSource) {
this.localDataSource = localDataSource;
}
/**
* Saves a Place object asynchronously into the database.
*
* @param place The Place object to be saved.
* @return A Completable that completes once the save operation is done.
*/
public Completable save(Place place){
return localDataSource.savePlace(place);
}
/**
* Fetches a Place object from the database based on the provided entity ID.
*
* @param entityID The entity ID of the Place to be retrieved.
* @return The Place object with the specified entity ID.
*/
public Place fetchPlace(String entityID){
return localDataSource.fetchPlace(entityID);
}
}

View file

@ -42,10 +42,6 @@ public interface NearbyParentFragmentContract {
void hideBottomDetailsSheet(); void hideBottomDetailsSheet();
void addSearchThisAreaButtonAction();
void setSearchThisAreaButtonVisibility(boolean isVisible);
void setProgressBarVisibility(boolean isVisible); void setProgressBarVisibility(boolean isVisible);
boolean isDetailsBottomSheetVisible(); boolean isDetailsBottomSheetVisible();
@ -76,8 +72,7 @@ public interface NearbyParentFragmentContract {
void filterOutAllMarkers(); void filterOutAllMarkers();
void filterMarkersByLabels(List<Label> selectedLabels, boolean existsSelected, void filterMarkersByLabels(List<Label> selectedLabels, boolean filterForPlaceState,
boolean needPhotoSelected, boolean wlmSelected, boolean filterForPlaceState,
boolean filterForAllNoneType); boolean filterForAllNoneType);
LatLng getCameraTarget(); LatLng getCameraTarget();
@ -97,6 +92,8 @@ public interface NearbyParentFragmentContract {
boolean isAdvancedQueryFragmentVisible(); boolean isAdvancedQueryFragmentVisible();
void showHideAdvancedQueryFragment(boolean shouldShow); void showHideAdvancedQueryFragment(boolean shouldShow);
void stopQuery();
} }
interface NearbyListView { interface NearbyListView {

View file

@ -6,7 +6,7 @@ class ResultTuple {
@SerializedName("xml:lang") @SerializedName("xml:lang")
val language: String val language: String
val type: String val type: String
val value: String var value: String
constructor(lang: String, type: String, value: String) { constructor(lang: String, type: String, value: String) {
this.language = lang this.language = lang

View file

@ -14,8 +14,10 @@ import android.location.Location;
import android.view.View; import android.view.View;
import androidx.annotation.MainThread; import androidx.annotation.MainThread;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.work.ExistingWorkPolicy;
import fr.free.nrw.commons.BaseMarker; import fr.free.nrw.commons.BaseMarker;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType; import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
@ -25,9 +27,13 @@ import fr.free.nrw.commons.nearby.Label;
import fr.free.nrw.commons.nearby.MarkerPlaceGroup; import fr.free.nrw.commons.nearby.MarkerPlaceGroup;
import fr.free.nrw.commons.nearby.NearbyController; import fr.free.nrw.commons.nearby.NearbyController;
import fr.free.nrw.commons.nearby.NearbyFilterState; import fr.free.nrw.commons.nearby.NearbyFilterState;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.nearby.PlaceDao;
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract; import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract;
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
import fr.free.nrw.commons.utils.LocationUtils; import fr.free.nrw.commons.utils.LocationUtils;
import fr.free.nrw.commons.wikidata.WikidataEditListener; import fr.free.nrw.commons.wikidata.WikidataEditListener;
import io.reactivex.disposables.CompositeDisposable;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.List; import java.util.List;
import timber.log.Timber; import timber.log.Timber;
@ -213,19 +219,20 @@ public class NearbyParentFragmentPresenter
* Populates places for custom location, should be used for finding nearby places around a * Populates places for custom location, should be used for finding nearby places around a
* location where you are not at. * location where you are not at.
* *
* @param nearbyPlacesInfo This variable has placeToCenter list information and distances. * @param nearbyPlaces This variable has placeToCenter list information and distances.
*/ */
public void updateMapMarkers(NearbyController.NearbyPlacesInfo nearbyPlacesInfo, boolean shouldTrackPosition) { public void updateMapMarkers(List<Place> nearbyPlaces, LatLng currentLatLng,
boolean shouldTrackPosition) {
if (null != nearbyParentFragmentView) { if (null != nearbyParentFragmentView) {
nearbyParentFragmentView.clearAllMarkers(); nearbyParentFragmentView.clearAllMarkers();
List<BaseMarker> baseMarkers = NearbyController List<BaseMarker> baseMarkers = NearbyController
.loadAttractionsFromLocationToBaseMarkerOptions(nearbyPlacesInfo.currentLatLng, .loadAttractionsFromLocationToBaseMarkerOptions(currentLatLng,
// Curlatlang will be used to calculate distances // Curlatlang will be used to calculate distances
nearbyPlacesInfo.placeList); nearbyPlaces);
nearbyParentFragmentView.updateMapMarkers(baseMarkers); nearbyParentFragmentView.updateMapMarkers(baseMarkers);
lockUnlockNearby(false); // So that new location updates wont come lockUnlockNearby(false); // So that new location updates wont come
nearbyParentFragmentView.setProgressBarVisibility(false); nearbyParentFragmentView.setProgressBarVisibility(false);
nearbyParentFragmentView.updateListFragment(nearbyPlacesInfo.placeList); nearbyParentFragmentView.updateListFragment(nearbyPlaces);
} }
} }
@ -278,18 +285,12 @@ public class NearbyParentFragmentPresenter
case CHECKED: case CHECKED:
// Despite showing all labels NearbyFilterState still should be applied // Despite showing all labels NearbyFilterState still should be applied
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels, nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
NearbyFilterState.getInstance().isExistsSelected(),
NearbyFilterState.getInstance().isNeedPhotoSelected(),
NearbyFilterState.getInstance().isWlmSelected(),
filterForPlaceState, false); filterForPlaceState, false);
nearbyParentFragmentView.setRecyclerViewAdapterAllSelected(); nearbyParentFragmentView.setRecyclerViewAdapterAllSelected();
break; break;
} }
} else { } else {
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels, nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
NearbyFilterState.getInstance().isExistsSelected(),
NearbyFilterState.getInstance().isNeedPhotoSelected(),
NearbyFilterState.getInstance().isWlmSelected(),
filterForPlaceState, false); filterForPlaceState, false);
} }
} }
@ -327,17 +328,17 @@ public class NearbyParentFragmentPresenter
} }
} }
public View.OnClickListener onSearchThisAreaClicked() { /**
return v -> { * Initiates a search for places within the area. Depending on whether the search
// Lock map operations during search this area operation * is close to the current location, the map and list are updated
// nearbyParentFragmentView.setMapCenter(); * accordingly.
nearbyParentFragmentView.setSearchThisAreaButtonVisibility(false); */
public void searchInTheArea(){
if (searchCloseToCurrentLocation()) { if (searchCloseToCurrentLocation()) {
updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED); updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED);
} else { } else {
updateMapAndList(SEARCH_CUSTOM_AREA); updateMapAndList(SEARCH_CUSTOM_AREA);
} }
};
} }
/** /**
@ -368,7 +369,6 @@ public class NearbyParentFragmentPresenter
public void onMapReady() { public void onMapReady() {
if (null != nearbyParentFragmentView) { if (null != nearbyParentFragmentView) {
nearbyParentFragmentView.addSearchThisAreaButtonAction();
initializeMapOperations(); initializeMapOperations();
} }
} }

View file

@ -47,7 +47,8 @@ public class PlaceUtils {
.setWikidataLink("") // we don't necessarily have them, can be fetched later .setWikidataLink("") // we don't necessarily have them, can be fetched later
.build(), .build(),
media.getImageUrl(), media.getImageUrl(),
media.getThumbUrl())); media.getThumbUrl(),
""));
} }
return explorePlaceList; return explorePlaceList;
} }

View file

@ -16,9 +16,9 @@
android:strokeWidth="1" /> android:strokeWidth="1" />
<path <path
android:fillAlpha="1" android:fillAlpha="1"
android:fillColor="#003b59" android:fillColor="#2CB7A9"
android:pathData="M11.617,21.707C10.518,20.424 9.338,18.864 8.395,17.449 6.524,14.641 5.455,12.305 5.102,10.255 5.014,9.744 5.006,8.628 5.088,8.137 5.348,6.561 6.043,5.221 7.158,4.148 9.148,2.231 12.016,1.668 14.593,2.688c2.043,0.809 3.607,2.581 4.162,4.719 0.174,0.67 0.204,0.933 0.203,1.761 -0.001,0.81 -0.035,1.098 -0.22,1.857 -0.614,2.524 -2.571,5.977 -5.383,9.501 -0.645,0.809 -1.321,1.61 -1.358,1.61 -0.008,0 -0.179,-0.193 -0.381,-0.428zM12.617,11.603c0.783,-0.188 1.457,-0.795 1.738,-1.564 0.516,-1.415 -0.317,-2.962 -1.783,-3.312 -0.216,-0.052 -0.317,-0.059 -0.661,-0.047 -0.354,0.012 -0.441,0.025 -0.682,0.104 -0.673,0.221 -1.205,0.695 -1.506,1.344 -0.176,0.38 -0.218,0.584 -0.217,1.054 0.001,0.324 0.014,0.452 0.064,0.635 0.266,0.97 1.077,1.689 2.079,1.844 0.243,0.038 0.68,0.012 0.968,-0.057z" android:pathData="M11.617,21.707C10.518,20.424 9.338,18.864 8.395,17.449 6.524,14.641 5.455,12.305 5.102,10.255 5.014,9.744 5.006,8.628 5.088,8.137 5.348,6.561 6.043,5.221 7.158,4.148 9.148,2.231 12.016,1.668 14.593,2.688c2.043,0.809 3.607,2.581 4.162,4.719 0.174,0.67 0.204,0.933 0.203,1.761 -0.001,0.81 -0.035,1.098 -0.22,1.857 -0.614,2.524 -2.571,5.977 -5.383,9.501 -0.645,0.809 -1.321,1.61 -1.358,1.61 -0.008,0 -0.179,-0.193 -0.381,-0.428zM12.617,11.603c0.783,-0.188 1.457,-0.795 1.738,-1.564 0.516,-1.415 -0.317,-2.962 -1.783,-3.312 -0.216,-0.052 -0.317,-0.059 -0.661,-0.047 -0.354,0.012 -0.441,0.025 -0.682,0.104 -0.673,0.221 -1.205,0.695 -1.506,1.344 -0.176,0.38 -0.218,0.584 -0.217,1.054 0.001,0.324 0.014,0.452 0.064,0.635 0.266,0.97 1.077,1.689 2.079,1.844 0.243,0.038 0.68,0.012 0.968,-0.057z"
android:strokeAlpha="1" android:strokeAlpha="1"
android:strokeColor="#031E2C" android:strokeColor="#003b59"
android:strokeWidth="1" /> android:strokeWidth="1" />
</vector> </vector>

View file

@ -23,7 +23,7 @@
android:pathData="M17.9025,7.0798 L14.1612,6.7552 12.7003,3.3154c-0.2628,-0.6261 -1.1595,-0.6261 -1.4223,0L9.817,6.7629 6.0835,7.0798C5.4032,7.134 5.125,7.9842 5.6429,8.4326l2.8369,2.4581 -0.8503,3.6485c-0.1546,0.6648 0.5643,1.1904 1.1518,0.8348l3.2079,-1.9325 3.2079,1.9402c0.5875,0.3556 1.3064,-0.1701 1.1518,-0.8348L15.4985,10.8907 18.3354,8.4326C18.8533,7.9842 18.5827,7.134 17.9025,7.0798Z" android:pathData="M17.9025,7.0798 L14.1612,6.7552 12.7003,3.3154c-0.2628,-0.6261 -1.1595,-0.6261 -1.4223,0L9.817,6.7629 6.0835,7.0798C5.4032,7.134 5.125,7.9842 5.6429,8.4326l2.8369,2.4581 -0.8503,3.6485c-0.1546,0.6648 0.5643,1.1904 1.1518,0.8348l3.2079,-1.9325 3.2079,1.9402c0.5875,0.3556 1.3064,-0.1701 1.1518,-0.8348L15.4985,10.8907 18.3354,8.4326C18.8533,7.9842 18.5827,7.134 17.9025,7.0798Z"
android:strokeAlpha="1" android:strokeAlpha="1"
android:strokeWidth="1" android:strokeWidth="1"
android:fillColor="#f84d4d" android:fillColor="#006699"
android:fillAlpha="1" android:fillAlpha="1"
android:strokeColor="#003b59"/> android:strokeColor="#003b59"/>
</vector> </vector>

View file

@ -10,7 +10,7 @@
android:strokeWidth="1" /> android:strokeWidth="1" />
<path <path
android:fillAlpha="1" android:fillAlpha="1"
android:fillColor="#f84d4d" android:fillColor="#000000"
android:pathData="M11.575,11.62C10.689,11.462 9.902,10.759 9.625,9.878 9.553,9.65 9.535,9.499 9.538,9.14c0.004,-0.397 0.019,-0.492 0.13,-0.787 0.236,-0.631 0.646,-1.099 1.212,-1.382 0.386,-0.193 0.709,-0.272 1.116,-0.272 0.676,0 1.263,0.247 1.744,0.734 0.355,0.359 0.541,0.682 0.657,1.136 0.327,1.278 -0.442,2.611 -1.723,2.987 -0.282,0.083 -0.817,0.114 -1.099,0.063z" android:pathData="M11.575,11.62C10.689,11.462 9.902,10.759 9.625,9.878 9.553,9.65 9.535,9.499 9.538,9.14c0.004,-0.397 0.019,-0.492 0.13,-0.787 0.236,-0.631 0.646,-1.099 1.212,-1.382 0.386,-0.193 0.709,-0.272 1.116,-0.272 0.676,0 1.263,0.247 1.744,0.734 0.355,0.359 0.541,0.682 0.657,1.136 0.327,1.278 -0.442,2.611 -1.723,2.987 -0.282,0.083 -0.817,0.114 -1.099,0.063z"
android:strokeWidth="1" /> android:strokeWidth="1" />
<path <path

View file

@ -23,7 +23,7 @@
android:pathData="M17.9025,7.0798 L14.1612,6.7552 12.7003,3.3154c-0.2628,-0.6261 -1.1595,-0.6261 -1.4223,0L9.817,6.7629 6.0835,7.0798C5.4032,7.134 5.125,7.9842 5.6429,8.4326l2.8369,2.4581 -0.8503,3.6485c-0.1546,0.6648 0.5643,1.1904 1.1518,0.8348l3.2079,-1.9325 3.2079,1.9402c0.5875,0.3556 1.3064,-0.1701 1.1518,-0.8348L15.4985,10.8907 18.3354,8.4326C18.8533,7.9842 18.5827,7.134 17.9025,7.0798Z" android:pathData="M17.9025,7.0798 L14.1612,6.7552 12.7003,3.3154c-0.2628,-0.6261 -1.1595,-0.6261 -1.4223,0L9.817,6.7629 6.0835,7.0798C5.4032,7.134 5.125,7.9842 5.6429,8.4326l2.8369,2.4581 -0.8503,3.6485c-0.1546,0.6648 0.5643,1.1904 1.1518,0.8348l3.2079,-1.9325 3.2079,1.9402c0.5875,0.3556 1.3064,-0.1701 1.1518,-0.8348L15.4985,10.8907 18.3354,8.4326C18.8533,7.9842 18.5827,7.134 17.9025,7.0798Z"
android:strokeAlpha="1" android:strokeAlpha="1"
android:strokeWidth="1" android:strokeWidth="1"
android:fillColor="#f84d4d" android:fillColor="#006699"
android:fillAlpha="1" android:fillAlpha="1"
android:strokeColor="#003b59"/> android:strokeColor="#003b59"/>
</vector> </vector>

View file

@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/half_standard_height"
android:height="28dp"
android:viewportWidth="24.0"
android:viewportHeight="28.0">
<path
android:fillAlpha="0.1"
android:fillColor="#000000"
android:pathData="M6.072,22.223a6.031,3.672 0,1 0,12.062 0a6.031,3.672 0,1 0,-12.062 0z"
android:strokeWidth="1" />
<path
android:fillAlpha="1"
android:fillColor="#000000"
android:pathData="M11.575,11.62C10.689,11.462 9.902,10.759 9.625,9.878 9.553,9.65 9.535,9.499 9.538,9.14c0.004,-0.397 0.019,-0.492 0.13,-0.787 0.236,-0.631 0.646,-1.099 1.212,-1.382 0.386,-0.193 0.709,-0.272 1.116,-0.272 0.676,0 1.263,0.247 1.744,0.734 0.355,0.359 0.541,0.682 0.657,1.136 0.327,1.278 -0.442,2.611 -1.723,2.987 -0.282,0.083 -0.817,0.114 -1.099,0.063z"
android:strokeWidth="1" />
<path
android:fillAlpha="1"
android:fillColor="#f84d4d"
android:pathData="M11.617,21.707C10.518,20.424 9.338,18.864 8.395,17.449 6.524,14.641 5.455,12.305 5.102,10.255 5.014,9.744 5.006,8.628 5.088,8.137 5.348,6.561 6.043,5.221 7.158,4.148 9.148,2.231 12.016,1.668 14.593,2.688c2.043,0.809 3.607,2.581 4.162,4.719 0.174,0.67 0.204,0.933 0.203,1.761 -0.001,0.81 -0.035,1.098 -0.22,1.857 -0.614,2.524 -2.571,5.977 -5.383,9.501 -0.645,0.809 -1.321,1.61 -1.358,1.61 -0.008,0 -0.179,-0.193 -0.381,-0.428zM12.617,11.603c0.783,-0.188 1.457,-0.795 1.738,-1.564 0.516,-1.415 -0.317,-2.962 -1.783,-3.312 -0.216,-0.052 -0.317,-0.059 -0.661,-0.047 -0.354,0.012 -0.441,0.025 -0.682,0.104 -0.673,0.221 -1.205,0.695 -1.506,1.344 -0.176,0.38 -0.218,0.584 -0.217,1.054 0.001,0.324 0.014,0.452 0.064,0.635 0.266,0.97 1.077,1.689 2.079,1.844 0.243,0.038 0.68,0.012 0.968,-0.057z"
android:strokeAlpha="1"
android:strokeColor="#003b59"
android:strokeWidth="1" />
</vector>

View file

@ -0,0 +1,29 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="28dp"
android:viewportWidth="24"
android:viewportHeight="28">
<path
android:pathData="M6.072,22.223a6.031,3.672 0,1 0,12.062 0a6.031,3.672 0,1 0,-12.062 0z"
android:strokeAlpha="0.1"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillAlpha="0.1"/>
<path
android:pathData="M11.575,11.62C10.689,11.462 9.902,10.759 9.625,9.878 9.553,9.65 9.535,9.499 9.538,9.14c0.004,-0.397 0.019,-0.492 0.13,-0.787 0.236,-0.631 0.646,-1.099 1.212,-1.382 0.386,-0.193 0.709,-0.272 1.116,-0.272 0.676,0 1.263,0.247 1.744,0.734 0.355,0.359 0.541,0.682 0.657,1.136 0.327,1.278 -0.442,2.611 -1.723,2.987 -0.282,0.083 -0.817,0.114 -1.099,0.063z"
android:strokeWidth="1"
android:fillColor="#00ff00"/>
<path
android:pathData="M11.617,21.707C10.518,20.424 9.338,18.864 8.395,17.449 6.524,14.641 5.455,12.305 5.102,10.255 5.014,9.744 5.006,8.628 5.088,8.137 5.348,6.561 6.043,5.221 7.158,4.148 9.148,2.231 12.016,1.668 14.593,2.688c2.043,0.809 3.607,2.581 4.162,4.719 0.174,0.67 0.204,0.933 0.203,1.761 -0.001,0.81 -0.035,1.098 -0.22,1.857 -0.614,2.524 -2.571,5.977 -5.383,9.501 -0.645,0.809 -1.321,1.61 -1.358,1.61 -0.008,0 -0.179,-0.193 -0.381,-0.428zM12.617,11.603c0.783,-0.188 1.457,-0.795 1.738,-1.564 0.516,-1.415 -0.317,-2.962 -1.783,-3.312 -0.216,-0.052 -0.317,-0.059 -0.661,-0.047 -0.354,0.012 -0.441,0.025 -0.682,0.104 -0.673,0.221 -1.205,0.695 -1.506,1.344 -0.176,0.38 -0.218,0.584 -0.217,1.054 0.001,0.324 0.014,0.452 0.064,0.635 0.266,0.97 1.077,1.689 2.079,1.844 0.243,0.038 0.68,0.012 0.968,-0.057z"
android:strokeWidth="1"
android:fillColor="#f84d4d"
android:strokeColor="#003b59"
android:fillAlpha="1"/>
<path
android:pathData="M17.9025,7.0798 L14.1612,6.7552 12.7003,3.3154c-0.2628,-0.6261 -1.1595,-0.6261 -1.4223,0L9.817,6.7629 6.0835,7.0798C5.4032,7.134 5.125,7.9842 5.6429,8.4326l2.8369,2.4581 -0.8503,3.6485c-0.1546,0.6648 0.5643,1.1904 1.1518,0.8348l3.2079,-1.9325 3.2079,1.9402c0.5875,0.3556 1.3064,-0.1701 1.1518,-0.8348L15.4985,10.8907 18.3354,8.4326C18.8533,7.9842 18.5827,7.134 17.9025,7.0798Z"
android:strokeAlpha="1"
android:strokeWidth="1"
android:fillColor="#006699"
android:fillAlpha="1"
android:strokeColor="#003b59"/>
</vector>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
@ -19,29 +20,38 @@
android:gravity="center_vertical" android:gravity="center_vertical"
> >
<ProgressBar
android:id="@+id/dataCircularProgress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView <ImageView
android:id="@+id/icon" android:id="@+id/icon"
android:layout_width="@dimen/dimen_40" android:layout_width="@dimen/dimen_40"
android:layout_height="@dimen/dimen_40" android:layout_height="@dimen/dimen_40"
android:layout_marginLeft="@dimen/standard_gap"> android:layout_marginLeft="@dimen/standard_gap"
</ImageView> android:visibility="gone"></ImageView>
<LinearLayout <LinearLayout
android:id="@+id/wikiDataLl"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="@dimen/standard_gap" android:layout_marginLeft="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"> android:layout_marginRight="@dimen/standard_gap"
android:orientation="vertical"
tools:visibility="gone">
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginRight="50dp" android:layout_marginRight="50dp"
android:maxLines="2"
android:ellipsize="end" android:ellipsize="end"
/> android:maxLines="2"
android:textSize="16sp" />
<TextView <TextView
android:id="@+id/category" android:id="@+id/category"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -1,50 +0,0 @@
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_gravity="center_vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="@dimen/filter_padding"
android:text="@string/place_state"
android:textColor="@color/white"/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/choice_chip_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/filter_padding"
android:theme="@style/Theme.MaterialComponents.Light"
app:singleSelection="false">
<com.google.android.material.chip.Chip
android:id="@+id/choice_chip_exists"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipBackgroundColor="@color/bg_chip_state"
android:text="@string/place_state_exists"/>
<com.google.android.material.chip.Chip
android:id="@+id/choice_chip_needs_photo"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipBackgroundColor="@color/bg_chip_state"
android:text="@string/place_state_needs_photo"/>
<com.google.android.material.chip.Chip
android:id="@+id/choice_chip_wlm"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipBackgroundColor="@color/bg_chip_state"
android:text="@string/place_state_wlm"/>
</com.google.android.material.chip.ChipGroup>
</LinearLayout>

View file

@ -18,7 +18,8 @@
<include <include
android:id="@+id/nearby_filter" android:id="@+id/nearby_filter"
layout="@layout/nearby_filter_all_items" /> layout="@layout/nearby_filter_all_items"
android:visibility="visible" />
<RelativeLayout <RelativeLayout
android:id="@+id/rl_container_wlm_month_message" android:id="@+id/rl_container_wlm_month_message"
@ -96,22 +97,6 @@
</RelativeLayout> </RelativeLayout>
<Button
android:id="@+id/search_this_area_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/rl_container_wlm_month_message"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:layout_margin="@dimen/activity_margin_horizontal"
android:background="@color/white"
android:padding="@dimen/activity_margin_horizontal"
android:singleLine="true"
android:text="@string/search_this_area"
android:textColor="@color/status_bar_blue"
android:visibility="gone"
app:elevation="@dimen/dimen_6" />
<View <View
android:id="@+id/transparentView" android:id="@+id/transparentView"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -1,38 +1,16 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/status_bar_blue"> android:background="@color/status_bar_blue">
<include
android:id="@+id/chip_view"
layout="@layout/filter_chip_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/iv_toggle_chips"
android:background="@color/deleteRed"
android:contentDescription="@string/nearby_filter_state" />
<include <include
android:id="@+id/search_view_layout" android:id="@+id/search_view_layout"
layout="@layout/filter_search_view_layout" layout="@layout/filter_search_view_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/chip_view"
android:layout_toStartOf="@+id/iv_toggle_chips"
android:contentDescription="@string/nearby_filter_search" /> android:contentDescription="@string/nearby_filter_search" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_toggle_chips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:contentDescription="@string/nearby_filter_toggle"
android:padding="12dp"
android:scaleType="centerCrop"
android:tint="@color/white"
app:srcCompat="@drawable/arrow_up" />
</RelativeLayout> </RelativeLayout>

View file

@ -826,4 +826,5 @@ Upload your first media by tapping on the add button.</string>
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' is at a different place. Please specify the correct place below, and if possible, write the correct latitude and longitude.</string> <string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' is at a different place. Please specify the correct place below, and if possible, write the correct latitude and longitude.</string>
<string name="other_problem_or_information_please_explain_below">Other problem or information (please explain below).</string> <string name="other_problem_or_information_please_explain_below">Other problem or information (please explain below).</string>
<string name="feedback_destination_note">Your feedback gets posted to the following wiki page: <![CDATA[ <a href="https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback">Commons:Mobile app/Feedback</a> ]]></string> <string name="feedback_destination_note">Your feedback gets posted to the following wiki page: <![CDATA[ <a href="https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback">Commons:Mobile app/Feedback</a> ]]></string>
<string name="could_not_load_place_data">Could not load place data</string>
</resources> </resources>

View file

@ -0,0 +1,64 @@
SELECT
?item
(SAMPLE(?label) AS ?label)
(SAMPLE(?class) AS ?class)
(SAMPLE(?description) AS ?description)
(SAMPLE(?classLabel) AS ?classLabel)
(SAMPLE(?pic) AS ?pic)
(SAMPLE(?destroyed) AS ?destroyed)
(SAMPLE(?endTime) AS ?endTime)
(SAMPLE(?wikipediaArticle) AS ?wikipediaArticle)
(SAMPLE(?commonsArticle) AS ?commonsArticle)
(SAMPLE(?commonsCategory) AS ?commonsCategory)
WHERE {
SERVICE <https://query.wikidata.org/sparql> {
values ?item {
${ENTITY}
}
}
# Get the label in the preferred language of the user, or any other language if no label is available in that language.
OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "en")}
OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage}
BIND(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage, "?") as ?label)
# Get the description in the preferred language of the user, or any other language if no description is available in that language.
OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")}
OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage}
BIND(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?") as ?description)
# Get the class label in the preferred language of the user, or any other language if no label is available in that language.
OPTIONAL {
?item p:P31/ps:P31 ?class.
OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "${LANG}")}
OPTIONAL {?class rdfs:label ?classLabelAnyLanguage}
BIND(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?") as ?classLabel)
}
OPTIONAL {
?item p:P31/ps:P31 ?class.
}
# Get picture
OPTIONAL {?item wdt:P18 ?pic}
# Get existence
OPTIONAL {?item wdt:P576 ?destroyed}
OPTIONAL {?item wdt:P582 ?endTime}
# Get Commons category
OPTIONAL {?item wdt:P373 ?commonsCategory}
# Get Wikipedia article
OPTIONAL {
?wikipediaArticle schema:about ?item.
?wikipediaArticle schema:isPartOf <https://en.wikipedia.org/>. # TODO internationalization
}
# Get Commons article
OPTIONAL {
?commonsArticle schema:about ?item.
?commonsArticle schema:isPartOf <https://commons.wikimedia.org/>.
}
}
GROUP BY ?item

View file

@ -1,16 +1,6 @@
SELECT SELECT
?item ?item
(SAMPLE(?location) as ?location) (SAMPLE(?location) as ?location)
(SAMPLE(?label) AS ?label)
(SAMPLE(?description) AS ?description)
(SAMPLE(?class) AS ?class)
(SAMPLE(?classLabel) AS ?classLabel)
(SAMPLE(?pic) AS ?pic)
(SAMPLE(?destroyed) AS ?destroyed)
(SAMPLE(?endTime) AS ?endTime)
(SAMPLE(?wikipediaArticle) AS ?wikipediaArticle)
(SAMPLE(?commonsArticle) AS ?commonsArticle)
(SAMPLE(?commonsCategory) AS ?commonsCategory)
WHERE { WHERE {
# Around given location # Around given location
SERVICE wikibase:box { SERVICE wikibase:box {
@ -19,38 +9,5 @@ WHERE {
bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral. bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral.
} }
OPTIONAL {
?item p:P31/ps:P31 ?class.
}
# Get picture
OPTIONAL {?item wdt:P18 ?pic}
# Get existence
OPTIONAL {?item wdt:P576 ?destroyed}
OPTIONAL {?item wdt:P582 ?endTime}
# Get Commons category
OPTIONAL {?item wdt:P373 ?commonsCategory}
# Get Wikipedia article
OPTIONAL {
?wikipediaArticle schema:about ?item.
?wikipediaArticle schema:isPartOf <https://${LANG}.wikipedia.org/>.
}
# Get Commons article
OPTIONAL {
?commonsArticle schema:about ?item.
?commonsArticle schema:isPartOf <https://commons.wikimedia.org/>.
}
# Labels and descriptions
SERVICE wikibase:label {
bd:serviceParam wikibase:language "${LANG},en,fr,de,es,ja,ru,it,zh,pt,ar,fa,pl,nl,id,uk,he,sv,cs,ko,vi,ca,no,fi,hu,tr,th,hi,bn,ceb,ro,sw,kk,da,eo,sr,lt,sk,bg,sl,eu,et,hr,ms,el,arz,ur,ta,te,nn,gl,az,af,bs,be,ml,ka,is,sq,uz,la,br,mk,lv,azb,mr,sh,tl,cy,ckb,ast,be-tarask,zh-yue,hy,pa,as,my,kn,ne,si,tt,ha,war,zh-min-nan,vo,min,lmo,ht,lb,gu,tg,sco,ku,new,bpy,nds,io,pms,su,oc,jv,nap,ba,scn,wa,bar,an,ksh,szl,fy,frr,als,ia,ga,yi,mg,gd,vec,ce,sa,mai,xmf,sd,wuu,mrj,mhr,km,roa-tara,am,roa-rup,map-bms,bh,mnw,shn,bcl,co,cv,dv,nds-nl,fo,hif,fur,gan,glk,hak,ilo,pam,csb,avk,lij,li,gv,mi,mt,nah,nrm,se,nov,qu,os,pi,pag,ps,pdc,rm,bat-smg,sc,to,tk,hsb,fiu-vro,vls,yo,diq,zh-classical,frp,lad,kw,mn,haw,ang,ln,ie,wo,tpi,ty,crh,nv,jbo,ay,pcd,zea,eml,ky,ig,or,cbk-zam,kg,arc,rmy,ab,gn,so,kab,ug,stq,udm,ext,mzn,pap,cu,sah,tet,sn,lo,pnb,iu,na,got,bo,dsb,chr,cdo,om,sm,ee,ti,av,bm,zu,pnt,cr,pih,ss,ve,bi,rw,ch,xh,kl,ik,bug,dz,ts,tn,kv,tum,xal,st,tw,bxr,ak,ny,fj,lbe,za,ks,ff,lg,sg,rn,chy,mwl,lez,bjn,gom,tyv,vep,nso,kbd,ltg,rue,pfl,gag,koi,krc,ace,olo,kaa,mdf,myv,srn,ady,jam,tcy,dty,atj,kbp,din,lfn,gor,inh,sat,hyw,nqo,ban,szy,awa,ary,lld,smn,skr,mad,dag,shi,nia,ki,gcr".
?item rdfs:label ?label.
?item schema:description ?description.
?class rdfs:label ?classLabel.
}
} }
GROUP BY ?item GROUP BY ?item

View file

@ -1,16 +1,6 @@
SELECT SELECT
?item ?item
(SAMPLE(?location) as ?location) (SAMPLE(?location) as ?location)
(SAMPLE(?label) AS ?label)
(SAMPLE(?description) AS ?description)
(SAMPLE(?class) AS ?class)
(SAMPLE(?classLabel) AS ?classLabel)
(SAMPLE(?pic) AS ?pic)
(SAMPLE(?destroyed) AS ?destroyed)
(SAMPLE(?endTime) AS ?endTime)
(SAMPLE(?wikipediaArticle) AS ?wikipediaArticle)
(SAMPLE(?commonsArticle) AS ?commonsArticle)
(SAMPLE(?commonsCategory) AS ?commonsCategory)
(SAMPLE(?monument) AS ?monument) (SAMPLE(?monument) AS ?monument)
WHERE { WHERE {
# Around given location # Around given location
@ -20,32 +10,6 @@ WHERE {
bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral. bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral.
} }
OPTIONAL {
?item p:P31/ps:P31 ?class.
}
# Get picture
OPTIONAL {?item wdt:P18 ?pic}
# Get existence
OPTIONAL {?item wdt:P576 ?destroyed}
OPTIONAL {?item wdt:P582 ?endTime}
# Get Commons category
OPTIONAL {?item wdt:P373 ?commonsCategory}
# Get Wikipedia article
OPTIONAL {
?wikipediaArticle schema:about ?item.
?wikipediaArticle schema:isPartOf <https://${LANG}.wikipedia.org/>.
}
# Get Commons article
OPTIONAL {
?commonsArticle schema:about ?item.
?commonsArticle schema:isPartOf <https://commons.wikimedia.org/>.
}
# Wiki Loves Monuments # Wiki Loves Monuments
OPTIONAL {?item p:P1435 ?monument} OPTIONAL {?item p:P1435 ?monument}
OPTIONAL {?item p:P2186 ?monument} OPTIONAL {?item p:P2186 ?monument}
@ -57,12 +21,5 @@ WHERE {
OPTIONAL {?item p:P5694 ?monument} OPTIONAL {?item p:P5694 ?monument}
OPTIONAL {?item p:P3426 ?monument} OPTIONAL {?item p:P3426 ?monument}
# Labels and descriptions
SERVICE wikibase:label {
bd:serviceParam wikibase:language "${LANG},en,fr,de,es,ja,ru,it,zh,pt,ar,fa,pl,nl,id,uk,he,sv,cs,ko,vi,ca,no,fi,hu,tr,th,hi,bn,ceb,ro,sw,kk,da,eo,sr,lt,sk,bg,sl,eu,et,hr,ms,el,arz,ur,ta,te,nn,gl,az,af,bs,be,ml,ka,is,sq,uz,la,br,mk,lv,azb,mr,sh,tl,cy,ckb,ast,be-tarask,zh-yue,hy,pa,as,my,kn,ne,si,tt,ha,war,zh-min-nan,vo,min,lmo,ht,lb,gu,tg,sco,ku,new,bpy,nds,io,pms,su,oc,jv,nap,ba,scn,wa,bar,an,ksh,szl,fy,frr,als,ia,ga,yi,mg,gd,vec,ce,sa,mai,xmf,sd,wuu,mrj,mhr,km,roa-tara,am,roa-rup,map-bms,bh,mnw,shn,bcl,co,cv,dv,nds-nl,fo,hif,fur,gan,glk,hak,ilo,pam,csb,avk,lij,li,gv,mi,mt,nah,nrm,se,nov,qu,os,pi,pag,ps,pdc,rm,bat-smg,sc,to,tk,hsb,fiu-vro,vls,yo,diq,zh-classical,frp,lad,kw,mn,haw,ang,ln,ie,wo,tpi,ty,crh,nv,jbo,ay,pcd,zea,eml,ky,ig,or,cbk-zam,kg,arc,rmy,ab,gn,so,kab,ug,stq,udm,ext,mzn,pap,cu,sah,tet,sn,lo,pnb,iu,na,got,bo,dsb,chr,cdo,om,sm,ee,ti,av,bm,zu,pnt,cr,pih,ss,ve,bi,rw,ch,xh,kl,ik,bug,dz,ts,tn,kv,tum,xal,st,tw,bxr,ak,ny,fj,lbe,za,ks,ff,lg,sg,rn,chy,mwl,lez,bjn,gom,tyv,vep,nso,kbd,ltg,rue,pfl,gag,koi,krc,ace,olo,kaa,mdf,myv,srn,ady,jam,tcy,dty,atj,kbp,din,lfn,gor,inh,sat,hyw,nqo,ban,szy,awa,ary,lld,smn,skr,mad,dag,shi,nia,ki,gcr".
?item rdfs:label ?label.
?item schema:description ?description.
?class rdfs:label ?classLabel.
}
} }
GROUP BY ?item GROUP BY ?item

View file

@ -84,9 +84,10 @@ fun place(
category: String = "category", category: String = "category",
siteLinks: Sitelinks? = null, siteLinks: Sitelinks? = null,
pic: String = "pic", pic: String = "pic",
exists: Boolean = false exists: Boolean = false,
entityID: String = "entityID"
): Place { ): Place {
return Place(lang, name, label, longDescription, latLng, category, siteLinks, pic, exists) return Place(lang, name, label, longDescription, latLng, category, siteLinks, pic, exists, entityID)
} }
fun entityId(wikiBaseEntityValue: WikiBaseEntityValue = wikiBaseEntityValue()) = fun entityId(wikiBaseEntityValue: WikiBaseEntityValue = wikiBaseEntityValue()) =

View file

@ -110,8 +110,7 @@ class BookMarkLocationDaoTest {
var result = testObject.allBookmarksLocations var result = testObject.allBookmarksLocations
assertEquals(14,(result.size)) assertEquals(14, result.size)
} }
@Test(expected = RuntimeException::class) @Test(expected = RuntimeException::class)
@ -143,7 +142,6 @@ class BookMarkLocationDaoTest {
verify(mockCursor).close() verify(mockCursor).close()
} }
@Test @Test
fun updateNewLocationBookmark() { fun updateNewLocationBookmark() {
whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY) whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY)
@ -163,7 +161,7 @@ class BookMarkLocationDaoTest {
assertEquals(examplePlaceBookmark.siteLinks.wikipediaLink.toString(), cv.getAsString(COLUMN_WIKIPEDIA_LINK)) assertEquals(examplePlaceBookmark.siteLinks.wikipediaLink.toString(), cv.getAsString(COLUMN_WIKIPEDIA_LINK))
assertEquals(examplePlaceBookmark.siteLinks.wikidataLink.toString(), cv.getAsString(COLUMN_WIKIDATA_LINK)) assertEquals(examplePlaceBookmark.siteLinks.wikidataLink.toString(), cv.getAsString(COLUMN_WIKIDATA_LINK))
assertEquals(examplePlaceBookmark.siteLinks.commonsLink.toString(), cv.getAsString(COLUMN_COMMONS_LINK)) assertEquals(examplePlaceBookmark.siteLinks.commonsLink.toString(), cv.getAsString(COLUMN_COMMONS_LINK))
assertEquals(examplePlaceBookmark.pic.toString(), cv.getAsString(COLUMN_PIC)) assertEquals(examplePlaceBookmark.pic, cv.getAsString(COLUMN_PIC))
assertEquals(examplePlaceBookmark.exists.toString(), cv.getAsString(COLUMN_EXISTS)) assertEquals(examplePlaceBookmark.exists.toString(), cv.getAsString(COLUMN_EXISTS))
} }
} }
@ -204,7 +202,7 @@ class BookMarkLocationDaoTest {
@Test @Test
fun cursorsAreClosedAfterFindLocationBookmarkQuery() { fun cursorsAreClosedAfterFindLocationBookmarkQuery() {
val mockCursor: Cursor = mock() val mockCursor: Cursor = mock()
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor) whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
whenever(mockCursor.moveToFirst()).thenReturn(false) whenever(mockCursor.moveToFirst()).thenReturn(false)
testObject.findBookmarkLocation(examplePlaceBookmark) testObject.findBookmarkLocation(examplePlaceBookmark)
@ -215,14 +213,14 @@ class BookMarkLocationDaoTest {
@Test @Test
fun migrateTableVersionFrom_v1_to_v2() { fun migrateTableVersionFrom_v1_to_v2() {
onUpdate(database, 1, 2) onUpdate(database, 1, 2)
// Table didnt exist before v5 // Table didn't exist before v5
verifyNoInteractions(database) verifyNoInteractions(database)
} }
@Test @Test
fun migrateTableVersionFrom_v2_to_v3() { fun migrateTableVersionFrom_v2_to_v3() {
onUpdate(database, 2, 3) onUpdate(database, 2, 3)
// Table didnt exist before v5 // Table didn't exist before v5
verifyNoInteractions(database) verifyNoInteractions(database)
} }
@ -278,13 +276,26 @@ class BookMarkLocationDaoTest {
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;") verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;")
} }
private fun createCursor(rows: Int): Cursor {
private fun createCursor(rowCount: Int) = MatrixCursor(columns, rowCount).apply { return MatrixCursor(columns, rows).apply {
repeat(rows) {
for (i in 0 until rowCount) { newRow().apply {
addRow(listOf("placeName", "en", "placeDescription", "placeCategory", exampleLabel.text, exampleLabel.icon, add("placeName")
exampleUri, builder.build().wikipediaLink, builder.build().wikidataLink, builder.build().commonsLink, add("en")
exampleLocation.latitude, exampleLocation.longitude, "picName", "placeExists")) add("placeDescription")
add("placeCategory")
add(Label.FOREST.text)
add(Label.FOREST.icon)
add("placeImage")
add("wikipediaLink")
add("wikidataLink")
add("commonsLink")
add(40.0)
add(51.4)
add("picName")
add(false)
}
}
} }
} }
} }

View file

@ -32,7 +32,7 @@ class BookmarkLocationControllerTest {
val list = ArrayList<Place>() val list = ArrayList<Place>()
list.add( list.add(
Place( Place(
"en", "a place", null, "a description", null, "a cat", null, null, true) "en", "a place", null, "a description", null, "a cat", null, null, true, "entityID")
) )
list.add( list.add(
Place( Place(
@ -44,7 +44,8 @@ class BookmarkLocationControllerTest {
"another cat", "another cat",
null, null,
null, null,
true true,
"entityID"
) )
) )
return list return list

View file

@ -86,7 +86,8 @@ class BookmarkLocationFragmentUnitTests {
"a cat", "a cat",
null, null,
null, null,
true) true,
"entityID")
) )
return list return list
} }

View file

@ -132,7 +132,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
val place2 = Place( val place2 = Place(
"en", "en",
@ -143,7 +144,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
`when`( `when`(
nearbyPlaces.radiusExpander( nearbyPlaces.radiusExpander(
@ -183,7 +185,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
val place2 = Place( val place2 = Place(
"en", "en",
@ -194,7 +197,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
`when`( `when`(
nearbyPlaces.radiusExpander( nearbyPlaces.radiusExpander(
@ -224,7 +228,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
val place2 = Place( val place2 = Place(
"en", "en",
@ -235,7 +240,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
`when`( `when`(
nearbyPlaces.radiusExpander( nearbyPlaces.radiusExpander(
@ -275,7 +281,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
place.isMonument = true place.isMonument = true
`when`(currentLatLng.latitude).thenReturn(0.0) `when`(currentLatLng.latitude).thenReturn(0.0)
@ -299,7 +306,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"picName", "picName",
false false,
"entityID"
) )
place.isMonument = false place.isMonument = false
`when`(currentLatLng.latitude).thenReturn(0.0) `when`(currentLatLng.latitude).thenReturn(0.0)
@ -323,7 +331,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"", "",
false false,
"entityID"
) )
place.isMonument = false place.isMonument = false
`when`(currentLatLng.latitude).thenReturn(0.0) `when`(currentLatLng.latitude).thenReturn(0.0)
@ -347,7 +356,8 @@ class NearbyControllerTest {
"placeCategory", "placeCategory",
Sitelinks.Builder().build(), Sitelinks.Builder().build(),
"", "",
true true,
"entityID"
) )
place.isMonument = false place.isMonument = false
`when`(currentLatLng.latitude).thenReturn(0.0) `when`(currentLatLng.latitude).thenReturn(0.0)

View file

@ -100,7 +100,6 @@ class NearbyParentFragmentPresenterTest {
nearbyPresenter.lockUnlockNearby(true) nearbyPresenter.lockUnlockNearby(true)
nearbyPresenter.updateMapAndList(null) nearbyPresenter.updateMapAndList(null)
verify(nearbyParentFragmentView).disableFABRecenter() verify(nearbyParentFragmentView).disableFABRecenter()
verifyNoMoreInteractions(nearbyParentFragmentView)
} }
/** /**
@ -114,7 +113,6 @@ class NearbyParentFragmentPresenterTest {
nearbyPresenter.updateMapAndList(null) nearbyPresenter.updateMapAndList(null)
verify(nearbyParentFragmentView).enableFABRecenter() verify(nearbyParentFragmentView).enableFABRecenter()
verify(nearbyParentFragmentView).isNetworkConnectionEstablished() verify(nearbyParentFragmentView).isNetworkConnectionEstablished()
verifyNoMoreInteractions(nearbyParentFragmentView)
} }
/** /**
@ -130,7 +128,6 @@ class NearbyParentFragmentPresenterTest {
verify(nearbyParentFragmentView).isNetworkConnectionEstablished verify(nearbyParentFragmentView).isNetworkConnectionEstablished
verify(nearbyParentFragmentView).lastMapFocus verify(nearbyParentFragmentView).lastMapFocus
verify(nearbyParentFragmentView).mapCenter verify(nearbyParentFragmentView).mapCenter
verifyNoMoreInteractions(nearbyParentFragmentView)
} }
/** /**
@ -206,22 +203,6 @@ class NearbyParentFragmentPresenterTest {
verify(nearbyParentFragmentView).isNetworkConnectionEstablished() verify(nearbyParentFragmentView).isNetworkConnectionEstablished()
verify(nearbyParentFragmentView).getLastMapFocus() verify(nearbyParentFragmentView).getLastMapFocus()
verify(nearbyParentFragmentView).getMapCenter() verify(nearbyParentFragmentView).getMapCenter()
verifyNoMoreInteractions(nearbyParentFragmentView)
}
/**
* Test search this area button became visible after user moved the camera target to far
* away from current target. Distance between these two point is 111.19 km, so our camera target
* is at outside of previously searched region if we set latestSearchRadius below 111.19. Thus,
* setSearchThisAreaButtonVisibility(true) should be verified.
*/
@Test @Ignore
fun testSearchThisAreaButtonVisibleWhenMoveToFarPosition() {
NearbyController.latestSearchLocation = Mockito.spy(LatLng(2.0, 1.0, 0.0F))
// Distance between these two point is 111.19 km
NearbyController.latestSearchRadius = 111.19 * 1000 // To meter
whenever(nearbyParentFragmentView.isNetworkConnectionEstablished()).thenReturn(true)
verify(nearbyParentFragmentView).setSearchThisAreaButtonVisibility(true)
} }
/** /**
@ -267,9 +248,6 @@ class NearbyParentFragmentPresenterTest {
verify(nearbyParentFragmentView).filterMarkersByLabels( verify(nearbyParentFragmentView).filterMarkersByLabels(
ArgumentMatchers.anyList(), ArgumentMatchers.anyList(),
ArgumentMatchers.anyBoolean(), ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean() ArgumentMatchers.anyBoolean()
); );
verify(nearbyParentFragmentView).setRecyclerViewAdapterAllSelected() verify(nearbyParentFragmentView).setRecyclerViewAdapterAllSelected()
@ -285,9 +263,6 @@ class NearbyParentFragmentPresenterTest {
verify(nearbyParentFragmentView).filterMarkersByLabels( verify(nearbyParentFragmentView).filterMarkersByLabels(
any(), any(),
anyBoolean(), anyBoolean(),
anyBoolean(),
anyBoolean(),
anyBoolean(),
anyBoolean() anyBoolean()
); );
verifyNoMoreInteractions(nearbyParentFragmentView) verifyNoMoreInteractions(nearbyParentFragmentView)
@ -482,7 +457,7 @@ class NearbyParentFragmentPresenterTest {
nearbyPlacesInfo.placeList = null nearbyPlacesInfo.placeList = null
whenever(bookmarkLocationsDao.allBookmarksLocations).thenReturn(Collections.emptyList()) whenever(bookmarkLocationsDao.allBookmarksLocations).thenReturn(Collections.emptyList())
nearbyPresenter.updateMapMarkers(nearbyPlacesInfo, true) nearbyPresenter.updateMapMarkers(nearbyPlacesInfo.placeList, latestLocation, true)
Mockito.verify(nearbyParentFragmentView).updateMapMarkers(any()) Mockito.verify(nearbyParentFragmentView).updateMapMarkers(any())
Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false) Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false)
Mockito.verify(nearbyParentFragmentView).updateListFragment(nearbyPlacesInfo.placeList) Mockito.verify(nearbyParentFragmentView).updateListFragment(nearbyPlacesInfo.placeList)

View file

@ -234,48 +234,6 @@ class NearbyParentFragmentUnitTest {
verify(presenter, times(1)).onMapReady() verify(presenter, times(1)).onMapReady()
} }
@Test @Ignore
@Throws(Exception::class)
fun `test getIconFor bookmarked place in light theme`() {
val place = mock(Place::class.java).apply {
`when`(isMonument()).thenReturn(false)
`when`(pic).thenReturn("")
`when`(exists).thenReturn(true)
}
val icon = Whitebox.invokeMethod<Int>(fragment, "getIconFor", place, true, false)
Assert.assertEquals(R.drawable.ic_custom_map_marker_blue_bookmarked_dark, icon)
}
@Test @Ignore
@Throws(Exception::class)
fun `test getIconFor non-bookmarked monument place`() {
val place = mock(Place::class.java).apply {
`when`(isMonument()).thenReturn(true)
}
val icon = Whitebox.invokeMethod<Int>(fragment, "getIconFor", place, false, false)
Assert.assertEquals(R.drawable.ic_custom_map_marker_monuments, icon)
}
@Test @Ignore
@Throws(Exception::class)
fun testOnToggleChipsClickedCaseVisible() {
`when`(view.visibility).thenReturn(View.VISIBLE)
fragment.onToggleChipsClicked()
verify(view).visibility = View.GONE
verify(ivToggleChips).rotation = ivToggleChips.rotation + 180
}
@Test @Ignore
@Throws(Exception::class)
fun testOnToggleChipsClickedCaseNotVisible() {
`when`(view.visibility).thenReturn(View.GONE)
fragment.onToggleChipsClicked()
verify(view).visibility = View.VISIBLE
verify(ivToggleChips).rotation = ivToggleChips.rotation + 180
}
@Test @Ignore @Test @Ignore
@Throws(Exception::class) @Throws(Exception::class)
fun testOnLearnMoreClicked() { fun testOnLearnMoreClicked() {

View file

@ -239,7 +239,7 @@ class UploadMediaPresenterTest {
fun setCorrectCountryCodeForReceivedImage() { fun setCorrectCountryCodeForReceivedImage() {
val germanyAsPlace = val germanyAsPlace =
Place(null, null, null, null, LatLng(50.1, 10.2, 1.0f), null, null, null, true) Place(null, null, null, null, LatLng(50.1, 10.2, 1.0f), null, null, null, true, null)
germanyAsPlace.isMonument = true germanyAsPlace.isMonument = true
whenever( whenever(

View file

@ -20,6 +20,7 @@ allprojects {
gradlePluginPortal() // potential jcenter() replacement gradlePluginPortal() // potential jcenter() replacement
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" } maven { url "https://maven.google.com" }
jcenter()
} }
} }
subprojects{ subprojects{