diff --git a/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.kt b/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.kt index 83f7687d4..1377ae281 100644 --- a/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.kt +++ b/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.kt @@ -18,7 +18,7 @@ class DBOpenHelper( companion object { private const val DATABASE_NAME = "commons.db" - private const val DATABASE_VERSION = 20 + private const val DATABASE_VERSION = 21 const val CONTRIBUTIONS_TABLE = "contributions" private const val DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS %s" } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/Place.java b/app/src/main/java/fr/free/nrw/commons/nearby/Place.java index 7732669bc..21dd14131 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/Place.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/Place.java @@ -5,6 +5,7 @@ import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.room.Embedded; import androidx.room.Entity; import androidx.room.PrimaryKey; import fr.free.nrw.commons.location.LatLng; @@ -24,6 +25,7 @@ public class Place implements Parcelable { public String name; private Label label; private String longDescription; + @Embedded public LatLng location; @PrimaryKey @NonNull public String entityID; diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java index 9e4292114..269384ffa 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java @@ -5,6 +5,7 @@ import androidx.room.Insert; import androidx.room.OnConflictStrategy; import androidx.room.Query; import io.reactivex.Completable; +import java.util.List; /** * Data Access Object (DAO) for accessing the Place entity in the database. @@ -32,6 +33,20 @@ public abstract class PlaceDao { @Query("SELECT * from place WHERE entityID=:entity") public abstract Place getPlace(String entity); + /** + * Retrieves a list of places within the specified rectangular area. + * + * @param latBegin Latitudinal lower bound + * @param lngBegin Longitudinal lower bound + * @param latEnd Latitudinal upper bound, should be greater than `latBegin` + * @param lngEnd Longitudinal upper bound, should be greater than `lngBegin` + * @return The list of places within the specified rectangular geographical area. + */ + @Query("SELECT * from place WHERE name!='' AND latitude>=:latBegin AND longitude>=:lngBegin " + + "AND latitude<:latEnd AND longitude<:lngEnd") + public abstract List fetchPlaces(double latBegin, double lngBegin, + double latEnd, double lngEnd); + /** * Saves a Place object asynchronously into the database. */ diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java index 86a57eadc..2d8c2733a 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java @@ -1,7 +1,11 @@ package fr.free.nrw.commons.nearby; +import fr.free.nrw.commons.location.LatLng; import io.reactivex.Completable; +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; +import timber.log.Timber; /** * The LocalDataSource class for Places @@ -26,6 +30,81 @@ public class PlacesLocalDataSource { return placeDao.getPlace(entityID); } + /** + * Retrieves a list of places from the database within the geographical area + * specified by map's opposite corners. + * + * @param mapBottomLeft Bottom left corner of the map. + * @param mapTopRight Top right corner of the map. + * @return The list of saved places within the map's view. + */ + public List fetchPlaces(final LatLng mapBottomLeft, final LatLng mapTopRight) { + class Constraint { + + final double latBegin; + final double lngBegin; + final double latEnd; + final double lngEnd; + + public Constraint(final double latBegin, final double lngBegin, final double latEnd, + final double lngEnd) { + this.latBegin = latBegin; + this.lngBegin = lngBegin; + this.latEnd = latEnd; + this.lngEnd = lngEnd; + } + } + + final List constraints = new ArrayList<>(); + + if (mapTopRight.getLatitude() < mapBottomLeft.getLatitude()) { + if (mapTopRight.getLongitude() < mapBottomLeft.getLongitude()) { + constraints.add( + new Constraint(mapBottomLeft.getLatitude(), mapBottomLeft.getLongitude(), 90.0, + 180.0)); + constraints.add(new Constraint(mapBottomLeft.getLatitude(), -180.0, 90.0, + mapTopRight.getLongitude())); + constraints.add( + new Constraint(-90.0, mapBottomLeft.getLongitude(), mapTopRight.getLatitude(), + 180.0)); + constraints.add(new Constraint(-90.0, -180.0, mapTopRight.getLatitude(), + mapTopRight.getLongitude())); + } else { + constraints.add( + new Constraint(mapBottomLeft.getLatitude(), mapBottomLeft.getLongitude(), 90.0, + mapTopRight.getLongitude())); + constraints.add( + new Constraint(-90.0, mapBottomLeft.getLongitude(), mapTopRight.getLatitude(), + mapTopRight.getLongitude())); + } + } else { + if (mapTopRight.getLongitude() < mapBottomLeft.getLongitude()) { + constraints.add( + new Constraint(mapBottomLeft.getLatitude(), mapBottomLeft.getLongitude(), + mapTopRight.getLatitude(), 180.0)); + constraints.add( + new Constraint(mapBottomLeft.getLatitude(), -180.0, mapTopRight.getLatitude(), + mapTopRight.getLongitude())); + } else { + constraints.add( + new Constraint(mapBottomLeft.getLatitude(), mapBottomLeft.getLongitude(), + mapTopRight.getLatitude(), mapTopRight.getLongitude())); + } + } + + final List cachedPlaces = new ArrayList<>(); + for (final Constraint constraint : constraints) { + cachedPlaces.addAll(placeDao.fetchPlaces( + constraint.latBegin, + constraint.lngBegin, + constraint.latEnd, + constraint.lngEnd + )); + } + + return cachedPlaces; + } + /** * Saves a Place object asynchronously into the database. * diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java index 846e54fac..c2edfe355 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java @@ -4,6 +4,7 @@ import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.location.LatLng; import io.reactivex.Completable; import io.reactivex.schedulers.Schedulers; +import java.util.List; import javax.inject.Inject; /** @@ -39,6 +40,17 @@ public class PlacesRepository { return localDataSource.fetchPlace(entityID); } + /** + * Retrieves a list of places within the geographical area specified by map's opposite corners. + * + * @param mapBottomLeft Bottom left corner of the map. + * @param mapTopRight Top right corner of the map. + * @return The list of saved places within the map's view. + */ + public List fetchPlaces(final LatLng mapBottomLeft, final LatLng mapTopRight) { + return localDataSource.fetchPlaces(mapBottomLeft, mapTopRight); + } + /** * Clears the Nearby cache on an IO thread. * diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java b/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java index 3b08cf7cb..e46e95353 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/contract/NearbyParentFragmentContract.java @@ -18,6 +18,8 @@ public interface NearbyParentFragmentContract { boolean isNetworkConnectionEstablished(); + void updateSnackbar(boolean offlinePinsShown); + void listOptionMenuItemClicked(); void populatePlaces(LatLng currentLatLng); @@ -91,6 +93,10 @@ public interface NearbyParentFragmentContract { LatLng getMapFocus(); + LatLng getScreenTopRight(); + + LatLng getScreenBottomLeft(); + boolean isAdvancedQueryFragmentVisible(); void showHideAdvancedQueryFragment(boolean shouldShow); @@ -122,8 +128,6 @@ public interface NearbyParentFragmentContract { void filterByMarkerType(List