mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
Merge pull request #1241 from commons-app/realTimeLocation
Real time location track
This commit is contained in:
commit
41e11b7f20
18 changed files with 486 additions and 273 deletions
|
|
@ -86,6 +86,7 @@ public class ContributionController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Timber.d("startGalleryPick() called with pickImageIntent");
|
Timber.d("startGalleryPick() called with pickImageIntent");
|
||||||
|
|
||||||
fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY);
|
fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,6 +116,7 @@ public class ContributionController {
|
||||||
if (isDirectUpload) {
|
if (isDirectUpload) {
|
||||||
shareIntent.putExtra("isDirectUpload", true);
|
shareIntent.putExtra("isDirectUpload", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -159,3 +159,4 @@ public class LatLng {
|
||||||
return Uri.parse("geo:0,0?q=" + latitude + "," + longitude);
|
return Uri.parse("geo:0,0?q=" + latitude + "," + longitude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import android.location.LocationManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
@ -19,7 +20,8 @@ import timber.log.Timber;
|
||||||
public class LocationServiceManager implements LocationListener {
|
public class LocationServiceManager implements LocationListener {
|
||||||
public static final int LOCATION_REQUEST = 1;
|
public static final int LOCATION_REQUEST = 1;
|
||||||
|
|
||||||
private static final long MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS = 2 * 60 * 1000;
|
// Maybe these values can be improved for efficiency
|
||||||
|
private static final long MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS = 2 * 60 * 100;
|
||||||
private static final long MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS = 10;
|
private static final long MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS = 10;
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
@ -120,12 +122,14 @@ public class LocationServiceManager implements LocationListener {
|
||||||
*
|
*
|
||||||
* @param location the location to be tested
|
* @param location the location to be tested
|
||||||
* @param currentBestLocation the current best location
|
* @param currentBestLocation the current best location
|
||||||
* @return true if the given location is better
|
* @return LOCATION_SIGNIFICANTLY_CHANGED if location changed significantly
|
||||||
|
* LOCATION_SLIGHTLY_CHANGED if location changed slightly
|
||||||
*/
|
*/
|
||||||
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
|
protected LocationChangeType isBetterLocation(Location location, Location currentBestLocation) {
|
||||||
|
|
||||||
if (currentBestLocation == null) {
|
if (currentBestLocation == null) {
|
||||||
// A new location is always better than no location
|
// A new location is always better than no location
|
||||||
return true;
|
return LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the new location fix is newer or older
|
// Check whether the new location fix is newer or older
|
||||||
|
|
@ -134,15 +138,6 @@ public class LocationServiceManager implements LocationListener {
|
||||||
boolean isSignificantlyOlder = timeDelta < -MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS;
|
boolean isSignificantlyOlder = timeDelta < -MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS;
|
||||||
boolean isNewer = timeDelta > 0;
|
boolean isNewer = timeDelta > 0;
|
||||||
|
|
||||||
// If it's been more than two minutes since the current location, use the new location
|
|
||||||
// because the user has likely moved
|
|
||||||
if (isSignificantlyNewer) {
|
|
||||||
return true;
|
|
||||||
// If the new location is more than two minutes older, it must be worse
|
|
||||||
} else if (isSignificantlyOlder) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether the new location fix is more or less accurate
|
// Check whether the new location fix is more or less accurate
|
||||||
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
|
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
|
||||||
boolean isLessAccurate = accuracyDelta > 0;
|
boolean isLessAccurate = accuracyDelta > 0;
|
||||||
|
|
@ -153,15 +148,28 @@ public class LocationServiceManager implements LocationListener {
|
||||||
boolean isFromSameProvider = isSameProvider(location.getProvider(),
|
boolean isFromSameProvider = isSameProvider(location.getProvider(),
|
||||||
currentBestLocation.getProvider());
|
currentBestLocation.getProvider());
|
||||||
|
|
||||||
// Determine location quality using a combination of timeliness and accuracy
|
float[] results = new float[5];
|
||||||
if (isMoreAccurate) {
|
Location.distanceBetween(
|
||||||
return true;
|
currentBestLocation.getLatitude(),
|
||||||
} else if (isNewer && !isLessAccurate) {
|
currentBestLocation.getLongitude(),
|
||||||
return true;
|
location.getLatitude(),
|
||||||
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
|
location.getLongitude(),
|
||||||
return true;
|
results);
|
||||||
|
|
||||||
|
// If it's been more than two minutes since the current location, use the new location
|
||||||
|
// because the user has likely moved
|
||||||
|
if (isSignificantlyNewer
|
||||||
|
|| isMoreAccurate
|
||||||
|
|| (isNewer && !isLessAccurate)
|
||||||
|
|| (isNewer && !isSignificantlyLessAccurate && isFromSameProvider)) {
|
||||||
|
if (results[0] < 1000) { // Means change is smaller than 1000 meter
|
||||||
|
return LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||||
|
} else {
|
||||||
|
return LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
return LocationChangeType.LOCATION_NOT_CHANGED;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -208,10 +216,17 @@ public class LocationServiceManager implements LocationListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChanged(Location location) {
|
public void onLocationChanged(Location location) {
|
||||||
if (isBetterLocation(location, lastLocation)) {
|
if (isBetterLocation(location, lastLocation)
|
||||||
|
.equals(LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) {
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
for (LocationUpdateListener listener : locationListeners) {
|
for (LocationUpdateListener listener : locationListeners) {
|
||||||
listener.onLocationChanged(LatLng.from(lastLocation));
|
listener.onLocationChangedSignificantly(LatLng.from(lastLocation));
|
||||||
|
}
|
||||||
|
} else if (isBetterLocation(location, lastLocation)
|
||||||
|
.equals(LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) {
|
||||||
|
lastLocation = location;
|
||||||
|
for (LocationUpdateListener listener : locationListeners) {
|
||||||
|
listener.onLocationChangedSlightly(LatLng.from(lastLocation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -230,4 +245,10 @@ public class LocationServiceManager implements LocationListener {
|
||||||
public void onProviderDisabled(String provider) {
|
public void onProviderDisabled(String provider) {
|
||||||
Timber.d("Provider %s disabled", provider);
|
Timber.d("Provider %s disabled", provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum LocationChangeType{
|
||||||
|
LOCATION_SIGNIFICANTLY_CHANGED, //Went out of borders of nearby markers
|
||||||
|
LOCATION_SLIGHTLY_CHANGED, //User might be walking or driving
|
||||||
|
LOCATION_NOT_CHANGED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.location;
|
package fr.free.nrw.commons.location;
|
||||||
|
|
||||||
public interface LocationUpdateListener {
|
public interface LocationUpdateListener {
|
||||||
void onLocationChanged(LatLng latLng);
|
void onLocationChangedSignificantly(LatLng latLng);
|
||||||
|
void onLocationChangedSlightly(LatLng latLng);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,8 @@ import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.BottomSheetBehavior;
|
import android.support.design.widget.BottomSheetBehavior;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
|
|
@ -28,17 +27,19 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||||
import fr.free.nrw.commons.location.LocationUpdateListener;
|
import fr.free.nrw.commons.location.LocationUpdateListener;
|
||||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||||
import fr.free.nrw.commons.utils.UriSerializer;
|
import fr.free.nrw.commons.utils.UriSerializer;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -68,7 +69,9 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
private BottomSheetBehavior bottomSheetBehavior; // Behavior for list bottom sheet
|
private BottomSheetBehavior bottomSheetBehavior; // Behavior for list bottom sheet
|
||||||
private BottomSheetBehavior bottomSheetBehaviorForDetails; // Behavior for details bottom sheet
|
private BottomSheetBehavior bottomSheetBehaviorForDetails; // Behavior for details bottom sheet
|
||||||
private NearbyMapFragment nearbyMapFragment;
|
private NearbyMapFragment nearbyMapFragment;
|
||||||
private static final String TAG_RETAINED_FRAGMENT = "RetainedFragment";
|
private NearbyListFragment nearbyListFragment;
|
||||||
|
private static final String TAG_RETAINED_MAP_FRAGMENT = NearbyMapFragment.class.getSimpleName();
|
||||||
|
private static final String TAG_RETAINED_LIST_FRAGMENT = NearbyListFragment.class.getSimpleName();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
@ -83,21 +86,13 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resumeFragment() {
|
private void resumeFragment() {
|
||||||
// find the retained fragment on activity restarts
|
// Find the retained fragment on activity restarts
|
||||||
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
|
nearbyMapFragment = getMapFragment();
|
||||||
nearbyMapFragment = (NearbyMapFragment) fm.findFragmentByTag(TAG_RETAINED_FRAGMENT);
|
nearbyListFragment = getListFragment();
|
||||||
|
|
||||||
// create the fragment and data the first time
|
|
||||||
if (nearbyMapFragment == null) {
|
|
||||||
// add the fragment
|
|
||||||
nearbyMapFragment = new NearbyMapFragment();
|
|
||||||
fm.beginTransaction().add(nearbyMapFragment, TAG_RETAINED_FRAGMENT).commit();
|
|
||||||
// load data from a data source or perform any calculation
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initBottomSheetBehaviour() {
|
private void initBottomSheetBehaviour() {
|
||||||
|
|
||||||
transparentView.setAlpha(0);
|
transparentView.setAlpha(0);
|
||||||
|
|
||||||
bottomSheet.getLayoutParams().height = getWindowManager()
|
bottomSheet.getLayoutParams().height = getWindowManager()
|
||||||
|
|
@ -154,7 +149,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case LOCATION_REQUEST: {
|
case LOCATION_REQUEST: {
|
||||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
refreshView();
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
} else {
|
} else {
|
||||||
//If permission not granted, go to page that says Nearby Places cannot be displayed
|
//If permission not granted, go to page that says Nearby Places cannot be displayed
|
||||||
hideProgressBar();
|
hideProgressBar();
|
||||||
|
|
@ -209,7 +204,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
private void checkLocationPermission() {
|
private void checkLocationPermission() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (locationManager.isLocationPermissionGranted()) {
|
if (locationManager.isLocationPermissionGranted()) {
|
||||||
refreshView();
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
} else {
|
} else {
|
||||||
// Should we show an explanation?
|
// Should we show an explanation?
|
||||||
if (locationManager.isPermissionExplanationRequired(this)) {
|
if (locationManager.isPermissionExplanationRequired(this)) {
|
||||||
|
|
@ -235,7 +230,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
refreshView();
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,7 +239,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (requestCode == 1) {
|
if (requestCode == 1) {
|
||||||
Timber.d("User is back from Settings page");
|
Timber.d("User is back from Settings page");
|
||||||
refreshView();
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,6 +247,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
locationManager.addLocationListener(this);
|
locationManager.addLocationListener(this);
|
||||||
|
locationManager.registerLocationManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -282,10 +278,10 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
// this means that this activity will not be recreated now, user is leaving it
|
// this means that this activity will not be recreated now, user is leaving it
|
||||||
// or the activity is otherwise finishing
|
// or the activity is otherwise finishing
|
||||||
if(isFinishing()) {
|
if(isFinishing()) {
|
||||||
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
|
|
||||||
// we will not need this fragment anymore, this may also be a good place to signal
|
// we will not need this fragment anymore, this may also be a good place to signal
|
||||||
// to the retained fragment object to perform its own cleanup.
|
// to the retained fragment object to perform its own cleanup.
|
||||||
fm.beginTransaction().remove(nearbyMapFragment).commit();
|
removeMapFragment();
|
||||||
|
removeListFragment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,13 +290,15 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
/**
|
/**
|
||||||
* This method should be the single point to load/refresh nearby places
|
* This method should be the single point to load/refresh nearby places
|
||||||
*
|
*
|
||||||
|
* @param locationChangeType defines if location shanged significantly or slightly
|
||||||
*/
|
*/
|
||||||
private void refreshView() {
|
private void refreshView(LocationServiceManager.LocationChangeType locationChangeType) {
|
||||||
if (lockNearbyView) {
|
if (lockNearbyView) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
locationManager.registerLocationManager();
|
locationManager.registerLocationManager();
|
||||||
LatLng lastLocation = locationManager.getLastLocation();
|
LatLng lastLocation = locationManager.getLastLocation();
|
||||||
|
|
||||||
if (curLatLang != null && curLatLang.equals(lastLocation)) { //refresh view only if location has changed
|
if (curLatLang != null && curLatLang.equals(lastLocation)) { //refresh view only if location has changed
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -312,20 +310,34 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locationChangeType
|
||||||
|
.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) {
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
placesDisposable = Observable.fromCallable(() -> nearbyController
|
placesDisposable = Observable.fromCallable(() -> nearbyController
|
||||||
.loadAttractionsFromLocation(curLatLang))
|
.loadAttractionsFromLocation(curLatLang))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(this::populatePlaces);
|
.subscribe(this::populatePlaces);
|
||||||
|
} else if (locationChangeType
|
||||||
|
.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) {
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Uri.class, new UriSerializer())
|
||||||
|
.create();
|
||||||
|
String gsonCurLatLng = gson.toJson(curLatLang);
|
||||||
|
bundle.putString("CurLatLng", gsonCurLatLng);
|
||||||
|
updateMapFragment(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populatePlaces(List<Place> placeList) {
|
private void populatePlaces(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
|
||||||
|
List<Place> placeList = nearbyPlacesInfo.placeList;
|
||||||
|
LatLng[] boundaryCoordinates = nearbyPlacesInfo.boundaryCoordinates;
|
||||||
Gson gson = new GsonBuilder()
|
Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter(Uri.class, new UriSerializer())
|
.registerTypeAdapter(Uri.class, new UriSerializer())
|
||||||
.create();
|
.create();
|
||||||
String gsonPlaceList = gson.toJson(placeList);
|
String gsonPlaceList = gson.toJson(placeList);
|
||||||
String gsonCurLatLng = gson.toJson(curLatLang);
|
String gsonCurLatLng = gson.toJson(curLatLang);
|
||||||
|
String gsonBoundaryCoordinates = gson.toJson(boundaryCoordinates);
|
||||||
|
|
||||||
if (placeList.size() == 0) {
|
if (placeList.size() == 0) {
|
||||||
int duration = Toast.LENGTH_SHORT;
|
int duration = Toast.LENGTH_SHORT;
|
||||||
|
|
@ -336,12 +348,20 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
bundle.clear();
|
bundle.clear();
|
||||||
bundle.putString("PlaceList", gsonPlaceList);
|
bundle.putString("PlaceList", gsonPlaceList);
|
||||||
bundle.putString("CurLatLng", gsonCurLatLng);
|
bundle.putString("CurLatLng", gsonCurLatLng);
|
||||||
|
bundle.putString("BoundaryCoord", gsonBoundaryCoordinates);
|
||||||
|
|
||||||
|
// First time to init fragments
|
||||||
|
if (nearbyMapFragment == null) {
|
||||||
lockNearbyView(true);
|
lockNearbyView(true);
|
||||||
setMapFragment();
|
setMapFragment();
|
||||||
setListFragment();
|
setListFragment();
|
||||||
|
|
||||||
hideProgressBar();
|
hideProgressBar();
|
||||||
|
lockNearbyView(false);
|
||||||
|
} else {
|
||||||
|
// There are fragments, just update the map and list
|
||||||
|
updateMapFragment(false);
|
||||||
|
updateListFragment();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void lockNearbyView(boolean lock) {
|
private void lockNearbyView(boolean lock) {
|
||||||
|
|
@ -362,14 +382,92 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private NearbyMapFragment getMapFragment() {
|
||||||
|
return (NearbyMapFragment) getSupportFragmentManager().findFragmentByTag(TAG_RETAINED_MAP_FRAGMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeMapFragment() {
|
||||||
|
if (nearbyMapFragment != null) {
|
||||||
|
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
|
||||||
|
fm.beginTransaction().remove(nearbyMapFragment).commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NearbyListFragment getListFragment() {
|
||||||
|
return (NearbyListFragment) getSupportFragmentManager().findFragmentByTag(TAG_RETAINED_LIST_FRAGMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeListFragment() {
|
||||||
|
if (nearbyListFragment != null) {
|
||||||
|
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
|
||||||
|
fm.beginTransaction().remove(nearbyListFragment).commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMapFragment(boolean isSlightUpdate) {
|
||||||
|
/*
|
||||||
|
* Significant update means updating nearby place markers. Slightly update means only
|
||||||
|
* updating current location marker and camera target.
|
||||||
|
* We update our map Significantly on each 1000 meter change, but we can't never know
|
||||||
|
* the frequency of nearby places. Thus we check if we are close to the boundaries of
|
||||||
|
* our nearby markers, we update our map Significantly.
|
||||||
|
* */
|
||||||
|
|
||||||
|
NearbyMapFragment nearbyMapFragment = getMapFragment();
|
||||||
|
|
||||||
|
if (nearbyMapFragment != null && curLatLang != null) {
|
||||||
|
hideProgressBar(); // In case it is visible (this happens, not an impossible case)
|
||||||
|
/*
|
||||||
|
* If we are close to nearby places boundaries, we need a significant update to
|
||||||
|
* get new nearby places. Check order is south, north, west, east
|
||||||
|
* */
|
||||||
|
if (nearbyMapFragment.boundaryCoordinates != null
|
||||||
|
&& (curLatLang.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude()
|
||||||
|
|| curLatLang.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude()
|
||||||
|
|| curLatLang.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude()
|
||||||
|
|| curLatLang.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) {
|
||||||
|
// populate places
|
||||||
|
placesDisposable = Observable.fromCallable(() -> nearbyController
|
||||||
|
.loadAttractionsFromLocation(curLatLang))
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(this::populatePlaces);
|
||||||
|
nearbyMapFragment.setArguments(bundle);
|
||||||
|
nearbyMapFragment.updateMapSignificantly();
|
||||||
|
updateListFragment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSlightUpdate) {
|
||||||
|
nearbyMapFragment.setArguments(bundle);
|
||||||
|
nearbyMapFragment.updateMapSlightly();
|
||||||
|
} else {
|
||||||
|
nearbyMapFragment.setArguments(bundle);
|
||||||
|
nearbyMapFragment.updateMapSignificantly();
|
||||||
|
updateListFragment();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lockNearbyView(true);
|
||||||
|
setMapFragment();
|
||||||
|
setListFragment();
|
||||||
|
hideProgressBar();
|
||||||
|
lockNearbyView(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateListFragment() {
|
||||||
|
nearbyListFragment.setArguments(bundle);
|
||||||
|
nearbyListFragment.updateNearbyListSignificantly();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls fragment for map view.
|
* Calls fragment for map view.
|
||||||
*/
|
*/
|
||||||
private void setMapFragment() {
|
private void setMapFragment() {
|
||||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||||
Fragment fragment = new NearbyMapFragment();
|
nearbyMapFragment = new NearbyMapFragment();
|
||||||
fragment.setArguments(bundle);
|
nearbyMapFragment.setArguments(bundle);
|
||||||
fragmentTransaction.replace(R.id.container, fragment, fragment.getClass().getSimpleName());
|
fragmentTransaction.replace(R.id.container, nearbyMapFragment, TAG_RETAINED_MAP_FRAGMENT);
|
||||||
fragmentTransaction.commitAllowingStateLoss();
|
fragmentTransaction.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,16 +476,22 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
*/
|
*/
|
||||||
private void setListFragment() {
|
private void setListFragment() {
|
||||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||||
Fragment fragment = new NearbyListFragment();
|
nearbyListFragment = new NearbyListFragment();
|
||||||
fragment.setArguments(bundle);
|
nearbyListFragment.setArguments(bundle);
|
||||||
fragmentTransaction.replace(R.id.container_sheet, fragment);
|
fragmentTransaction.replace(R.id.container_sheet, nearbyListFragment, TAG_RETAINED_LIST_FRAGMENT);
|
||||||
|
initBottomSheetBehaviour();
|
||||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
fragmentTransaction.commitAllowingStateLoss();
|
fragmentTransaction.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChanged(LatLng latLng) {
|
public void onLocationChangedSignificantly(LatLng latLng) {
|
||||||
refreshView();
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocationChangedSlightly(LatLng latLng) {
|
||||||
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareViewsForSheetPosition(int bottomSheetState) {
|
public void prepareViewsForSheetPosition(int bottomSheetState) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
import com.pedrogomez.renderers.ListAdapteeCollection;
|
import com.pedrogomez.renderers.ListAdapteeCollection;
|
||||||
|
|
@ -32,4 +33,9 @@ class NearbyAdapterFactory {
|
||||||
placeList != null ? placeList : Collections.emptyList());
|
placeList != null ? placeList : Collections.emptyList());
|
||||||
return new RVRendererAdapter<>(builder, collection);
|
return new RVRendererAdapter<>(builder, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateAdapterData(List<Place> newPlaceList, RVRendererAdapter<Place> rendererAdapter) {
|
||||||
|
rendererAdapter.notifyDataSetChanged();
|
||||||
|
rendererAdapter.diffUpdate(newPlaceList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,19 +41,42 @@ public class NearbyController {
|
||||||
* Prepares Place list to make their distance information update later.
|
* Prepares Place list to make their distance information update later.
|
||||||
*
|
*
|
||||||
* @param curLatLng current location for user
|
* @param curLatLng current location for user
|
||||||
* @return Place list without distance information
|
* @return NearbyPlacesInfo a variable holds Place list without distance information
|
||||||
|
* and boundary coordinates of current Place List
|
||||||
*/
|
*/
|
||||||
public List<Place> loadAttractionsFromLocation(LatLng curLatLng) {
|
public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng) {
|
||||||
|
|
||||||
Timber.d("Loading attractions near %s", curLatLng);
|
Timber.d("Loading attractions near %s", curLatLng);
|
||||||
|
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
|
||||||
|
|
||||||
if (curLatLng == null) {
|
if (curLatLng == null) {
|
||||||
return Collections.emptyList();
|
return null;
|
||||||
}
|
}
|
||||||
List<Place> places = nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage());
|
List<Place> places = nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage());
|
||||||
|
|
||||||
|
LatLng[] boundaryCoordinates = {places.get(0).location, // south
|
||||||
|
places.get(0).location, // north
|
||||||
|
places.get(0).location, // west
|
||||||
|
places.get(0).location};// east, init with a random location
|
||||||
|
|
||||||
if (curLatLng != null) {
|
if (curLatLng != null) {
|
||||||
Timber.d("Sorting places by distance...");
|
Timber.d("Sorting places by distance...");
|
||||||
final Map<Place, Double> distances = new HashMap<>();
|
final Map<Place, Double> distances = new HashMap<>();
|
||||||
for (Place place: places) {
|
for (Place place: places) {
|
||||||
distances.put(place, computeDistanceBetween(place.location, curLatLng));
|
distances.put(place, computeDistanceBetween(place.location, curLatLng));
|
||||||
|
// Find boundaries with basic find max approach
|
||||||
|
if (place.location.getLatitude() < boundaryCoordinates[0].getLatitude()) {
|
||||||
|
boundaryCoordinates[0] = place.location;
|
||||||
|
}
|
||||||
|
if (place.location.getLatitude() > boundaryCoordinates[1].getLatitude()) {
|
||||||
|
boundaryCoordinates[1] = place.location;
|
||||||
|
}
|
||||||
|
if (place.location.getLongitude() < boundaryCoordinates[2].getLongitude()) {
|
||||||
|
boundaryCoordinates[2] = place.location;
|
||||||
|
}
|
||||||
|
if (place.location.getLongitude() > boundaryCoordinates[3].getLongitude()) {
|
||||||
|
boundaryCoordinates[3] = place.location;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(places,
|
Collections.sort(places,
|
||||||
(lhs, rhs) -> {
|
(lhs, rhs) -> {
|
||||||
|
|
@ -63,7 +86,9 @@ public class NearbyController {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return places;
|
nearbyPlacesInfo.placeList = places;
|
||||||
|
nearbyPlacesInfo.boundaryCoordinates = boundaryCoordinates;
|
||||||
|
return nearbyPlacesInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -128,4 +153,9 @@ public class NearbyController {
|
||||||
}
|
}
|
||||||
return baseMarkerOptions;
|
return baseMarkerOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NearbyPlacesInfo {
|
||||||
|
List<Place> placeList; // List of nearby places
|
||||||
|
LatLng[] boundaryCoordinates; // Corners of nearby area
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import android.view.ViewGroup;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.pedrogomez.renderers.RVRendererAdapter;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -64,6 +65,7 @@ public class NearbyListFragment extends DaggerFragment {
|
||||||
View view = inflater.inflate(R.layout.fragment_nearby, container, false);
|
View view = inflater.inflate(R.layout.fragment_nearby, container, false);
|
||||||
recyclerView = view.findViewById(R.id.listView);
|
recyclerView = view.findViewById(R.id.listView);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
|
||||||
controller = new ContributionController(this);
|
controller = new ContributionController(this);
|
||||||
adapterFactory = new NearbyAdapterFactory(this, controller);
|
adapterFactory = new NearbyAdapterFactory(this, controller);
|
||||||
return view;
|
return view;
|
||||||
|
|
@ -73,8 +75,19 @@ public class NearbyListFragment extends DaggerFragment {
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
// Check that this is the first time view is created,
|
// Check that this is the first time view is created,
|
||||||
// to avoid double list when screen orientation changed
|
// to avoid double list when screen orientation changed
|
||||||
List<Place> placeList = Collections.emptyList();
|
|
||||||
Bundle bundle = this.getArguments();
|
Bundle bundle = this.getArguments();
|
||||||
|
recyclerView.setAdapter(adapterFactory.create(getPlaceListFromBundle(bundle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateNearbyListSignificantly() {
|
||||||
|
Bundle bundle = this.getArguments();
|
||||||
|
adapterFactory.updateAdapterData(getPlaceListFromBundle(bundle),
|
||||||
|
(RVRendererAdapter<Place>) recyclerView.getAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Place> getPlaceListFromBundle(Bundle bundle) {
|
||||||
|
List<Place> placeList = Collections.emptyList();
|
||||||
|
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
String gsonPlaceList = bundle.getString("PlaceList", "[]");
|
String gsonPlaceList = bundle.getString("PlaceList", "[]");
|
||||||
placeList = gson.fromJson(gsonPlaceList, LIST_TYPE);
|
placeList = gson.fromJson(gsonPlaceList, LIST_TYPE);
|
||||||
|
|
@ -84,9 +97,9 @@ public class NearbyListFragment extends DaggerFragment {
|
||||||
|
|
||||||
placeList = NearbyController.loadAttractionsFromLocationToPlaces(curLatLng, placeList);
|
placeList = NearbyController.loadAttractionsFromLocationToPlaces(curLatLng, placeList);
|
||||||
}
|
}
|
||||||
recyclerView.setAdapter(adapterFactory.create(placeList));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return placeList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
|
@ -126,4 +139,5 @@ public class NearbyListFragment extends DaggerFragment {
|
||||||
requestCode, resultCode, data);
|
requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.animation.TypeEvaluator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
|
@ -11,6 +15,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.BottomSheetBehavior;
|
import android.support.design.widget.BottomSheetBehavior;
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
@ -29,11 +34,13 @@ import com.mapbox.mapboxsdk.annotations.Marker;
|
||||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||||
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
||||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||||
|
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||||
import com.mapbox.mapboxsdk.constants.Style;
|
import com.mapbox.mapboxsdk.constants.Style;
|
||||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||||
import com.mapbox.mapboxsdk.maps.MapView;
|
import com.mapbox.mapboxsdk.maps.MapView;
|
||||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||||
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
|
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
|
||||||
|
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||||
import com.mapbox.services.android.telemetry.MapboxTelemetry;
|
import com.mapbox.services.android.telemetry.MapboxTelemetry;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
@ -57,6 +64,8 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
private MapView mapView;
|
private MapView mapView;
|
||||||
private List<NearbyBaseMarker> baseMarkerOptions;
|
private List<NearbyBaseMarker> baseMarkerOptions;
|
||||||
private fr.free.nrw.commons.location.LatLng curLatLng;
|
private fr.free.nrw.commons.location.LatLng curLatLng;
|
||||||
|
public fr.free.nrw.commons.location.LatLng[] boundaryCoordinates;
|
||||||
|
|
||||||
private View bottomSheetList;
|
private View bottomSheetList;
|
||||||
private View bottomSheetDetails;
|
private View bottomSheetDetails;
|
||||||
|
|
||||||
|
|
@ -89,6 +98,12 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
|
|
||||||
private Place place;
|
private Place place;
|
||||||
private Marker selected;
|
private Marker selected;
|
||||||
|
private Marker currentLocationMarker;
|
||||||
|
private MapboxMap mapboxMap;
|
||||||
|
private PolygonOptions currentLocationPolygonOptions;
|
||||||
|
|
||||||
|
private boolean isBottomListSheetExpanded;
|
||||||
|
private final double CAMERA_TARGET_SHIFT_FACTOR = 0.06;
|
||||||
|
|
||||||
@Inject @Named("prefs") SharedPreferences prefs;
|
@Inject @Named("prefs") SharedPreferences prefs;
|
||||||
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
|
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
|
||||||
|
|
@ -100,22 +115,23 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Bundle bundle = this.getArguments();
|
Bundle bundle = this.getArguments();
|
||||||
initViews();
|
|
||||||
setListeners();
|
|
||||||
Gson gson = new GsonBuilder()
|
Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
||||||
.create();
|
.create();
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
String gsonPlaceList = bundle.getString("PlaceList");
|
String gsonPlaceList = bundle.getString("PlaceList");
|
||||||
String gsonLatLng = bundle.getString("CurLatLng");
|
String gsonLatLng = bundle.getString("CurLatLng");
|
||||||
|
String gsonBoundaryCoordinates = bundle.getString("BoundaryCoord");
|
||||||
Type listType = new TypeToken<List<Place>>() {}.getType();
|
Type listType = new TypeToken<List<Place>>() {}.getType();
|
||||||
List<Place> placeList = gson.fromJson(gsonPlaceList, listType);
|
List<Place> placeList = gson.fromJson(gsonPlaceList, listType);
|
||||||
Type curLatLngType = new TypeToken<fr.free.nrw.commons.location.LatLng>() {}.getType();
|
Type curLatLngType = new TypeToken<fr.free.nrw.commons.location.LatLng>() {}.getType();
|
||||||
|
Type gsonBoundaryCoordinatesType = new TypeToken<fr.free.nrw.commons.location.LatLng[]>() {}.getType();
|
||||||
curLatLng = gson.fromJson(gsonLatLng, curLatLngType);
|
curLatLng = gson.fromJson(gsonLatLng, curLatLngType);
|
||||||
baseMarkerOptions = NearbyController
|
baseMarkerOptions = NearbyController
|
||||||
.loadAttractionsFromLocationToBaseMarkerOptions(curLatLng,
|
.loadAttractionsFromLocationToBaseMarkerOptions(curLatLng,
|
||||||
placeList,
|
placeList,
|
||||||
getActivity());
|
getActivity());
|
||||||
|
boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType);
|
||||||
}
|
}
|
||||||
Mapbox.getInstance(getActivity(),
|
Mapbox.getInstance(getActivity(),
|
||||||
getString(R.string.mapbox_commons_app_token));
|
getString(R.string.mapbox_commons_app_token));
|
||||||
|
|
@ -160,12 +176,123 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateMapSlightly() {
|
||||||
|
// Get arguments from bundle for new location
|
||||||
|
Bundle bundle = this.getArguments();
|
||||||
|
if (mapboxMap != null) {
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
||||||
|
.create();
|
||||||
|
if (bundle != null) {
|
||||||
|
String gsonLatLng = bundle.getString("CurLatLng");
|
||||||
|
Type curLatLngType = new TypeToken<fr.free.nrw.commons.location.LatLng>() {}.getType();
|
||||||
|
curLatLng = gson.fromJson(gsonLatLng, curLatLngType);
|
||||||
|
}
|
||||||
|
updateMapToTrackPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMapSignificantly() {
|
||||||
|
|
||||||
|
Bundle bundle = this.getArguments();
|
||||||
|
if (mapboxMap != null) {
|
||||||
|
if (bundle != null) {
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
||||||
|
.create();
|
||||||
|
|
||||||
|
String gsonPlaceList = bundle.getString("PlaceList");
|
||||||
|
String gsonLatLng = bundle.getString("CurLatLng");
|
||||||
|
String gsonBoundaryCoordinates = bundle.getString("BoundaryCoord");
|
||||||
|
Type listType = new TypeToken<List<Place>>() {}.getType();
|
||||||
|
List<Place> placeList = gson.fromJson(gsonPlaceList, listType);
|
||||||
|
Type curLatLngType = new TypeToken<fr.free.nrw.commons.location.LatLng>() {}.getType();
|
||||||
|
Type gsonBoundaryCoordinatesType = new TypeToken<fr.free.nrw.commons.location.LatLng[]>() {}.getType();
|
||||||
|
curLatLng = gson.fromJson(gsonLatLng, curLatLngType);
|
||||||
|
baseMarkerOptions = NearbyController
|
||||||
|
.loadAttractionsFromLocationToBaseMarkerOptions(curLatLng,
|
||||||
|
placeList,
|
||||||
|
getActivity());
|
||||||
|
boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType);
|
||||||
|
}
|
||||||
|
mapboxMap.clear();
|
||||||
|
addCurrentLocationMarker(mapboxMap);
|
||||||
|
updateMapToTrackPosition();
|
||||||
|
addNearbyMarkerstoMapBoxMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update current position marker and camera view
|
||||||
|
private void updateMapToTrackPosition() {
|
||||||
|
|
||||||
|
if (currentLocationMarker != null) {
|
||||||
|
LatLng curMapBoxLatLng = new LatLng(curLatLng.getLatitude(),curLatLng.getLongitude());
|
||||||
|
ValueAnimator markerAnimator = ObjectAnimator.ofObject(currentLocationMarker, "position",
|
||||||
|
new LatLngEvaluator(), currentLocationMarker.getPosition(),
|
||||||
|
curMapBoxLatLng);
|
||||||
|
markerAnimator.setDuration(1000);
|
||||||
|
markerAnimator.start();
|
||||||
|
|
||||||
|
List<LatLng> circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
||||||
|
curLatLng.getAccuracy() * 2, 100);
|
||||||
|
if (currentLocationPolygonOptions != null){
|
||||||
|
mapboxMap.removePolygon(currentLocationPolygonOptions.getPolygon());
|
||||||
|
currentLocationPolygonOptions = new PolygonOptions()
|
||||||
|
.addAll(circle)
|
||||||
|
.strokeColor(Color.parseColor("#55000000"))
|
||||||
|
.fillColor(Color.parseColor("#11000000"));
|
||||||
|
mapboxMap.addPolygon(currentLocationPolygonOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make camera to follow user on location change
|
||||||
|
CameraPosition position = new CameraPosition.Builder()
|
||||||
|
.target(isBottomListSheetExpanded ?
|
||||||
|
new LatLng(curMapBoxLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR,
|
||||||
|
curMapBoxLatLng.getLongitude())
|
||||||
|
: curMapBoxLatLng ) // Sets the new camera position
|
||||||
|
.zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mapboxMap.animateCamera(CameraUpdateFactory
|
||||||
|
.newCameraPosition(position), 1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMapCameraAccordingToBottomSheet(boolean isBottomListSheetExpanded) {
|
||||||
|
CameraPosition position;
|
||||||
|
this.isBottomListSheetExpanded = isBottomListSheetExpanded;
|
||||||
|
if (mapboxMap != null && curLatLng != null) {
|
||||||
|
if (isBottomListSheetExpanded) {
|
||||||
|
// Make camera to follow user on location change
|
||||||
|
position = new CameraPosition.Builder()
|
||||||
|
.target(new LatLng(curLatLng.getLatitude() - CAMERA_TARGET_SHIFT_FACTOR,
|
||||||
|
curLatLng.getLongitude())) // Sets the new camera target above
|
||||||
|
// current to make it visible when sheet is expanded
|
||||||
|
.zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level
|
||||||
|
.build();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Make camera to follow user on location change
|
||||||
|
position = new CameraPosition.Builder()
|
||||||
|
.target(new LatLng(curLatLng.getLatitude(),
|
||||||
|
curLatLng.getLongitude())) // Sets the new camera target to curLatLng
|
||||||
|
.zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
mapboxMap.animateCamera(CameraUpdateFactory
|
||||||
|
.newCameraPosition(position), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initViews() {
|
private void initViews() {
|
||||||
bottomSheetList = getActivity().findViewById(R.id.bottom_sheet);
|
bottomSheetList = getActivity().findViewById(R.id.bottom_sheet);
|
||||||
bottomSheetListBehavior = BottomSheetBehavior.from(bottomSheetList);
|
bottomSheetListBehavior = BottomSheetBehavior.from(bottomSheetList);
|
||||||
bottomSheetDetails = getActivity().findViewById(R.id.bottom_sheet_details);
|
bottomSheetDetails = getActivity().findViewById(R.id.bottom_sheet_details);
|
||||||
bottomSheetDetailsBehavior = BottomSheetBehavior.from(bottomSheetDetails);
|
bottomSheetDetailsBehavior = BottomSheetBehavior.from(bottomSheetDetails);
|
||||||
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
bottomSheetDetails.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
fabPlus = getActivity().findViewById(R.id.fab_plus);
|
fabPlus = getActivity().findViewById(R.id.fab_plus);
|
||||||
fabCamera = getActivity().findViewById(R.id.fab_camera);
|
fabCamera = getActivity().findViewById(R.id.fab_camera);
|
||||||
|
|
@ -233,6 +360,9 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||||
if (newState == BottomSheetBehavior.STATE_EXPANDED){
|
if (newState == BottomSheetBehavior.STATE_EXPANDED){
|
||||||
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
updateMapCameraAccordingToBottomSheet(true);
|
||||||
|
} else {
|
||||||
|
updateMapCameraAccordingToBottomSheet(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,9 +397,48 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
// create map
|
// create map
|
||||||
mapView = new MapView(getActivity(), options);
|
mapView = new MapView(getActivity(), options);
|
||||||
mapView.onCreate(savedInstanceState);
|
mapView.onCreate(savedInstanceState);
|
||||||
mapView.getMapAsync(mapboxMap -> {
|
mapView.getMapAsync(new OnMapReadyCallback() {
|
||||||
mapboxMap.addMarkers(baseMarkerOptions);
|
@Override
|
||||||
|
public void onMapReady(MapboxMap mapboxMap) {
|
||||||
|
NearbyMapFragment.this.mapboxMap = mapboxMap;
|
||||||
|
updateMapSignificantly();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mapView.setStyleUrl("asset://mapstyle.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a marker for the user's current position. Adds a
|
||||||
|
* circle which uses the accuracy * 2, to draw a circle
|
||||||
|
* which represents the user's position with an accuracy
|
||||||
|
* of 95%.
|
||||||
|
*
|
||||||
|
* Should be called only on creation of mapboxMap, there
|
||||||
|
* is other method to update markers location with users
|
||||||
|
* move.
|
||||||
|
*/
|
||||||
|
private void addCurrentLocationMarker(MapboxMap mapboxMap) {
|
||||||
|
if (currentLocationMarker != null) {
|
||||||
|
currentLocationMarker.remove(); // Remove previous marker, we are not Hansel and Gretel
|
||||||
|
}
|
||||||
|
MarkerOptions currentLocationMarkerOptions = new MarkerOptions()
|
||||||
|
.position(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude()));
|
||||||
|
currentLocationMarker = mapboxMap.addMarker(currentLocationMarkerOptions);
|
||||||
|
|
||||||
|
|
||||||
|
List<LatLng> circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
||||||
|
curLatLng.getAccuracy() * 2, 100);
|
||||||
|
|
||||||
|
currentLocationPolygonOptions = new PolygonOptions()
|
||||||
|
.addAll(circle)
|
||||||
|
.strokeColor(Color.parseColor("#55000000"))
|
||||||
|
.fillColor(Color.parseColor("#11000000"));
|
||||||
|
mapboxMap.addPolygon(currentLocationPolygonOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNearbyMarkerstoMapBoxMap() {
|
||||||
|
|
||||||
|
mapboxMap.addMarkers(baseMarkerOptions);
|
||||||
mapboxMap.setOnInfoWindowCloseListener(marker -> {
|
mapboxMap.setOnInfoWindowCloseListener(marker -> {
|
||||||
if (marker == selected){
|
if (marker == selected){
|
||||||
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
|
@ -288,33 +457,9 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
addCurrentLocationMarker(mapboxMap);
|
|
||||||
});
|
|
||||||
|
|
||||||
mapView.setStyleUrl("asset://mapstyle.json");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a marker for the user's current position. Adds a
|
|
||||||
* circle which uses the accuracy * 2, to draw a circle
|
|
||||||
* which represents the user's position with an accuracy
|
|
||||||
* of 95%.
|
|
||||||
*/
|
|
||||||
private void addCurrentLocationMarker(MapboxMap mapboxMap) {
|
|
||||||
MarkerOptions currentLocationMarker = new MarkerOptions()
|
|
||||||
.position(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude()));
|
|
||||||
mapboxMap.addMarker(currentLocationMarker);
|
|
||||||
|
|
||||||
List<LatLng> circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
|
||||||
curLatLng.getAccuracy() * 2, 100);
|
|
||||||
|
|
||||||
mapboxMap.addPolygon(
|
|
||||||
new PolygonOptions()
|
|
||||||
.addAll(circle)
|
|
||||||
.strokeColor(Color.parseColor("#55000000"))
|
|
||||||
.fillColor(Color.parseColor("#11000000"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a series of points that create a circle on the map.
|
* Creates a series of points that create a circle on the map.
|
||||||
|
|
@ -401,6 +546,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
commonsButton.setOnClickListener(view -> openWebView(place.siteLinks.getCommonsLink()));
|
commonsButton.setOnClickListener(view -> openWebView(place.siteLinks.getCommonsLink()));
|
||||||
|
|
||||||
icon.setImageResource(place.getLabel().getIcon());
|
icon.setImageResource(place.getLabel().getIcon());
|
||||||
|
|
||||||
title.setText(place.name);
|
title.setText(place.name);
|
||||||
distance.setText(place.distance);
|
distance.setText(place.distance);
|
||||||
description.setText(place.getLongDescription());
|
description.setText(place.getLongDescription());
|
||||||
|
|
@ -410,6 +556,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
fabCamera.setOnClickListener(view -> {
|
fabCamera.setOnClickListener(view -> {
|
||||||
Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
||||||
controller = new ContributionController(this);
|
controller = new ContributionController(this);
|
||||||
|
|
||||||
DirectUpload directUpload = new DirectUpload(this, controller);
|
DirectUpload directUpload = new DirectUpload(this, controller);
|
||||||
storeSharedPrefs();
|
storeSharedPrefs();
|
||||||
directUpload.initiateCameraUpload();
|
directUpload.initiateCameraUpload();
|
||||||
|
|
@ -418,12 +565,14 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
fabGallery.setOnClickListener(view -> {
|
fabGallery.setOnClickListener(view -> {
|
||||||
Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
||||||
controller = new ContributionController(this);
|
controller = new ContributionController(this);
|
||||||
|
|
||||||
DirectUpload directUpload = new DirectUpload(this, controller);
|
DirectUpload directUpload = new DirectUpload(this, controller);
|
||||||
storeSharedPrefs();
|
storeSharedPrefs();
|
||||||
directUpload.initiateGalleryUpload();
|
directUpload.initiateGalleryUpload();
|
||||||
|
|
||||||
//TODO: App crashes after image upload completes
|
//TODO: App crashes after image upload completes
|
||||||
//TODO: Handle onRequestPermissionsResult
|
//TODO: Handle onRequestPermissionsResult
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -523,10 +672,14 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
if (mapView != null) {
|
if (mapView != null) {
|
||||||
mapView.onResume();
|
mapView.onResume();
|
||||||
}
|
}
|
||||||
super.onResume();
|
initViews();
|
||||||
|
setListeners();
|
||||||
|
transparentView.setClickable(false);
|
||||||
|
transparentView.setAlpha(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -544,4 +697,19 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
}
|
}
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
|
||||||
|
// Method is used to interpolate the marker animation.
|
||||||
|
private LatLng latLng = new LatLng();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
|
||||||
|
latLng.setLatitude(startValue.getLatitude()
|
||||||
|
+ ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
|
||||||
|
latLng.setLongitude(startValue.getLongitude()
|
||||||
|
+ ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
|
||||||
|
return latLng;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ public class Place {
|
||||||
this.siteLinks = siteLinks;
|
this.siteLinks = siteLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
|
||||||
public Label getLabel() {
|
public Label getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() { return name; }
|
|
||||||
|
|
||||||
public String getLongDescription() { return longDescription; }
|
public String getLongDescription() { return longDescription; }
|
||||||
|
|
||||||
public void setDistance(String distance) {
|
public void setDistance(String distance) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.transition.TransitionManager;
|
import android.content.SharedPreferences;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.transition.TransitionManager;
|
||||||
import android.support.v7.widget.PopupMenu;
|
import android.support.v7.widget.PopupMenu;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
@ -37,17 +38,20 @@ public class PlaceRenderer extends Renderer<Place> {
|
||||||
@BindView(R.id.icon) ImageView icon;
|
@BindView(R.id.icon) ImageView icon;
|
||||||
@BindView(R.id.buttonLayout) LinearLayout buttonLayout;
|
@BindView(R.id.buttonLayout) LinearLayout buttonLayout;
|
||||||
@BindView(R.id.cameraButton) LinearLayout cameraButton;
|
@BindView(R.id.cameraButton) LinearLayout cameraButton;
|
||||||
|
|
||||||
@BindView(R.id.galleryButton) LinearLayout galleryButton;
|
@BindView(R.id.galleryButton) LinearLayout galleryButton;
|
||||||
@BindView(R.id.directionsButton) LinearLayout directionsButton;
|
@BindView(R.id.directionsButton) LinearLayout directionsButton;
|
||||||
@BindView(R.id.iconOverflow) LinearLayout iconOverflow;
|
@BindView(R.id.iconOverflow) LinearLayout iconOverflow;
|
||||||
@BindView(R.id.cameraButtonText) TextView cameraButtonText;
|
@BindView(R.id.cameraButtonText) TextView cameraButtonText;
|
||||||
@BindView(R.id.galleryButtonText) TextView galleryButtonText;
|
@BindView(R.id.galleryButtonText) TextView galleryButtonText;
|
||||||
|
|
||||||
@BindView(R.id.directionsButtonText) TextView directionsButtonText;
|
@BindView(R.id.directionsButtonText) TextView directionsButtonText;
|
||||||
@BindView(R.id.iconOverflowText) TextView iconOverflowText;
|
@BindView(R.id.iconOverflowText) TextView iconOverflowText;
|
||||||
|
|
||||||
private View view;
|
private View view;
|
||||||
private static ArrayList<LinearLayout> openedItems;
|
private static ArrayList<LinearLayout> openedItems;
|
||||||
private Place place;
|
private Place place;
|
||||||
|
|
||||||
private Fragment fragment;
|
private Fragment fragment;
|
||||||
private ContributionController controller;
|
private ContributionController controller;
|
||||||
|
|
||||||
|
|
@ -121,6 +125,7 @@ public class PlaceRenderer extends Renderer<Place> {
|
||||||
editor.putString("Title", place.getName());
|
editor.putString("Title", place.getName());
|
||||||
editor.putString("Desc", place.getLongDescription());
|
editor.putString("Desc", place.getLongDescription());
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeLayout(LinearLayout buttonLayout){
|
private void closeLayout(LinearLayout buttonLayout){
|
||||||
|
|
@ -133,10 +138,11 @@ public class PlaceRenderer extends Renderer<Place> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render() {
|
public void render() {
|
||||||
// ((CommonsApplication) getContext().getApplicationContext()).injector().inject(this);
|
|
||||||
place = getContent();
|
place = getContent();
|
||||||
tvName.setText(place.name);
|
tvName.setText(place.name);
|
||||||
String descriptionText = place.getLongDescription();
|
String descriptionText = place.getLongDescription();
|
||||||
|
|
||||||
if (descriptionText.equals("?")) {
|
if (descriptionText.equals("?")) {
|
||||||
descriptionText = getContext().getString(R.string.no_description_found);
|
descriptionText = getContext().getString(R.string.no_description_found);
|
||||||
}
|
}
|
||||||
|
|
@ -154,6 +160,7 @@ public class PlaceRenderer extends Renderer<Place> {
|
||||||
|
|
||||||
iconOverflow.setVisibility(showMenu() ? View.VISIBLE : View.GONE);
|
iconOverflow.setVisibility(showMenu() ? View.VISIBLE : View.GONE);
|
||||||
iconOverflow.setOnClickListener(v -> popupMenuListener());
|
iconOverflow.setOnClickListener(v -> popupMenuListener());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void popupMenuListener() {
|
private void popupMenuListener() {
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import fr.free.nrw.commons.modifications.ModificationsContentProvider;
|
||||||
import fr.free.nrw.commons.modifications.ModifierSequence;
|
import fr.free.nrw.commons.modifications.ModifierSequence;
|
||||||
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||||
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
|
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
|
||||||
|
|
||||||
import fr.free.nrw.commons.utils.ImageUtils;
|
import fr.free.nrw.commons.utils.ImageUtils;
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -111,8 +112,10 @@ public class ShareActivity
|
||||||
private String description;
|
private String description;
|
||||||
private Snackbar snackbar;
|
private Snackbar snackbar;
|
||||||
private boolean duplicateCheckPassed = false;
|
private boolean duplicateCheckPassed = false;
|
||||||
|
|
||||||
private boolean haveCheckedForOtherImages = false;
|
private boolean haveCheckedForOtherImages = false;
|
||||||
private boolean isNearbyUpload = false;
|
private boolean isNearbyUpload = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when user taps the submit button.
|
* Called when user taps the submit button.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
|
||||||
4
app/src/main/res/drawable/blue_location_dot.xml
Normal file
4
app/src/main/res/drawable/blue_location_dot.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</selector>
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/drawer_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/coordinator_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
>
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
layout="@layout/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_below="@id/toolbar">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true" />
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"></FrameLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:id="@+id/transparentView"
|
|
||||||
android:layout_below="@id/toolbar"
|
|
||||||
android:background="#aa969696"
|
|
||||||
android:elevation="6dp"
|
|
||||||
/>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<include layout="@layout/bottom_sheet_nearby" />
|
|
||||||
<include layout="@layout/bottom_sheet_details" android:id="@+id/bottom_sheet_details" />
|
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/fab_plus"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fabSize="normal"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:visibility="invisible"
|
|
||||||
android:clickable="true"
|
|
||||||
app:elevation="6dp"
|
|
||||||
app:pressedTranslationZ="12dp"
|
|
||||||
app:backgroundTint="@color/button_blue"
|
|
||||||
app:layout_anchor="@id/bottom_sheet_details"
|
|
||||||
app:layout_anchorGravity="top|right|end"
|
|
||||||
app:srcCompat="@drawable/ic_add_white_24dp"/>
|
|
||||||
<View
|
|
||||||
android:id = "@+id/empty_view2"
|
|
||||||
android:layout_height = "306dip"
|
|
||||||
android:layout_width = "56dp"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:layout_anchor="@id/fab_plus"
|
|
||||||
app:layout_anchorGravity="center_horizontal"
|
|
||||||
/>
|
|
||||||
<View
|
|
||||||
android:id = "@+id/empty_view1"
|
|
||||||
android:layout_height = "186dip"
|
|
||||||
android:layout_width = "56dp"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:layout_anchor="@id/fab_plus"
|
|
||||||
app:layout_anchorGravity="center_horizontal"
|
|
||||||
/>
|
|
||||||
<View
|
|
||||||
android:id = "@+id/empty_view"
|
|
||||||
android:layout_height = "66dip"
|
|
||||||
android:layout_width = "56dp"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:layout_anchor="@id/fab_plus"
|
|
||||||
app:layout_anchorGravity="center_horizontal"
|
|
||||||
/>
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/fab_camera"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fabSize="mini"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:backgroundTint="@color/main_background_light"
|
|
||||||
app:elevation="6dp"
|
|
||||||
app:pressedTranslationZ="12dp"
|
|
||||||
app:layout_anchor="@id/empty_view1"
|
|
||||||
app:layout_anchorGravity="center_horizontal"
|
|
||||||
app:srcCompat="@drawable/ic_photo_camera_white_24dp"
|
|
||||||
android:tint="@color/button_blue"
|
|
||||||
android:scaleType="center"/>
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/fab_galery"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fabSize="mini"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:backgroundTint="@color/main_background_light"
|
|
||||||
app:elevation="6dp"
|
|
||||||
app:pressedTranslationZ="12dp"
|
|
||||||
app:layout_anchor="@id/empty_view"
|
|
||||||
app:layout_anchorGravity="center_horizontal"
|
|
||||||
app:srcCompat="@drawable/ic_photo_white_24dp"
|
|
||||||
android:tint="@color/button_blue"
|
|
||||||
android:scaleType="center"
|
|
||||||
/>
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/fab_commons_page"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:fabSize="mini"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:backgroundTint="@color/main_background_light"
|
|
||||||
app:elevation="6dp"
|
|
||||||
app:pressedTranslationZ="12dp"
|
|
||||||
app:layout_anchor="@id/empty_view2"
|
|
||||||
app:layout_anchorGravity="center_horizontal"
|
|
||||||
app:srcCompat="@drawable/ic_commons_icon_vector"
|
|
||||||
android:scaleType="center"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<android.support.design.widget.NavigationView
|
|
||||||
android:id="@+id/navigation_view"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
app:headerLayout="@layout/drawer_header"
|
|
||||||
app:menu="@menu/drawer"/>
|
|
||||||
|
|
||||||
</android.support.v4.widget.DrawerLayout>
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
android:background="#aa969696"
|
android:background="#aa969696"
|
||||||
android:elevation="6dp"
|
android:elevation="6dp"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
<include layout="@layout/bottom_sheet_nearby" />
|
<include layout="@layout/bottom_sheet_nearby" />
|
||||||
<include layout="@layout/bottom_sheet_details" android:id="@+id/bottom_sheet_details" />
|
<include layout="@layout/bottom_sheet_details" android:id="@+id/bottom_sheet_details" />
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
app:layout_behavior="@string/bottom_sheet_behavior"
|
app:layout_behavior="@string/bottom_sheet_behavior"
|
||||||
app:behavior_peekHeight="72dp"
|
app:behavior_peekHeight="72dp"
|
||||||
app:behavior_hideable="true"
|
app:behavior_hideable="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,8 @@ public class NearbyAdapterFactoryTest {
|
||||||
private static final Place PLACE = new Place("name", Place.Label.AIRPORT,
|
private static final Place PLACE = new Place("name", Place.Label.AIRPORT,
|
||||||
"desc", null, new LatLng(38.6270, -90.1994, 0), null);
|
"desc", null, new LatLng(38.6270, -90.1994, 0), null);
|
||||||
private static final Place UNKNOWN_PLACE = new Place("name", Place.Label.UNKNOWN,
|
private static final Place UNKNOWN_PLACE = new Place("name", Place.Label.UNKNOWN,
|
||||||
<<<<<<< 27ac8ae0d72011bc651affecf7b1da2100ec927e
|
|
||||||
"?", null, new LatLng(39.7392, -104.9903, 0), null);
|
|
||||||
// ^ "?" is a special value for unknown class names from Wikidata query results
|
|
||||||
=======
|
|
||||||
"desc", null, new LatLng(39.7392, -104.9903, 0), null);
|
"desc", null, new LatLng(39.7392, -104.9903, 0), null);
|
||||||
>>>>>>> Rename Description to Label to prevent misunderstandings
|
|
||||||
private Place clickedPlace;
|
private Place clickedPlace;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue