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

@ -46,11 +46,11 @@ public class BookmarkLocationsDao {
ContentProviderClient db = clientProvider.get();
try {
cursor = db.query(
BookmarkLocationsContentProvider.BASE_URI,
Table.ALL_FIELDS,
null,
new String[]{},
null);
BookmarkLocationsContentProvider.BASE_URI,
Table.ALL_FIELDS,
null,
new String[]{},
null);
while (cursor != null && cursor.moveToNext()) {
items.add(fromCursor(cursor));
}
@ -126,11 +126,11 @@ public class BookmarkLocationsDao {
ContentProviderClient db = clientProvider.get();
try {
cursor = db.query(
BookmarkLocationsContentProvider.BASE_URI,
Table.ALL_FIELDS,
Table.COLUMN_NAME + "=?",
new String[]{bookmarkLocation.name},
null);
BookmarkLocationsContentProvider.BASE_URI,
Table.ALL_FIELDS,
Table.COLUMN_NAME + "=?",
new String[]{bookmarkLocation.name},
null);
if (cursor != null && cursor.moveToFirst()) {
return true;
}
@ -149,7 +149,7 @@ public class BookmarkLocationsDao {
@NonNull
Place fromCursor(final Cursor cursor) {
final LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LONG)), 1F);
cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LONG)), 1F);
final Sitelinks.Builder builder = new Sitelinks.Builder();
builder.setWikipediaLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIPEDIA_LINK)));
@ -207,40 +207,40 @@ public class BookmarkLocationsDao {
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
public static final String[] ALL_FIELDS = {
COLUMN_NAME,
COLUMN_LANGUAGE,
COLUMN_DESCRIPTION,
COLUMN_CATEGORY,
COLUMN_LABEL_TEXT,
COLUMN_LABEL_ICON,
COLUMN_LAT,
COLUMN_LONG,
COLUMN_IMAGE_URL,
COLUMN_WIKIPEDIA_LINK,
COLUMN_WIKIDATA_LINK,
COLUMN_COMMONS_LINK,
COLUMN_PIC,
COLUMN_EXISTS,
COLUMN_NAME,
COLUMN_LANGUAGE,
COLUMN_DESCRIPTION,
COLUMN_CATEGORY,
COLUMN_LABEL_TEXT,
COLUMN_LABEL_ICON,
COLUMN_LAT,
COLUMN_LONG,
COLUMN_IMAGE_URL,
COLUMN_WIKIPEDIA_LINK,
COLUMN_WIKIDATA_LINK,
COLUMN_COMMONS_LINK,
COLUMN_PIC,
COLUMN_EXISTS,
};
static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME;
static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " ("
+ COLUMN_NAME + " STRING PRIMARY KEY,"
+ COLUMN_LANGUAGE + " STRING,"
+ COLUMN_DESCRIPTION + " STRING,"
+ COLUMN_CATEGORY + " STRING,"
+ COLUMN_LABEL_TEXT + " STRING,"
+ COLUMN_LABEL_ICON + " INTEGER,"
+ COLUMN_LAT + " DOUBLE,"
+ COLUMN_LONG + " DOUBLE,"
+ COLUMN_IMAGE_URL + " STRING,"
+ COLUMN_WIKIPEDIA_LINK + " STRING,"
+ COLUMN_WIKIDATA_LINK + " STRING,"
+ COLUMN_COMMONS_LINK + " STRING,"
+ COLUMN_PIC + " STRING,"
+ COLUMN_EXISTS + " STRING"
+ ");";
+ COLUMN_NAME + " STRING PRIMARY KEY,"
+ COLUMN_LANGUAGE + " STRING,"
+ COLUMN_DESCRIPTION + " STRING,"
+ COLUMN_CATEGORY + " STRING,"
+ COLUMN_LABEL_TEXT + " STRING,"
+ COLUMN_LABEL_ICON + " INTEGER,"
+ COLUMN_LAT + " DOUBLE,"
+ COLUMN_LONG + " DOUBLE,"
+ COLUMN_IMAGE_URL + " STRING,"
+ COLUMN_WIKIPEDIA_LINK + " STRING,"
+ COLUMN_WIKIDATA_LINK + " STRING,"
+ COLUMN_COMMONS_LINK + " STRING,"
+ COLUMN_PIC + " STRING,"
+ COLUMN_EXISTS + " STRING"
+ ");";
public static void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_STATEMENT);
@ -308,4 +308,4 @@ public class BookmarkLocationsDao {
}
}
}
}
}

View file

@ -6,6 +6,8 @@ import androidx.room.TypeConverters
import fr.free.nrw.commons.contributions.Contribution
import fr.free.nrw.commons.contributions.ContributionDao
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.ReviewEntity
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
*
*/
@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)
abstract class AppDatabase : RoomDatabase() {
abstract fun contributionDao(): ContributionDao
abstract fun PlaceDao(): PlaceDao
abstract fun DepictsDao(): DepictsDao;
abstract fun UploadedStatusDao(): UploadedStatusDao;
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.di.ApplicationlessInjection;
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.structure.depictions.DepictedItem;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -134,6 +136,18 @@ public class Converters {
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) {
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.kvstore.JsonKvStore;
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.settings.Prefs;
import fr.free.nrw.commons.upload.UploadController;
@ -275,6 +276,11 @@ public class CommonsApplicationModule {
return appDatabase.contributionDao();
}
@Provides
public PlaceDao providesPlaceDao(AppDatabase appDatabase) {
return appDatabase.PlaceDao();
}
/**
* Get the reference of DepictsDao class.
*/

View file

@ -397,6 +397,54 @@ public class OkHttpJsonApiClient {
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
*

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) {
double lat1 = Math.toRadians(latitude);
double deltaLat = distance * 0.008;

View file

@ -120,6 +120,22 @@ public class NearbyPlaces {
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
*

View file

@ -3,34 +3,38 @@ package fr.free.nrw.commons.nearby;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
import fr.free.nrw.commons.utils.LocationUtils;
import fr.free.nrw.commons.utils.PlaceUtils;
import org.apache.commons.lang3.StringUtils;
import timber.log.Timber;
/**
* A single geolocated Wikidata item
*/
@Entity(tableName = "place")
public class Place implements Parcelable {
public final String language;
public final String name;
private final Label label;
private final String longDescription;
public final LatLng location;
private final String category;
public final String pic;
public String language;
public String name;
private Label label;
private String longDescription;
public LatLng location;
@PrimaryKey @NonNull
public String entityID;
private String category;
public String pic;
// 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).
public final Boolean exists;
public Boolean exists;
public String distance;
public final Sitelinks siteLinks;
public Sitelinks siteLinks;
private boolean isMonument;
private String thumb;
@ -44,9 +48,11 @@ public class Place implements Parcelable {
pic = null;
exists = 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;
@ -54,21 +60,37 @@ public class Place implements Parcelable {
this.location = location;
this.category = category;
this.siteLinks = siteLinks;
this.pic = (pic == null) ? "":pic;
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.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;
}
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.longDescription = longDescription;
this.location = location;
this.category = category;
this.siteLinks = siteLinks;
this.pic = (pic == null) ? "":pic;
this.pic = (pic == null) ? "" : pic;
this.thumb = thumb;
this.language = null;
this.label = null;
this.exists = true;
this.entityID = entityID;
}
public Place(Parcel in) {
@ -80,19 +102,27 @@ public class Place implements Parcelable {
this.category = in.readString();
this.siteLinks = in.readParcelable(Sitelinks.class.getClassLoader());
String picString = in.readString();
this.pic = (picString == null) ? "":picString;
this.pic = (picString == null) ? "" : picString;
String existString = in.readString();
this.exists = Boolean.parseBoolean(existString);
this.isMonument = in.readInt() == 1;
this.entityID = in.readString();
}
public static Place from(NearbyResultItem item) {
String itemClass = item.getClassName().getValue();
String classEntityId = "";
if(!StringUtils.isBlank(itemClass)) {
if (!StringUtils.isBlank(itemClass)) {
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
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
description = (description.equals("?")
&& (item.getLabel().getValue() != null
@ -104,8 +134,8 @@ public class Place implements Parcelable {
*/
description = ((item.getLabel().getValue() != null && !item.getLabel().getValue().isEmpty())
? item.getLabel().getValue()
+ ((description != null && !description.isEmpty())
? " (" + description + ")" : "")
+ ((description != null && !description.isEmpty())
? " (" + description + ")" : "")
: description);
return new Place(
item.getLabel().getLanguage(),
@ -121,11 +151,12 @@ public class Place implements Parcelable {
.build(),
item.getPic().getValue(),
// 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.
*
* @return language
*/
public String getLanguage() {
@ -134,12 +165,27 @@ public class Place implements Parcelable {
/**
* Gets the name of the place
*
* @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
*/
public Label getLabel() {
@ -152,6 +198,7 @@ public class Place implements Parcelable {
/**
* Gets the long description of the place
*
* @return long description
*/
public String getLongDescription() {
@ -160,12 +207,16 @@ public class Place implements Parcelable {
/**
* Gets the Commons category of the place
*
* @return Commons category
*/
public String getCategory() {return category; }
public String getCategory() {
return category;
}
/**
* Sets the distance of the place from the user's location
*
* @param distance distance of place from user's location
*/
public void setDistance(String distance) {
@ -174,6 +225,7 @@ public class Place implements Parcelable {
/**
* Extracts the entity id from the wikidata link
*
* @return returns the entity id if wikidata link destroyed
*/
@Nullable
@ -189,6 +241,7 @@ public class Place implements Parcelable {
/**
* Checks if the Wikidata item has a Wikipedia page associated with it
*
* @return true if there is a Wikipedia link
*/
public boolean hasWikipediaLink() {
@ -197,6 +250,7 @@ public class Place implements Parcelable {
/**
* Checks if the Wikidata item has a Wikidata page associated with it
*
* @return true if there is a Wikidata link
*/
public boolean hasWikidataLink() {
@ -205,6 +259,7 @@ public class Place implements Parcelable {
/**
* Checks if the Wikidata item has a Commons page associated with it
*
* @return true if there is a Commons link
*/
public boolean hasCommonsLink() {
@ -213,6 +268,7 @@ public class Place implements Parcelable {
/**
* Sets that this place in nearby is a WikiData monument
*
* @param monument
*/
public void setMonument(final boolean monument) {
@ -221,6 +277,7 @@ public class Place implements Parcelable {
/**
* Returns if this place is a WikiData monument
*
* @return
*/
public boolean isMonument() {
@ -229,6 +286,7 @@ public class Place implements Parcelable {
/**
* Check if we already have the exact same Place
*
* @param o Place being tested
* @return true if name and location of Place is exactly the same
*/
@ -250,17 +308,18 @@ public class Place implements Parcelable {
@Override
public String toString() {
return "Place{" +
"name='" + name + '\'' +
", lang='" + language + '\'' +
", label='" + label + '\'' +
", longDescription='" + longDescription + '\'' +
", location='" + location + '\'' +
", category='" + category + '\'' +
", distance='" + distance + '\'' +
", siteLinks='" + siteLinks.toString() + '\'' +
", pic='" + pic + '\'' +
", exists='" + exists.toString() + '\'' +
'}';
"name='" + name + '\'' +
", lang='" + language + '\'' +
", label='" + label + '\'' +
", longDescription='" + longDescription + '\'' +
", location='" + location + '\'' +
", category='" + category + '\'' +
", distance='" + distance + '\'' +
", siteLinks='" + siteLinks.toString() + '\'' +
", pic='" + pic + '\'' +
", exists='" + exists.toString() + '\'' +
", entityID='" + entityID + '\'' +
'}';
}
@Override
@ -278,6 +337,7 @@ public class Place implements Parcelable {
dest.writeString(category);
dest.writeParcelable(siteLinks, 0);
dest.writeString(pic);
dest.writeString(entityID);
dest.writeString(exists.toString());
dest.writeInt(isMonument ? 1 : 0);
}
@ -298,7 +358,40 @@ public class Place implements Parcelable {
return thumb;
}
/**
* Sets the thumbnail URL for the place.
*
* @param thumb the thumbnail URL to set
*/
public void setThumb(String 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 addSearchThisAreaButtonAction();
void setSearchThisAreaButtonVisibility(boolean isVisible);
void setProgressBarVisibility(boolean isVisible);
boolean isDetailsBottomSheetVisible();
@ -76,8 +72,7 @@ public interface NearbyParentFragmentContract {
void filterOutAllMarkers();
void filterMarkersByLabels(List<Label> selectedLabels, boolean existsSelected,
boolean needPhotoSelected, boolean wlmSelected, boolean filterForPlaceState,
void filterMarkersByLabels(List<Label> selectedLabels, boolean filterForPlaceState,
boolean filterForAllNoneType);
LatLng getCameraTarget();
@ -97,6 +92,8 @@ public interface NearbyParentFragmentContract {
boolean isAdvancedQueryFragmentVisible();
void showHideAdvancedQueryFragment(boolean shouldShow);
void stopQuery();
}
interface NearbyListView {

View file

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

View file

@ -14,8 +14,10 @@ import android.location.Location;
import android.view.View;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.work.ExistingWorkPolicy;
import fr.free.nrw.commons.BaseMarker;
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.location.LatLng;
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.NearbyController;
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.upload.worker.WorkRequestHelper;
import fr.free.nrw.commons.utils.LocationUtils;
import fr.free.nrw.commons.wikidata.WikidataEditListener;
import io.reactivex.disposables.CompositeDisposable;
import java.lang.reflect.Proxy;
import java.util.List;
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
* 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) {
nearbyParentFragmentView.clearAllMarkers();
List<BaseMarker> baseMarkers = NearbyController
.loadAttractionsFromLocationToBaseMarkerOptions(nearbyPlacesInfo.currentLatLng,
.loadAttractionsFromLocationToBaseMarkerOptions(currentLatLng,
// Curlatlang will be used to calculate distances
nearbyPlacesInfo.placeList);
nearbyPlaces);
nearbyParentFragmentView.updateMapMarkers(baseMarkers);
lockUnlockNearby(false); // So that new location updates wont come
nearbyParentFragmentView.setProgressBarVisibility(false);
nearbyParentFragmentView.updateListFragment(nearbyPlacesInfo.placeList);
nearbyParentFragmentView.updateListFragment(nearbyPlaces);
}
}
@ -278,18 +285,12 @@ public class NearbyParentFragmentPresenter
case CHECKED:
// Despite showing all labels NearbyFilterState still should be applied
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
NearbyFilterState.getInstance().isExistsSelected(),
NearbyFilterState.getInstance().isNeedPhotoSelected(),
NearbyFilterState.getInstance().isWlmSelected(),
filterForPlaceState, false);
nearbyParentFragmentView.setRecyclerViewAdapterAllSelected();
break;
}
} else {
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
NearbyFilterState.getInstance().isExistsSelected(),
NearbyFilterState.getInstance().isNeedPhotoSelected(),
NearbyFilterState.getInstance().isWlmSelected(),
filterForPlaceState, false);
}
}
@ -327,17 +328,17 @@ public class NearbyParentFragmentPresenter
}
}
public View.OnClickListener onSearchThisAreaClicked() {
return v -> {
// Lock map operations during search this area operation
// nearbyParentFragmentView.setMapCenter();
nearbyParentFragmentView.setSearchThisAreaButtonVisibility(false);
if (searchCloseToCurrentLocation()) {
updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED);
} else {
updateMapAndList(SEARCH_CUSTOM_AREA);
}
};
/**
* Initiates a search for places within the area. Depending on whether the search
* is close to the current location, the map and list are updated
* accordingly.
*/
public void searchInTheArea(){
if (searchCloseToCurrentLocation()) {
updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED);
} else {
updateMapAndList(SEARCH_CUSTOM_AREA);
}
}
/**
@ -368,7 +369,6 @@ public class NearbyParentFragmentPresenter
public void onMapReady() {
if (null != nearbyParentFragmentView) {
nearbyParentFragmentView.addSearchThisAreaButtonAction();
initializeMapOperations();
}
}

View file

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