mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Merge pull request #1346 from commons-app/directNearbyUploadsNew
Merge Direct nearby uploads new branch to master
This commit is contained in:
commit
cb0b9763a7
57 changed files with 2132 additions and 503 deletions
|
|
@ -73,6 +73,8 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
@Inject MediaWikiApi mwApi;
|
@Inject MediaWikiApi mwApi;
|
||||||
@Inject @Named("default_preferences") SharedPreferences prefs;
|
@Inject @Named("default_preferences") SharedPreferences prefs;
|
||||||
|
@Inject @Named("prefs") SharedPreferences prefsPrefs;
|
||||||
|
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
|
||||||
@Inject CategoryDao categoryDao;
|
@Inject CategoryDao categoryDao;
|
||||||
|
|
||||||
private RVRendererAdapter<CategoryItem> categoriesAdapter;
|
private RVRendererAdapter<CategoryItem> categoriesAdapter;
|
||||||
|
|
@ -80,6 +82,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
|
||||||
private HashMap<String, ArrayList<String>> categoriesCache;
|
private HashMap<String, ArrayList<String>> categoriesCache;
|
||||||
private List<CategoryItem> selectedCategories = new ArrayList<>();
|
private List<CategoryItem> selectedCategories = new ArrayList<>();
|
||||||
private TitleTextWatcher textWatcher = new TitleTextWatcher();
|
private TitleTextWatcher textWatcher = new TitleTextWatcher();
|
||||||
|
private boolean hasDirectCategories = false;
|
||||||
|
|
||||||
private final CategoriesAdapterFactory adapterFactory = new CategoriesAdapterFactory(item -> {
|
private final CategoriesAdapterFactory adapterFactory = new CategoriesAdapterFactory(item -> {
|
||||||
if (item.isSelected()) {
|
if (item.isSelected()) {
|
||||||
|
|
@ -128,7 +131,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hideKeyboard(View view) {
|
public void hideKeyboard(View view) {
|
||||||
InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
|
InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
|
||||||
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,7 +226,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
s -> categoriesAdapter.add(s),
|
s -> categoriesAdapter.add(s),
|
||||||
Timber::e,
|
Timber::e,
|
||||||
() -> {
|
() -> {
|
||||||
categoriesAdapter.notifyDataSetChanged();
|
categoriesAdapter.notifyDataSetChanged();
|
||||||
categoriesSearchInProgress.setVisibility(View.GONE);
|
categoriesSearchInProgress.setVisibility(View.GONE);
|
||||||
|
|
@ -258,9 +261,34 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Observable<CategoryItem> defaultCategories() {
|
private Observable<CategoryItem> defaultCategories() {
|
||||||
return gpsCategories()
|
|
||||||
.concatWith(titleCategories())
|
Observable<CategoryItem> directCat = directCategories();
|
||||||
.concatWith(recentCategories());
|
if (hasDirectCategories) {
|
||||||
|
Timber.d("Image has direct Cat");
|
||||||
|
return directCat
|
||||||
|
.concatWith(gpsCategories())
|
||||||
|
.concatWith(titleCategories())
|
||||||
|
.concatWith(recentCategories());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Timber.d("Image has no direct Cat");
|
||||||
|
return gpsCategories()
|
||||||
|
.concatWith(titleCategories())
|
||||||
|
.concatWith(recentCategories());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Observable<CategoryItem> directCategories() {
|
||||||
|
String directCategory = directPrefs.getString("Category", "");
|
||||||
|
List<String> categoryList = new ArrayList<>();
|
||||||
|
Timber.d("Direct category found: " + directCategory);
|
||||||
|
|
||||||
|
if (!directCategory.equals("")) {
|
||||||
|
hasDirectCategories = true;
|
||||||
|
categoryList.add(directCategory);
|
||||||
|
Timber.d("DirectCat does not equal emptyString. Direct Cat list has " + categoryList);
|
||||||
|
}
|
||||||
|
return Observable.fromIterable(categoryList).map(name -> new CategoryItem(name, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Observable<CategoryItem> gpsCategories() {
|
private Observable<CategoryItem> gpsCategories() {
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ import static fr.free.nrw.commons.contributions.Contribution.SOURCE_CAMERA;
|
||||||
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY;
|
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY;
|
||||||
import static fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE;
|
import static fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE;
|
||||||
|
|
||||||
class ContributionController {
|
public class ContributionController {
|
||||||
|
|
||||||
private static final int SELECT_FROM_GALLERY = 1;
|
private static final int SELECT_FROM_GALLERY = 1;
|
||||||
private static final int SELECT_FROM_CAMERA = 2;
|
private static final int SELECT_FROM_CAMERA = 2;
|
||||||
|
|
||||||
private Fragment fragment;
|
private Fragment fragment;
|
||||||
|
|
||||||
ContributionController(Fragment fragment) {
|
public ContributionController(Fragment fragment) {
|
||||||
this.fragment = fragment;
|
this.fragment = fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ class ContributionController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void startCameraCapture() {
|
public void startCameraCapture() {
|
||||||
|
|
||||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
lastGeneratedCaptureUri = reGenerateImageCaptureUriInCache();
|
lastGeneratedCaptureUri = reGenerateImageCaptureUriInCache();
|
||||||
|
|
@ -70,6 +70,9 @@ class ContributionController {
|
||||||
requestWritePermission(fragment.getContext(), takePictureIntent, lastGeneratedCaptureUri);
|
requestWritePermission(fragment.getContext(), takePictureIntent, lastGeneratedCaptureUri);
|
||||||
|
|
||||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, lastGeneratedCaptureUri);
|
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, lastGeneratedCaptureUri);
|
||||||
|
if (!fragment.isAdded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
fragment.startActivityForResult(takePictureIntent, SELECT_FROM_CAMERA);
|
fragment.startActivityForResult(takePictureIntent, SELECT_FROM_CAMERA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,11 +80,19 @@ class ContributionController {
|
||||||
//FIXME: Starts gallery (opens Google Photos)
|
//FIXME: Starts gallery (opens Google Photos)
|
||||||
Intent pickImageIntent = new Intent(ACTION_GET_CONTENT);
|
Intent pickImageIntent = new Intent(ACTION_GET_CONTENT);
|
||||||
pickImageIntent.setType("image/*");
|
pickImageIntent.setType("image/*");
|
||||||
|
// See https://stackoverflow.com/questions/22366596/android-illegalstateexception-fragment-not-attached-to-activity-webview
|
||||||
|
if (!fragment.isAdded()) {
|
||||||
|
Timber.d("Fragment is not added, startActivityForResult cannot be called");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Timber.d("startGalleryPick() called with pickImageIntent");
|
||||||
|
|
||||||
fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY);
|
fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleImagePicked(int requestCode, Intent data) {
|
public void handleImagePicked(int requestCode, Intent data, boolean isDirectUpload) {
|
||||||
FragmentActivity activity = fragment.getActivity();
|
FragmentActivity activity = fragment.getActivity();
|
||||||
|
Timber.d("handleImagePicked() called with onActivityResult()");
|
||||||
Intent shareIntent = new Intent(activity, ShareActivity.class);
|
Intent shareIntent = new Intent(activity, ShareActivity.class);
|
||||||
shareIntent.setAction(ACTION_SEND);
|
shareIntent.setAction(ACTION_SEND);
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
|
|
@ -91,6 +102,9 @@ class ContributionController {
|
||||||
shareIntent.setType(activity.getContentResolver().getType(imageData));
|
shareIntent.setType(activity.getContentResolver().getType(imageData));
|
||||||
shareIntent.putExtra(EXTRA_STREAM, imageData);
|
shareIntent.putExtra(EXTRA_STREAM, imageData);
|
||||||
shareIntent.putExtra(EXTRA_SOURCE, SOURCE_GALLERY);
|
shareIntent.putExtra(EXTRA_SOURCE, SOURCE_GALLERY);
|
||||||
|
if (isDirectUpload) {
|
||||||
|
shareIntent.putExtra("isDirectUpload", true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SELECT_FROM_CAMERA:
|
case SELECT_FROM_CAMERA:
|
||||||
//FIXME: Find out appropriate mime type
|
//FIXME: Find out appropriate mime type
|
||||||
|
|
@ -99,6 +113,10 @@ class ContributionController {
|
||||||
shareIntent.setType("image/jpeg");
|
shareIntent.setType("image/jpeg");
|
||||||
shareIntent.putExtra(EXTRA_STREAM, lastGeneratedCaptureUri);
|
shareIntent.putExtra(EXTRA_STREAM, lastGeneratedCaptureUri);
|
||||||
shareIntent.putExtra(EXTRA_SOURCE, SOURCE_CAMERA);
|
shareIntent.putExtra(EXTRA_SOURCE, SOURCE_CAMERA);
|
||||||
|
if (isDirectUpload) {
|
||||||
|
shareIntent.putExtra("isDirectUpload", true);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -122,5 +140,4 @@ class ContributionController {
|
||||||
lastGeneratedCaptureUri = savedInstanceState.getParcelable("lastGeneratedCaptureURI");
|
lastGeneratedCaptureUri = savedInstanceState.getParcelable("lastGeneratedCaptureURI");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
requestCode, resultCode, data);
|
requestCode, resultCode, data);
|
||||||
controller.handleImagePicked(requestCode, data);
|
controller.handleImagePicked(requestCode, data, false);
|
||||||
} else {
|
} else {
|
||||||
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
requestCode, resultCode, data);
|
requestCode, resultCode, data);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import fr.free.nrw.commons.contributions.ContributionsSyncAdapter;
|
||||||
import fr.free.nrw.commons.delete.DeleteTask;
|
import fr.free.nrw.commons.delete.DeleteTask;
|
||||||
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
|
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
|
||||||
import fr.free.nrw.commons.settings.SettingsFragment;
|
import fr.free.nrw.commons.settings.SettingsFragment;
|
||||||
|
import fr.free.nrw.commons.nearby.PlaceRenderer;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
|
|
@ -44,6 +45,8 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
|
||||||
@Override
|
@Override
|
||||||
void inject(ApplicationlessInjection instance);
|
void inject(ApplicationlessInjection instance);
|
||||||
|
|
||||||
|
void inject(PlaceRenderer placeRenderer);
|
||||||
|
|
||||||
@Component.Builder
|
@Component.Builder
|
||||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||||
interface Builder {
|
interface Builder {
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ public class CommonsApplicationModule {
|
||||||
public static final String CATEGORY_AUTHORITY = "fr.free.nrw.commons.categories.contentprovider";
|
public static final String CATEGORY_AUTHORITY = "fr.free.nrw.commons.categories.contentprovider";
|
||||||
public static final long OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024;
|
public static final long OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024;
|
||||||
|
|
||||||
private CommonsApplication application;
|
|
||||||
private Context applicationContext;
|
private Context applicationContext;
|
||||||
|
|
||||||
public CommonsApplicationModule(Context applicationContext) {
|
public CommonsApplicationModule(Context applicationContext) {
|
||||||
|
|
@ -87,9 +86,13 @@ public class CommonsApplicationModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
public UploadController providesUploadController(Context context,
|
@Named("direct_nearby_upload_prefs")
|
||||||
SessionManager sessionManager,
|
public SharedPreferences providesDirectNearbyUploadPreferences(Context context) {
|
||||||
@Named("default_preferences") SharedPreferences sharedPreferences) {
|
return context.getSharedPreferences("direct_nearby_upload_prefs", MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
public UploadController providesUploadController(SessionManager sessionManager, @Named("default_preferences") SharedPreferences sharedPreferences, Context context) {
|
||||||
return new UploadController(sessionManager, context, sharedPreferences);
|
return new UploadController(sessionManager, context, sharedPreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import fr.free.nrw.commons.contributions.ContributionsListFragment;
|
||||||
import fr.free.nrw.commons.media.MediaDetailFragment;
|
import fr.free.nrw.commons.media.MediaDetailFragment;
|
||||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||||
import fr.free.nrw.commons.nearby.NearbyListFragment;
|
import fr.free.nrw.commons.nearby.NearbyListFragment;
|
||||||
|
import fr.free.nrw.commons.nearby.NearbyMapFragment;
|
||||||
import fr.free.nrw.commons.nearby.NoPermissionsFragment;
|
import fr.free.nrw.commons.nearby.NoPermissionsFragment;
|
||||||
import fr.free.nrw.commons.settings.SettingsFragment;
|
import fr.free.nrw.commons.settings.SettingsFragment;
|
||||||
import fr.free.nrw.commons.upload.MultipleUploadListFragment;
|
import fr.free.nrw.commons.upload.MultipleUploadListFragment;
|
||||||
|
|
@ -31,6 +32,9 @@ public abstract class FragmentBuilderModule {
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract NearbyListFragment bindNearbyListFragment();
|
abstract NearbyListFragment bindNearbyListFragment();
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract NearbyMapFragment bindNearbyMapFragment();
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract NoPermissionsFragment bindNoPermissionsFragment();
|
abstract NoPermissionsFragment bindNoPermissionsFragment();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package fr.free.nrw.commons.location;
|
package fr.free.nrw.commons.location;
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -11,15 +12,15 @@ public class LatLng {
|
||||||
private final double latitude;
|
private final double latitude;
|
||||||
private final double longitude;
|
private final double longitude;
|
||||||
private final float accuracy;
|
private final float accuracy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts latitude and longitude.
|
* Accepts latitude and longitude.
|
||||||
* North and South values are cut off at 90°
|
* North and South values are cut off at 90°
|
||||||
*
|
*
|
||||||
* @param latitude the latitude
|
* @param latitude the latitude
|
||||||
* @param longitude the longitude
|
* @param longitude the longitude
|
||||||
* @param accuracy the accuracy
|
* @param accuracy the accuracy
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* the Statue of Liberty is located at 40.69° N, 74.04° W
|
* the Statue of Liberty is located at 40.69° N, 74.04° W
|
||||||
* The Statue of Liberty could be constructed as LatLng(40.69, -74.04, 1.0)
|
* The Statue of Liberty could be constructed as LatLng(40.69, -74.04, 1.0)
|
||||||
|
|
@ -43,7 +44,7 @@ public class LatLng {
|
||||||
public static LatLng from(@NonNull Location location) {
|
public static LatLng from(@NonNull Location location) {
|
||||||
return new LatLng(location.getLatitude(), location.getLongitude(), location.getAccuracy());
|
return new LatLng(location.getLatitude(), location.getLongitude(), location.getAccuracy());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates a hash code for the longitude and longitude
|
* creates a hash code for the longitude and longitude
|
||||||
*/
|
*/
|
||||||
|
|
@ -153,4 +154,9 @@ public class LatLng {
|
||||||
public double getLatitude() {
|
public double getLatitude() {
|
||||||
return latitude;
|
return latitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uri getGmmIntentUri() {
|
||||||
|
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,12 +216,19 @@ 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)
|
||||||
lastLocation = location;
|
.equals(LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) {
|
||||||
for (LocationUpdateListener listener : locationListeners) {
|
lastLocation = location;
|
||||||
listener.onLocationChanged(LatLng.from(lastLocation));
|
for (LocationUpdateListener listener : locationListeners) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||||
|
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
class DirectUpload {
|
||||||
|
|
||||||
|
private ContributionController controller;
|
||||||
|
private Fragment fragment;
|
||||||
|
|
||||||
|
DirectUpload(Fragment fragment, ContributionController controller) {
|
||||||
|
this.fragment = fragment;
|
||||||
|
this.controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initiateCameraUpload() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (ContextCompat.checkSelfPermission(fragment.getActivity(), WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
|
||||||
|
if (fragment.getActivity().shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
|
||||||
|
new AlertDialog.Builder(fragment.getActivity())
|
||||||
|
.setMessage(fragment.getActivity().getString(R.string.write_storage_permission_rationale))
|
||||||
|
.setPositiveButton("OK", (dialog, which) -> {
|
||||||
|
fragment.getActivity().requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 3);
|
||||||
|
dialog.dismiss();
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
fragment.getActivity().requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 3);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controller.startCameraCapture();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controller.startCameraCapture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initiateGalleryUpload() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (ContextCompat.checkSelfPermission(fragment.getActivity(), READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
|
||||||
|
if (fragment.getActivity().shouldShowRequestPermissionRationale(READ_EXTERNAL_STORAGE)) {
|
||||||
|
new AlertDialog.Builder(fragment.getActivity())
|
||||||
|
.setMessage(fragment.getActivity().getString(R.string.read_storage_permission_rationale))
|
||||||
|
.setPositiveButton("OK", (dialog, which) -> {
|
||||||
|
fragment.getActivity().requestPermissions(new String[]{READ_EXTERNAL_STORAGE}, 1);
|
||||||
|
dialog.dismiss();
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
fragment.getActivity().requestPermissions(new String[]{READ_EXTERNAL_STORAGE},
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controller.startGalleryPick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.startGalleryPick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
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.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.design.widget.BottomSheetBehavior;
|
||||||
|
|
||||||
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;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
|
@ -28,28 +27,36 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener {
|
public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener {
|
||||||
|
|
||||||
private static final int LOCATION_REQUEST = 1;
|
private static final int LOCATION_REQUEST = 1;
|
||||||
private static final String MAP_LAST_USED_PREFERENCE = "mapLastUsed";
|
|
||||||
|
|
||||||
@BindView(R.id.progressBar)
|
@BindView(R.id.progressBar)
|
||||||
ProgressBar progressBar;
|
ProgressBar progressBar;
|
||||||
|
|
||||||
|
@BindView(R.id.bottom_sheet)
|
||||||
|
LinearLayout bottomSheet;
|
||||||
|
@BindView(R.id.bottom_sheet_details)
|
||||||
|
LinearLayout bottomSheetDetails;
|
||||||
|
@BindView(R.id.transparentView)
|
||||||
|
View transparentView;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LocationServiceManager locationManager;
|
LocationServiceManager locationManager;
|
||||||
@Inject
|
@Inject
|
||||||
|
|
@ -57,35 +64,57 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
|
|
||||||
private LatLng curLatLang;
|
private LatLng curLatLang;
|
||||||
private Bundle bundle;
|
private Bundle bundle;
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
private NearbyActivityMode viewMode;
|
|
||||||
private Disposable placesDisposable;
|
private Disposable placesDisposable;
|
||||||
private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed
|
private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed
|
||||||
@BindView(R.id.swipe_container) SwipeRefreshLayout swipeLayout;
|
private BottomSheetBehavior bottomSheetBehavior; // Behavior for list bottom sheet
|
||||||
|
private BottomSheetBehavior bottomSheetBehaviorForDetails; // Behavior for details bottom sheet
|
||||||
|
private NearbyMapFragment nearbyMapFragment;
|
||||||
|
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) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
|
||||||
setContentView(R.layout.activity_nearby);
|
setContentView(R.layout.activity_nearby);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
|
resumeFragment();
|
||||||
bundle = new Bundle();
|
bundle = new Bundle();
|
||||||
|
|
||||||
|
initBottomSheetBehaviour();
|
||||||
initDrawer();
|
initDrawer();
|
||||||
initViewState();
|
|
||||||
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
|
||||||
@Override
|
|
||||||
public void onRefresh() {
|
|
||||||
lockNearbyView(false);
|
|
||||||
refreshView(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initViewState() {
|
private void resumeFragment() {
|
||||||
if (sharedPreferences.getBoolean(MAP_LAST_USED_PREFERENCE, false)) {
|
// Find the retained fragment on activity restarts
|
||||||
viewMode = NearbyActivityMode.MAP;
|
nearbyMapFragment = getMapFragment();
|
||||||
} else {
|
nearbyListFragment = getListFragment();
|
||||||
viewMode = NearbyActivityMode.LIST;
|
}
|
||||||
}
|
|
||||||
|
private void initBottomSheetBehaviour() {
|
||||||
|
|
||||||
|
transparentView.setAlpha(0);
|
||||||
|
|
||||||
|
bottomSheet.getLayoutParams().height = getWindowManager()
|
||||||
|
.getDefaultDisplay().getHeight() / 16 * 9;
|
||||||
|
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
|
||||||
|
// TODO initProperBottomSheetBehavior();
|
||||||
|
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateChanged(View bottomSheet, int newState) {
|
||||||
|
prepareViewsForSheetPosition(newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSlide(View bottomSheet, float slideOffset) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
bottomSheetBehaviorForDetails = BottomSheetBehavior.from(bottomSheetDetails);
|
||||||
|
bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -93,11 +122,6 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.menu_nearby, menu);
|
inflater.inflate(R.menu.menu_nearby, menu);
|
||||||
|
|
||||||
if (viewMode.isMap()) {
|
|
||||||
MenuItem item = menu.findItem(R.id.action_toggle_view);
|
|
||||||
item.setIcon(viewMode.getIcon());
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,14 +129,9 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
// Handle item selection
|
// Handle item selection
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_refresh:
|
case R.id.action_display_list:
|
||||||
lockNearbyView(false);
|
bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
refreshView(true);
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||||
return true;
|
|
||||||
case R.id.action_toggle_view:
|
|
||||||
viewMode = viewMode.toggle();
|
|
||||||
item.setIcon(viewMode.getIcon());
|
|
||||||
toggleView();
|
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
|
@ -130,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(false);
|
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();
|
||||||
|
|
@ -185,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(false);
|
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)) {
|
||||||
|
|
@ -211,7 +230,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
refreshView(false);
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,23 +239,15 @@ 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(false);
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleView() {
|
|
||||||
if (viewMode.isMap()) {
|
|
||||||
setMapFragment();
|
|
||||||
} else {
|
|
||||||
setListFragment();
|
|
||||||
}
|
|
||||||
sharedPreferences.edit().putBoolean(MAP_LAST_USED_PREFERENCE, viewMode.isMap()).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
locationManager.addLocationListener(this);
|
locationManager.addLocationListener(this);
|
||||||
|
locationManager.registerLocationManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -261,21 +272,34 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
checkGps();
|
checkGps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
// this means that this activity will not be recreated now, user is leaving it
|
||||||
|
// or the activity is otherwise finishing
|
||||||
|
if(isFinishing()) {
|
||||||
|
// 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.
|
||||||
|
removeMapFragment();
|
||||||
|
removeListFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 isHardRefresh Should display a toast if the location hasn't changed
|
* @param locationChangeType defines if location shanged significantly or slightly
|
||||||
*/
|
*/
|
||||||
private void refreshView(boolean isHardRefresh) {
|
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
|
||||||
if (isHardRefresh) {
|
|
||||||
ViewUtil.showSnackbar(findViewById(R.id.container), R.string.nearby_location_has_not_changed);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
curLatLang = lastLocation;
|
curLatLang = lastLocation;
|
||||||
|
|
@ -285,20 +309,34 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
if (locationChangeType
|
||||||
placesDisposable = Observable.fromCallable(() -> nearbyController
|
.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) {
|
||||||
.loadAttractionsFromLocation(curLatLang, this))
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
.subscribeOn(Schedulers.io())
|
placesDisposable = Observable.fromCallable(() -> nearbyController
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.loadAttractionsFromLocation(curLatLang))
|
||||||
.subscribe(this::populatePlaces);
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.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) {
|
||||||
ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby);
|
ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby);
|
||||||
|
|
@ -307,16 +345,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);
|
||||||
|
|
||||||
lockNearbyView(true);
|
// First time to init fragments
|
||||||
// Begin the transaction
|
if (nearbyMapFragment == null) {
|
||||||
if (viewMode.isMap()) {
|
lockNearbyView(true);
|
||||||
setMapFragment();
|
setMapFragment();
|
||||||
} else {
|
|
||||||
setListFragment();
|
setListFragment();
|
||||||
|
hideProgressBar();
|
||||||
|
lockNearbyView(false);
|
||||||
|
} else {
|
||||||
|
// There are fragments, just update the map and list
|
||||||
|
updateMapFragment(false);
|
||||||
|
updateListFragment();
|
||||||
}
|
}
|
||||||
swipeLayout.setRefreshing(false);
|
|
||||||
hideProgressBar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void lockNearbyView(boolean lock) {
|
private void lockNearbyView(boolean lock) {
|
||||||
|
|
@ -337,14 +379,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -353,14 +473,25 @@ 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, fragment, fragment.getClass().getSimpleName());
|
fragmentTransaction.replace(R.id.container_sheet, nearbyListFragment, TAG_RETAINED_LIST_FRAGMENT);
|
||||||
|
initBottomSheetBehaviour();
|
||||||
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
fragmentTransaction.commitAllowingStateLoss();
|
fragmentTransaction.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChanged(LatLng latLng) {
|
public void onLocationChangedSignificantly(LatLng latLng) {
|
||||||
refreshView(false);
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocationChangedSlightly(LatLng latLng) {
|
||||||
|
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepareViewsForSheetPosition(int bottomSheetState) {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
|
||||||
|
|
||||||
import android.support.annotation.DrawableRes;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
|
||||||
|
|
||||||
enum NearbyActivityMode {
|
|
||||||
MAP(R.drawable.ic_list_white_24dp),
|
|
||||||
LIST(R.drawable.ic_map_white_24dp);
|
|
||||||
|
|
||||||
@DrawableRes
|
|
||||||
private final int icon;
|
|
||||||
|
|
||||||
NearbyActivityMode(int icon) {
|
|
||||||
this.icon = icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
@DrawableRes
|
|
||||||
public int getIcon() {
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NearbyActivityMode toggle() {
|
|
||||||
return isMap() ? LIST : MAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMap() {
|
|
||||||
return MAP.equals(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
import com.pedrogomez.renderers.ListAdapteeCollection;
|
import com.pedrogomez.renderers.ListAdapteeCollection;
|
||||||
import com.pedrogomez.renderers.RVRendererAdapter;
|
import com.pedrogomez.renderers.RVRendererAdapter;
|
||||||
|
|
@ -9,18 +10,32 @@ import com.pedrogomez.renderers.RendererBuilder;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
class NearbyAdapterFactory {
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
private PlaceRenderer.PlaceClickedListener listener;
|
|
||||||
|
|
||||||
NearbyAdapterFactory(@NonNull PlaceRenderer.PlaceClickedListener listener) {
|
class NearbyAdapterFactory {
|
||||||
this.listener = listener;
|
|
||||||
|
private Fragment fragment;
|
||||||
|
private ContributionController controller;
|
||||||
|
|
||||||
|
NearbyAdapterFactory(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NearbyAdapterFactory(Fragment fragment, ContributionController controller) {
|
||||||
|
this.fragment = fragment;
|
||||||
|
this.controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RVRendererAdapter<Place> create(List<Place> placeList) {
|
public RVRendererAdapter<Place> create(List<Place> placeList) {
|
||||||
RendererBuilder<Place> builder = new RendererBuilder<Place>()
|
RendererBuilder<Place> builder = new RendererBuilder<Place>()
|
||||||
.bind(Place.class, new PlaceRenderer(listener));
|
.bind(Place.class, new PlaceRenderer(fragment, controller));
|
||||||
ListAdapteeCollection<Place> collection = new ListAdapteeCollection<>(
|
ListAdapteeCollection<Place> collection = new ListAdapteeCollection<>(
|
||||||
placeList != null ? placeList : Collections.<Place>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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ public class NearbyBaseMarker extends BaseMarkerOptions<NearbyMarker, NearbyBase
|
||||||
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
|
position(in.readParcelable(LatLng.class.getClassLoader()));
|
||||||
snippet(in.readString());
|
snippet(in.readString());
|
||||||
String iconId = in.readString();
|
String iconId = in.readString();
|
||||||
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
|
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
|
||||||
|
|
|
||||||
|
|
@ -41,30 +41,54 @@ 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
|
||||||
* @param context context
|
* @return NearbyPlacesInfo a variable holds Place list without distance information
|
||||||
* @return Place list without distance information
|
* and boundary coordinates of current Place List
|
||||||
*/
|
*/
|
||||||
public List<Place> loadAttractionsFromLocation(LatLng curLatLng, Context context) {
|
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 = prefs.getBoolean("useWikidata", true)
|
List<Place> places = nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage());
|
||||||
? nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage())
|
|
||||||
: nearbyPlaces.getFromWikiNeedsPictures();
|
LatLng[] boundaryCoordinates = {places.get(0).location, // south
|
||||||
Timber.d("Sorting places by distance...");
|
places.get(0).location, // north
|
||||||
final Map<Place, Double> distances = new HashMap<>();
|
places.get(0).location, // west
|
||||||
for (Place place : places) {
|
places.get(0).location};// east, init with a random location
|
||||||
distances.put(place, computeDistanceBetween(place.location, curLatLng));
|
|
||||||
}
|
if (curLatLng != null) {
|
||||||
Collections.sort(places,
|
Timber.d("Sorting places by distance...");
|
||||||
(lhs, rhs) -> {
|
final Map<Place, Double> distances = new HashMap<>();
|
||||||
double lhsDistance = distances.get(lhs);
|
for (Place place: places) {
|
||||||
double rhsDistance = distances.get(rhs);
|
distances.put(place, computeDistanceBetween(place.location, curLatLng));
|
||||||
return (int) (lhsDistance - rhsDistance);
|
// 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()) {
|
||||||
return places;
|
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,
|
||||||
|
(lhs, rhs) -> {
|
||||||
|
double lhsDistance = distances.get(lhs);
|
||||||
|
double rhsDistance = distances.get(rhs);
|
||||||
|
return (int) (lhsDistance - rhsDistance);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nearbyPlacesInfo.placeList = places;
|
||||||
|
nearbyPlacesInfo.boundaryCoordinates = boundaryCoordinates;
|
||||||
|
return nearbyPlacesInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -129,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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.customtabs.CustomTabsIntent;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.widget.PopupMenu;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
import butterknife.Unbinder;
|
|
||||||
import fr.free.nrw.commons.R;
|
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import fr.free.nrw.commons.ui.widget.OverlayDialog;
|
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
|
||||||
|
|
||||||
public class NearbyInfoDialog extends OverlayDialog {
|
|
||||||
|
|
||||||
private final static String ARG_TITLE = "placeTitle";
|
|
||||||
private final static String ARG_DESC = "placeDesc";
|
|
||||||
private final static String ARG_LATITUDE = "latitude";
|
|
||||||
private final static String ARG_LONGITUDE = "longitude";
|
|
||||||
private final static String ARG_SITE_LINK = "sitelink";
|
|
||||||
|
|
||||||
@BindView(R.id.link_preview_title) TextView placeTitle;
|
|
||||||
@BindView(R.id.link_preview_extract) TextView placeDescription;
|
|
||||||
@BindView(R.id.link_preview_go_button) TextView goToButton;
|
|
||||||
@BindView(R.id.link_preview_overflow_button) ImageView overflowButton;
|
|
||||||
|
|
||||||
private Unbinder unbinder;
|
|
||||||
private LatLng location;
|
|
||||||
private Sitelinks sitelinks;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.dialog_nearby_info, container, false);
|
|
||||||
unbinder = ButterKnife.bind(this, view);
|
|
||||||
initUi();
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initUi() {
|
|
||||||
Bundle bundle = getArguments();
|
|
||||||
placeTitle.setText(bundle.getString(ARG_TITLE));
|
|
||||||
placeDescription.setText(bundle.getString(ARG_DESC));
|
|
||||||
location = new LatLng(bundle.getDouble(ARG_LATITUDE), bundle.getDouble(ARG_LONGITUDE), 0);
|
|
||||||
getArticleLink(bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getArticleLink(Bundle bundle) {
|
|
||||||
this.sitelinks = bundle.getParcelable(ARG_SITE_LINK);
|
|
||||||
|
|
||||||
if (sitelinks == null || Uri.EMPTY.equals(sitelinks.getWikipediaLink())) {
|
|
||||||
goToButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
overflowButton.setVisibility(showMenu() ? View.VISIBLE : View.GONE);
|
|
||||||
|
|
||||||
overflowButton.setOnClickListener(v -> popupMenuListener());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void popupMenuListener() {
|
|
||||||
PopupMenu popupMenu = new PopupMenu(getActivity(), overflowButton);
|
|
||||||
popupMenu.inflate(R.menu.nearby_info_dialog_options);
|
|
||||||
|
|
||||||
MenuItem commonsArticle = popupMenu.getMenu()
|
|
||||||
.findItem(R.id.nearby_info_menu_commons_article);
|
|
||||||
MenuItem wikiDataArticle = popupMenu.getMenu()
|
|
||||||
.findItem(R.id.nearby_info_menu_wikidata_article);
|
|
||||||
|
|
||||||
commonsArticle.setEnabled(!sitelinks.getCommonsLink().equals(Uri.EMPTY));
|
|
||||||
wikiDataArticle.setEnabled(!sitelinks.getWikidataLink().equals(Uri.EMPTY));
|
|
||||||
|
|
||||||
popupMenu.setOnMenuItemClickListener(menuListener);
|
|
||||||
popupMenu.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean showMenu() {
|
|
||||||
return !sitelinks.getCommonsLink().equals(Uri.EMPTY)
|
|
||||||
|| !sitelinks.getWikidataLink().equals(Uri.EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final PopupMenu.OnMenuItemClickListener menuListener = new PopupMenu
|
|
||||||
.OnMenuItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case R.id.nearby_info_menu_commons_article:
|
|
||||||
openWebView(sitelinks.getCommonsLink());
|
|
||||||
return true;
|
|
||||||
case R.id.nearby_info_menu_wikidata_article:
|
|
||||||
openWebView(sitelinks.getWikidataLink());
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static void showYourself(FragmentActivity fragmentActivity, Place place) {
|
|
||||||
NearbyInfoDialog mDialog = new NearbyInfoDialog();
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putString(ARG_TITLE, place.name);
|
|
||||||
bundle.putString(ARG_DESC, place.getLongDescription());
|
|
||||||
bundle.putDouble(ARG_LATITUDE, place.location.getLatitude());
|
|
||||||
bundle.putDouble(ARG_LONGITUDE, place.location.getLongitude());
|
|
||||||
bundle.putParcelable(ARG_SITE_LINK, place.siteLinks);
|
|
||||||
mDialog.setArguments(bundle);
|
|
||||||
DialogUtil.showSafely(fragmentActivity, mDialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
super.onDestroyView();
|
|
||||||
unbinder.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.link_preview_directions_button)
|
|
||||||
void onDirectionsClick() {
|
|
||||||
//Open map app at given position
|
|
||||||
Uri gmmIntentUri = Uri.parse(
|
|
||||||
"geo:0,0?q=" + location.getLatitude() + "," + location.getLongitude());
|
|
||||||
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
|
||||||
|
|
||||||
if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
|
|
||||||
startActivity(mapIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.link_preview_go_button)
|
|
||||||
void onReadArticleClick() {
|
|
||||||
openWebView(sitelinks.getWikipediaLink());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openWebView(Uri link) {
|
|
||||||
Utils.handleWebUrl(getContext(),link);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.emptyLayout)
|
|
||||||
void onCloseClicked() {
|
|
||||||
dismissAllowingStateLoss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
@ -13,18 +15,24 @@ 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;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dagger.android.support.AndroidSupportInjection;
|
import dagger.android.support.AndroidSupportInjection;
|
||||||
|
import dagger.android.support.DaggerFragment;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.utils.UriDeserializer;
|
import fr.free.nrw.commons.utils.UriDeserializer;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class NearbyListFragment extends Fragment {
|
import static android.app.Activity.RESULT_OK;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
public class NearbyListFragment extends DaggerFragment {
|
||||||
private static final Type LIST_TYPE = new TypeToken<List<Place>>() {
|
private static final Type LIST_TYPE = new TypeToken<List<Place>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
private static final Type CUR_LAT_LNG_TYPE = new TypeToken<LatLng>() {
|
private static final Type CUR_LAT_LNG_TYPE = new TypeToken<LatLng>() {
|
||||||
|
|
@ -35,6 +43,7 @@ public class NearbyListFragment extends Fragment {
|
||||||
|
|
||||||
private NearbyAdapterFactory adapterFactory;
|
private NearbyAdapterFactory adapterFactory;
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
|
private ContributionController controller;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
@ -54,9 +63,11 @@ public class NearbyListFragment extends Fragment {
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
Timber.d("NearbyListFragment created");
|
Timber.d("NearbyListFragment created");
|
||||||
View view = inflater.inflate(R.layout.fragment_nearby, container, false);
|
View view = inflater.inflate(R.layout.fragment_nearby, container, false);
|
||||||
recyclerView = (RecyclerView) view.findViewById(R.id.listView);
|
recyclerView = view.findViewById(R.id.listView);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
adapterFactory = new NearbyAdapterFactory(place -> NearbyInfoDialog.showYourself(getActivity(), place));
|
|
||||||
|
controller = new ContributionController(this);
|
||||||
|
adapterFactory = new NearbyAdapterFactory(this, controller);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,9 +75,19 @@ public class NearbyListFragment extends Fragment {
|
||||||
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
|
||||||
|
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();
|
List<Place> placeList = Collections.emptyList();
|
||||||
|
|
||||||
Bundle bundle = this.getArguments();
|
|
||||||
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);
|
||||||
|
|
@ -77,6 +98,46 @@ public class NearbyListFragment extends Fragment {
|
||||||
placeList = NearbyController.loadAttractionsFromLocationToPlaces(curLatLng, placeList);
|
placeList = NearbyController.loadAttractionsFromLocationToPlaces(curLatLng, placeList);
|
||||||
}
|
}
|
||||||
|
|
||||||
recyclerView.setAdapter(adapterFactory.create(placeList));
|
return placeList;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
Timber.d("onRequestPermissionsResult: req code = " + " perm = " + permissions + " grant =" + grantResults);
|
||||||
|
|
||||||
|
switch (requestCode) {
|
||||||
|
// 1 = "Read external storage" allowed when gallery selected
|
||||||
|
case 1: {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) {
|
||||||
|
Timber.d("Call controller.startGalleryPick()");
|
||||||
|
controller.startGalleryPick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 3 = "Write external storage" allowed when camera selected
|
||||||
|
case 3: {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
Timber.d("Call controller.startCameraCapture()");
|
||||||
|
controller.startCameraCapture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
requestCode, resultCode, data);
|
||||||
|
controller.handleImagePicked(requestCode, data, true);
|
||||||
|
} else {
|
||||||
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,37 +1,116 @@
|
||||||
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.SharedPreferences;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.BottomSheetBehavior;
|
||||||
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.AnimationUtils;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
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.mapbox.mapboxsdk.Mapbox;
|
import com.mapbox.mapboxsdk.Mapbox;
|
||||||
|
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||||
|
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||||
|
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;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
import javax.inject.Inject;
|
||||||
import fr.free.nrw.commons.utils.UriDeserializer;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import dagger.android.support.DaggerFragment;
|
||||||
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
|
import fr.free.nrw.commons.utils.UriDeserializer;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static android.app.Activity.RESULT_OK;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
public class NearbyMapFragment extends DaggerFragment {
|
||||||
|
|
||||||
public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
|
||||||
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 bottomSheetDetails;
|
||||||
|
|
||||||
|
private BottomSheetBehavior bottomSheetListBehavior;
|
||||||
|
private BottomSheetBehavior bottomSheetDetailsBehavior;
|
||||||
|
private LinearLayout wikipediaButton;
|
||||||
|
private LinearLayout wikidataButton;
|
||||||
|
private LinearLayout directionsButton;
|
||||||
|
private LinearLayout commonsButton;
|
||||||
|
private FloatingActionButton fabPlus;
|
||||||
|
private FloatingActionButton fabCamera;
|
||||||
|
private FloatingActionButton fabGallery;
|
||||||
|
private View transparentView;
|
||||||
|
private TextView description;
|
||||||
|
private TextView title;
|
||||||
|
private TextView distance;
|
||||||
|
private ImageView icon;
|
||||||
|
|
||||||
|
private TextView wikipediaButtonText;
|
||||||
|
private TextView wikidataButtonText;
|
||||||
|
private TextView commonsButtonText;
|
||||||
|
private TextView directionsButtonText;
|
||||||
|
|
||||||
|
private boolean isFabOpen=false;
|
||||||
|
private Animation rotate_backward;
|
||||||
|
private Animation fab_close;
|
||||||
|
private Animation fab_open;
|
||||||
|
private Animation rotate_forward;
|
||||||
|
private ContributionController controller;
|
||||||
|
|
||||||
|
private Place place;
|
||||||
|
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("direct_nearby_upload_prefs") SharedPreferences directPrefs;
|
||||||
|
|
||||||
public NearbyMapFragment() {
|
public NearbyMapFragment() {
|
||||||
}
|
}
|
||||||
|
|
@ -46,18 +125,22 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
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));
|
||||||
MapboxTelemetry.getInstance().setTelemetryEnabled(false);
|
MapboxTelemetry.getInstance().setTelemetryEnabled(false);
|
||||||
|
setRetainInstance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -73,6 +156,238 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
return mapView;
|
return mapView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
this.getView().setFocusableInTouchMode(true);
|
||||||
|
this.getView().requestFocus();
|
||||||
|
this.getView().setOnKeyListener((v, keyCode, event) -> {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
if(bottomSheetDetailsBehavior.getState() == BottomSheetBehavior
|
||||||
|
.STATE_EXPANDED) {
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (bottomSheetDetailsBehavior.getState() == BottomSheetBehavior
|
||||||
|
.STATE_COLLAPSED) {
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
mapView.getMapAsync(MapboxMap::deselectMarkers);
|
||||||
|
selected=null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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(11) // 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() {
|
||||||
|
bottomSheetList = getActivity().findViewById(R.id.bottom_sheet);
|
||||||
|
bottomSheetListBehavior = BottomSheetBehavior.from(bottomSheetList);
|
||||||
|
bottomSheetDetails = getActivity().findViewById(R.id.bottom_sheet_details);
|
||||||
|
bottomSheetDetailsBehavior = BottomSheetBehavior.from(bottomSheetDetails);
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
bottomSheetDetails.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
fabPlus = getActivity().findViewById(R.id.fab_plus);
|
||||||
|
fabCamera = getActivity().findViewById(R.id.fab_camera);
|
||||||
|
fabGallery = getActivity().findViewById(R.id.fab_galery);
|
||||||
|
|
||||||
|
fab_open = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_open);
|
||||||
|
fab_close = AnimationUtils.loadAnimation(getActivity(),R.anim.fab_close);
|
||||||
|
rotate_forward = AnimationUtils.loadAnimation(getActivity(),R.anim.rotate_forward);
|
||||||
|
rotate_backward = AnimationUtils.loadAnimation(getActivity(),R.anim.rotate_backward);
|
||||||
|
|
||||||
|
transparentView = getActivity().findViewById(R.id.transparentView);
|
||||||
|
|
||||||
|
description = getActivity().findViewById(R.id.description);
|
||||||
|
title = getActivity().findViewById(R.id.title);
|
||||||
|
distance = getActivity().findViewById(R.id.category);
|
||||||
|
icon = getActivity().findViewById(R.id.icon);
|
||||||
|
|
||||||
|
wikidataButton = getActivity().findViewById(R.id.wikidataButton);
|
||||||
|
wikipediaButton = getActivity().findViewById(R.id.wikipediaButton);
|
||||||
|
directionsButton = getActivity().findViewById(R.id.directionsButton);
|
||||||
|
commonsButton = getActivity().findViewById(R.id.commonsButton);
|
||||||
|
|
||||||
|
wikidataButtonText = getActivity().findViewById(R.id.wikidataButtonText);
|
||||||
|
wikipediaButtonText = getActivity().findViewById(R.id.wikipediaButtonText);
|
||||||
|
directionsButtonText = getActivity().findViewById(R.id.directionsButtonText);
|
||||||
|
commonsButtonText = getActivity().findViewById(R.id.commonsButtonText);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setListeners() {
|
||||||
|
fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
||||||
|
|
||||||
|
bottomSheetDetails.setOnClickListener(view -> {
|
||||||
|
if(bottomSheetDetailsBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bottomSheetDetailsBehavior.setBottomSheetCallback(new BottomSheetBehavior
|
||||||
|
.BottomSheetCallback() {
|
||||||
|
@Override
|
||||||
|
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||||
|
prepareViewsForSheetPosition(newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
||||||
|
if (slideOffset >= 0) {
|
||||||
|
transparentView.setAlpha(slideOffset);
|
||||||
|
if (slideOffset == 1) {
|
||||||
|
transparentView.setClickable(true);
|
||||||
|
} else if (slideOffset == 0){
|
||||||
|
transparentView.setClickable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bottomSheetListBehavior.setBottomSheetCallback(new BottomSheetBehavior
|
||||||
|
.BottomSheetCallback() {
|
||||||
|
@Override
|
||||||
|
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||||
|
if (newState == BottomSheetBehavior.STATE_EXPANDED){
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
updateMapCameraAccordingToBottomSheet(true);
|
||||||
|
} else {
|
||||||
|
updateMapCameraAccordingToBottomSheet(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove texts if it doesnt fit
|
||||||
|
if (wikipediaButtonText.getLineCount() > 1
|
||||||
|
|| wikidataButtonText.getLineCount() > 1
|
||||||
|
|| commonsButtonText.getLineCount() > 1
|
||||||
|
|| directionsButtonText.getLineCount() > 1) {
|
||||||
|
wikipediaButtonText.setVisibility(View.GONE);
|
||||||
|
wikidataButtonText.setVisibility(View.GONE);
|
||||||
|
commonsButtonText.setVisibility(View.GONE);
|
||||||
|
directionsButtonText.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setupMapView(Bundle savedInstanceState) {
|
private void setupMapView(Bundle savedInstanceState) {
|
||||||
MapboxMapOptions options = new MapboxMapOptions()
|
MapboxMapOptions options = new MapboxMapOptions()
|
||||||
.styleUrl(Style.OUTDOORS)
|
.styleUrl(Style.OUTDOORS)
|
||||||
|
|
@ -86,21 +401,13 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
// 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) {
|
||||||
mapboxMap.setOnMarkerClickListener(marker -> {
|
NearbyMapFragment.this.mapboxMap = mapboxMap;
|
||||||
if (marker instanceof NearbyMarker) {
|
updateMapSignificantly();
|
||||||
NearbyMarker nearbyMarker = (NearbyMarker) marker;
|
}
|
||||||
Place place = nearbyMarker.getNearbyBaseMarker().getPlace();
|
|
||||||
NearbyInfoDialog.showYourself(getActivity(), place);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
addCurrentLocationMarker(mapboxMap);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
mapView.setStyleUrl("asset://mapstyle.json");
|
mapView.setStyleUrl("asset://mapstyle.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,23 +416,59 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
* circle which uses the accuracy * 2, to draw a circle
|
* circle which uses the accuracy * 2, to draw a circle
|
||||||
* which represents the user's position with an accuracy
|
* which represents the user's position with an accuracy
|
||||||
* of 95%.
|
* 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) {
|
private void addCurrentLocationMarker(MapboxMap mapboxMap) {
|
||||||
MarkerOptions currentLocationMarker = new MarkerOptions()
|
if (currentLocationMarker != null) {
|
||||||
|
currentLocationMarker.remove(); // Remove previous marker, we are not Hansel and Gretel
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon icon = IconFactory.getInstance(getContext()).fromResource(R.drawable.current_location_marker);
|
||||||
|
|
||||||
|
MarkerOptions currentLocationMarkerOptions = new MarkerOptions()
|
||||||
.position(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude()));
|
.position(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude()));
|
||||||
mapboxMap.addMarker(currentLocationMarker);
|
currentLocationMarkerOptions.setIcon(icon); // Set custom icon
|
||||||
|
|
||||||
|
currentLocationMarker = mapboxMap.addMarker(currentLocationMarkerOptions);
|
||||||
|
|
||||||
List<LatLng> circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
List<LatLng> circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(),
|
||||||
curLatLng.getAccuracy() * 2, 100);
|
curLatLng.getAccuracy() * 2, 100);
|
||||||
|
|
||||||
mapboxMap.addPolygon(
|
currentLocationPolygonOptions = new PolygonOptions()
|
||||||
new PolygonOptions()
|
.addAll(circle)
|
||||||
.addAll(circle)
|
.strokeColor(Color.parseColor("#55000000"))
|
||||||
.strokeColor(Color.parseColor("#55000000"))
|
.fillColor(Color.parseColor("#11000000"));
|
||||||
.fillColor(Color.parseColor("#11000000"))
|
mapboxMap.addPolygon(currentLocationPolygonOptions);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addNearbyMarkerstoMapBoxMap() {
|
||||||
|
|
||||||
|
mapboxMap.addMarkers(baseMarkerOptions);
|
||||||
|
mapboxMap.setOnInfoWindowCloseListener(marker -> {
|
||||||
|
if (marker == selected){
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mapboxMap.setOnMarkerClickListener(marker -> {
|
||||||
|
if (marker instanceof NearbyMarker) {
|
||||||
|
this.selected = marker;
|
||||||
|
NearbyMarker nearbyMarker = (NearbyMarker) marker;
|
||||||
|
Place place = nearbyMarker.getNearbyBaseMarker().getPlace();
|
||||||
|
passInfoToSheet(place);
|
||||||
|
bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a series of points that create a circle on the map.
|
* Creates a series of points that create a circle on the map.
|
||||||
* Takes the center latitude, center longitude of the circle,
|
* Takes the center latitude, center longitude of the circle,
|
||||||
|
|
@ -147,10 +490,229 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
double nodeLatitude = centerLat + radiusLat * Math.sin(theta);
|
double nodeLatitude = centerLat + radiusLat * Math.sin(theta);
|
||||||
circle.add(new LatLng(nodeLatitude, nodeLongitude));
|
circle.add(new LatLng(nodeLatitude, nodeLongitude));
|
||||||
}
|
}
|
||||||
|
|
||||||
return circle;
|
return circle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void prepareViewsForSheetPosition(int bottomSheetState) {
|
||||||
|
|
||||||
|
switch (bottomSheetState) {
|
||||||
|
case (BottomSheetBehavior.STATE_COLLAPSED):
|
||||||
|
closeFabs(isFabOpen);
|
||||||
|
if (!fabPlus.isShown()) showFAB();
|
||||||
|
this.getView().requestFocus();
|
||||||
|
break;
|
||||||
|
case (BottomSheetBehavior.STATE_EXPANDED):
|
||||||
|
this.getView().requestFocus();
|
||||||
|
break;
|
||||||
|
case (BottomSheetBehavior.STATE_HIDDEN):
|
||||||
|
mapView.getMapAsync(MapboxMap::deselectMarkers);
|
||||||
|
transparentView.setClickable(false);
|
||||||
|
transparentView.setAlpha(0);
|
||||||
|
closeFabs(isFabOpen);
|
||||||
|
hideFAB();
|
||||||
|
this.getView().requestFocus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideFAB() {
|
||||||
|
|
||||||
|
removeAnchorFromFABs(fabPlus);
|
||||||
|
fabPlus.hide();
|
||||||
|
|
||||||
|
removeAnchorFromFABs(fabCamera);
|
||||||
|
fabCamera.hide();
|
||||||
|
|
||||||
|
removeAnchorFromFABs(fabGallery);
|
||||||
|
fabGallery.hide();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are not able to hide FABs without removing anchors, this method removes anchors
|
||||||
|
* */
|
||||||
|
private void removeAnchorFromFABs(FloatingActionButton floatingActionButton) {
|
||||||
|
//get rid of anchors
|
||||||
|
//Somehow this was the only way https://stackoverflow.com/questions/32732932
|
||||||
|
// /floatingactionbutton-visible-for-sometime-even-if-visibility-is-set-to-gone
|
||||||
|
CoordinatorLayout.LayoutParams param = (CoordinatorLayout.LayoutParams) floatingActionButton
|
||||||
|
.getLayoutParams();
|
||||||
|
param.setAnchorId(View.NO_ID);
|
||||||
|
// If we don't set them to zero, then they become visible for a moment on upper left side
|
||||||
|
param.width = 0;
|
||||||
|
param.height = 0;
|
||||||
|
floatingActionButton.setLayoutParams(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showFAB() {
|
||||||
|
|
||||||
|
addAnchorToBigFABs(fabPlus, getActivity().findViewById(R.id.bottom_sheet_details).getId());
|
||||||
|
fabPlus.show();
|
||||||
|
|
||||||
|
addAnchorToSmallFABs(fabGallery, getActivity().findViewById(R.id.empty_view).getId());
|
||||||
|
|
||||||
|
addAnchorToSmallFABs(fabCamera, getActivity().findViewById(R.id.empty_view1).getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add amnchors back before making them visible again.
|
||||||
|
* */
|
||||||
|
private void addAnchorToBigFABs(FloatingActionButton floatingActionButton, int anchorID) {
|
||||||
|
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams
|
||||||
|
(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
params.setAnchorId(anchorID);
|
||||||
|
params.anchorGravity = Gravity.TOP|Gravity.RIGHT|Gravity.END;
|
||||||
|
floatingActionButton.setLayoutParams(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add amnchors back before making them visible again. Big and small fabs have different anchor
|
||||||
|
* gravities, therefore the are two methods.
|
||||||
|
* */
|
||||||
|
private void addAnchorToSmallFABs(FloatingActionButton floatingActionButton, int anchorID) {
|
||||||
|
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams
|
||||||
|
(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
params.setAnchorId(anchorID);
|
||||||
|
params.anchorGravity = Gravity.CENTER_HORIZONTAL;
|
||||||
|
floatingActionButton.setLayoutParams(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void passInfoToSheet(Place place) {
|
||||||
|
this.place = place;
|
||||||
|
wikipediaButton.setEnabled(place.hasWikipediaLink());
|
||||||
|
wikipediaButton.setOnClickListener(view -> openWebView(place.siteLinks.getWikipediaLink()));
|
||||||
|
|
||||||
|
wikidataButton.setEnabled(place.hasWikidataLink());
|
||||||
|
wikidataButton.setOnClickListener(view -> openWebView(place.siteLinks.getWikidataLink()));
|
||||||
|
|
||||||
|
directionsButton.setOnClickListener(view -> {
|
||||||
|
//Open map app at given position
|
||||||
|
Intent mapIntent = new Intent(Intent.ACTION_VIEW, place.location.getGmmIntentUri());
|
||||||
|
if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
|
||||||
|
startActivity(mapIntent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
commonsButton.setEnabled(place.hasCommonsLink());
|
||||||
|
commonsButton.setOnClickListener(view -> openWebView(place.siteLinks.getCommonsLink()));
|
||||||
|
|
||||||
|
icon.setImageResource(place.getLabel().getIcon());
|
||||||
|
|
||||||
|
title.setText(place.name);
|
||||||
|
distance.setText(place.distance);
|
||||||
|
description.setText(place.getLongDescription());
|
||||||
|
title.setText(place.name.toString());
|
||||||
|
distance.setText(place.distance.toString());
|
||||||
|
|
||||||
|
fabCamera.setOnClickListener(view -> {
|
||||||
|
if (fabCamera.isShown()) {
|
||||||
|
Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
||||||
|
controller = new ContributionController(this);
|
||||||
|
|
||||||
|
DirectUpload directUpload = new DirectUpload(this, controller);
|
||||||
|
storeSharedPrefs();
|
||||||
|
directUpload.initiateCameraUpload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fabGallery.setOnClickListener(view -> {
|
||||||
|
if (fabGallery.isShown()) {
|
||||||
|
Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
||||||
|
controller = new ContributionController(this);
|
||||||
|
|
||||||
|
DirectUpload directUpload = new DirectUpload(this, controller);
|
||||||
|
storeSharedPrefs();
|
||||||
|
directUpload.initiateGalleryUpload();
|
||||||
|
|
||||||
|
//TODO: App crashes after image upload completes
|
||||||
|
//TODO: Handle onRequestPermissionsResult
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeSharedPrefs() {
|
||||||
|
SharedPreferences.Editor editor = directPrefs.edit();
|
||||||
|
editor.putString("Title", place.getName());
|
||||||
|
editor.putString("Desc", place.getLongDescription());
|
||||||
|
editor.putString("Category", place.getCategory());
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
Timber.d("onRequestPermissionsResult: req code = " + " perm = " + permissions + " grant =" + grantResults);
|
||||||
|
|
||||||
|
switch (requestCode) {
|
||||||
|
// 1 = "Read external storage" allowed when gallery selected
|
||||||
|
case 1: {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) {
|
||||||
|
Timber.d("Call controller.startGalleryPick()");
|
||||||
|
controller.startGalleryPick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 3 = "Write external storage" allowed when camera selected
|
||||||
|
case 3: {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
Timber.d("Call controller.startCameraCapture()");
|
||||||
|
controller.startCameraCapture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
requestCode, resultCode, data);
|
||||||
|
controller.handleImagePicked(requestCode, data, true);
|
||||||
|
} else {
|
||||||
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openWebView(Uri link) {
|
||||||
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, link);
|
||||||
|
startActivity(browserIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animateFAB(boolean isFabOpen) {
|
||||||
|
if (fabPlus.isShown()){
|
||||||
|
if (isFabOpen) {
|
||||||
|
fabPlus.startAnimation(rotate_backward);
|
||||||
|
fabCamera.startAnimation(fab_close);
|
||||||
|
fabGallery.startAnimation(fab_close);
|
||||||
|
fabCamera.hide();
|
||||||
|
fabGallery.hide();
|
||||||
|
} else {
|
||||||
|
fabPlus.startAnimation(rotate_forward);
|
||||||
|
fabCamera.startAnimation(fab_open);
|
||||||
|
fabGallery.startAnimation(fab_open);
|
||||||
|
fabCamera.show();
|
||||||
|
fabGallery.show();
|
||||||
|
}
|
||||||
|
this.isFabOpen=!isFabOpen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeFabs(boolean isFabOpen){
|
||||||
|
if (isFabOpen) {
|
||||||
|
fabPlus.startAnimation(rotate_backward);
|
||||||
|
fabCamera.startAnimation(fab_close);
|
||||||
|
fabGallery.startAnimation(fab_close);
|
||||||
|
fabCamera.hide();
|
||||||
|
fabGallery.hide();
|
||||||
|
this.isFabOpen=!isFabOpen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
if (mapView != null) {
|
if (mapView != null) {
|
||||||
|
|
@ -169,10 +731,14 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
|
|
||||||
@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
|
||||||
|
|
@ -190,4 +756,19 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.StrictMode;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -9,6 +8,7 @@ import java.io.InputStreamReader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
@ -30,7 +30,6 @@ public class NearbyPlaces {
|
||||||
private static final Uri WIKIDATA_QUERY_UI_URL = Uri.parse("https://query.wikidata.org/");
|
private static final Uri WIKIDATA_QUERY_UI_URL = Uri.parse("https://query.wikidata.org/");
|
||||||
private final String wikidataQuery;
|
private final String wikidataQuery;
|
||||||
private double radius = INITIAL_RADIUS;
|
private double radius = INITIAL_RADIUS;
|
||||||
private List<Place> places;
|
|
||||||
|
|
||||||
public NearbyPlaces() {
|
public NearbyPlaces() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -102,13 +101,17 @@ public class NearbyPlaces {
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] fields = line.split("\t");
|
String[] fields = line.split("\t");
|
||||||
|
Timber.v("Fields: " + Arrays.toString(fields));
|
||||||
String point = fields[0];
|
String point = fields[0];
|
||||||
|
String wikiDataLink = Utils.stripLocalizedString(fields[1]);
|
||||||
String name = Utils.stripLocalizedString(fields[2]);
|
String name = Utils.stripLocalizedString(fields[2]);
|
||||||
String type = Utils.stripLocalizedString(fields[4]);
|
String type = Utils.stripLocalizedString(fields[4]);
|
||||||
|
String icon = fields[5];
|
||||||
String wikipediaSitelink = Utils.stripLocalizedString(fields[7]);
|
String wikipediaSitelink = Utils.stripLocalizedString(fields[7]);
|
||||||
String commonsSitelink = Utils.stripLocalizedString(fields[8]);
|
String commonsSitelink = Utils.stripLocalizedString(fields[8]);
|
||||||
String wikiDataLink = Utils.stripLocalizedString(fields[1]);
|
String category = Utils.stripLocalizedString(fields[9]);
|
||||||
String icon = fields[5];
|
|
||||||
|
Timber.v("Name: " + name + ", type: " + type + ", category: " + category + ", wikipediaSitelink: " + wikipediaSitelink + ", commonsSitelink: " + commonsSitelink);
|
||||||
|
|
||||||
double latitude;
|
double latitude;
|
||||||
double longitude;
|
double longitude;
|
||||||
|
|
@ -130,6 +133,7 @@ public class NearbyPlaces {
|
||||||
type, // details
|
type, // details
|
||||||
Uri.parse(icon),
|
Uri.parse(icon),
|
||||||
new LatLng(latitude, longitude, 0),
|
new LatLng(latitude, longitude, 0),
|
||||||
|
category,
|
||||||
new Sitelinks.Builder()
|
new Sitelinks.Builder()
|
||||||
.setWikipediaLink(wikipediaSitelink)
|
.setWikipediaLink(wikipediaSitelink)
|
||||||
.setCommonsLink(commonsSitelink)
|
.setCommonsLink(commonsSitelink)
|
||||||
|
|
@ -141,66 +145,4 @@ public class NearbyPlaces {
|
||||||
|
|
||||||
return places;
|
return places;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Place> getFromWikiNeedsPictures() {
|
|
||||||
if (places != null) {
|
|
||||||
return places;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
places = new ArrayList<>();
|
|
||||||
StrictMode.ThreadPolicy policy
|
|
||||||
= new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
|
||||||
StrictMode.setThreadPolicy(policy);
|
|
||||||
|
|
||||||
URL file = new URL("https://tools.wmflabs.org/wiki-needs-pictures/data/data.csv");
|
|
||||||
|
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(file.openStream()));
|
|
||||||
|
|
||||||
boolean firstLine = true;
|
|
||||||
String line;
|
|
||||||
Timber.d("Reading from CSV file...");
|
|
||||||
|
|
||||||
while ((line = in.readLine()) != null) {
|
|
||||||
|
|
||||||
// Skip CSV header.
|
|
||||||
if (firstLine) {
|
|
||||||
firstLine = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] fields = line.split(",");
|
|
||||||
String name = Utils.stripLocalizedString(fields[0]);
|
|
||||||
|
|
||||||
double latitude;
|
|
||||||
double longitude;
|
|
||||||
try {
|
|
||||||
latitude = Double.parseDouble(fields[1]);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
latitude = 0;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
longitude = Double.parseDouble(fields[2]);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
longitude = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
String type = fields[3];
|
|
||||||
|
|
||||||
places.add(new Place(
|
|
||||||
name,
|
|
||||||
Place.Label.fromText(type), // list
|
|
||||||
type, // details
|
|
||||||
null,
|
|
||||||
new LatLng(latitude, longitude, 0),
|
|
||||||
new Sitelinks.Builder().build()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.d(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return places;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ public class Place {
|
||||||
private final String longDescription;
|
private final String longDescription;
|
||||||
private final Uri secondaryImageUrl;
|
private final Uri secondaryImageUrl;
|
||||||
public final LatLng location;
|
public final LatLng location;
|
||||||
|
private final String category;
|
||||||
|
|
||||||
public Bitmap image;
|
public Bitmap image;
|
||||||
public Bitmap secondaryImage;
|
public Bitmap secondaryImage;
|
||||||
|
|
@ -25,27 +26,42 @@ public class Place {
|
||||||
|
|
||||||
|
|
||||||
public Place(String name, Label label, String longDescription,
|
public Place(String name, Label label, String longDescription,
|
||||||
Uri secondaryImageUrl, LatLng location, Sitelinks siteLinks) {
|
Uri secondaryImageUrl, LatLng location, String category, Sitelinks siteLinks) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.longDescription = longDescription;
|
this.longDescription = longDescription;
|
||||||
this.secondaryImageUrl = secondaryImageUrl;
|
this.secondaryImageUrl = secondaryImageUrl;
|
||||||
this.location = location;
|
this.location = location;
|
||||||
|
this.category = category;
|
||||||
this.siteLinks = siteLinks;
|
this.siteLinks = siteLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
|
||||||
public Label getLabel() {
|
public Label getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLongDescription() {
|
public String getLongDescription() { return longDescription; }
|
||||||
return longDescription;
|
|
||||||
}
|
public String getCategory() {return category; }
|
||||||
|
|
||||||
public void setDistance(String distance) {
|
public void setDistance(String distance) {
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasWikipediaLink() {
|
||||||
|
return !(siteLinks == null || Uri.EMPTY.equals(siteLinks.getWikipediaLink()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasWikidataLink() {
|
||||||
|
return !(siteLinks == null || Uri.EMPTY.equals(siteLinks.getWikidataLink()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCommonsLink() {
|
||||||
|
return !(siteLinks == null || Uri.EMPTY.equals(siteLinks.getCommonsLink()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o instanceof Place) {
|
if (o instanceof Place) {
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,79 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.transition.TransitionManager;
|
||||||
|
import android.support.v7.widget.PopupMenu;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.pedrogomez.renderers.Renderer;
|
import com.pedrogomez.renderers.Renderer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
|
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class PlaceRenderer extends Renderer<Place> {
|
||||||
|
|
||||||
class PlaceRenderer extends Renderer<Place> {
|
|
||||||
@BindView(R.id.tvName) TextView tvName;
|
@BindView(R.id.tvName) TextView tvName;
|
||||||
@BindView(R.id.tvDesc) TextView tvDesc;
|
@BindView(R.id.tvDesc) TextView tvDesc;
|
||||||
@BindView(R.id.distance) TextView distance;
|
@BindView(R.id.distance) TextView distance;
|
||||||
@BindView(R.id.icon) ImageView icon;
|
@BindView(R.id.icon) ImageView icon;
|
||||||
private final PlaceClickedListener listener;
|
@BindView(R.id.buttonLayout) LinearLayout buttonLayout;
|
||||||
|
@BindView(R.id.cameraButton) LinearLayout cameraButton;
|
||||||
|
|
||||||
PlaceRenderer(@NonNull PlaceClickedListener listener) {
|
@BindView(R.id.galleryButton) LinearLayout galleryButton;
|
||||||
this.listener = listener;
|
@BindView(R.id.directionsButton) LinearLayout directionsButton;
|
||||||
|
@BindView(R.id.iconOverflow) LinearLayout iconOverflow;
|
||||||
|
@BindView(R.id.cameraButtonText) TextView cameraButtonText;
|
||||||
|
@BindView(R.id.galleryButtonText) TextView galleryButtonText;
|
||||||
|
|
||||||
|
@BindView(R.id.directionsButtonText) TextView directionsButtonText;
|
||||||
|
@BindView(R.id.iconOverflowText) TextView iconOverflowText;
|
||||||
|
|
||||||
|
private View view;
|
||||||
|
private static ArrayList<LinearLayout> openedItems;
|
||||||
|
private Place place;
|
||||||
|
|
||||||
|
private Fragment fragment;
|
||||||
|
private ContributionController controller;
|
||||||
|
|
||||||
|
|
||||||
|
@Inject @Named("prefs") SharedPreferences prefs;
|
||||||
|
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
|
||||||
|
|
||||||
|
public PlaceRenderer(){
|
||||||
|
openedItems = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceRenderer(Fragment fragment, ContributionController controller) {
|
||||||
|
this.fragment = fragment;
|
||||||
|
this.controller = controller;
|
||||||
|
openedItems = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View inflate(LayoutInflater layoutInflater, ViewGroup viewGroup) {
|
protected View inflate(LayoutInflater layoutInflater, ViewGroup viewGroup) {
|
||||||
return layoutInflater.inflate(R.layout.item_place, viewGroup, false);
|
view = layoutInflater.inflate(R.layout.item_place, viewGroup, false);
|
||||||
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -36,15 +83,67 @@ class PlaceRenderer extends Renderer<Place> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void hookListeners(View view) {
|
protected void hookListeners(View view) {
|
||||||
view.setOnClickListener(v -> listener.placeClicked(getContent()));
|
|
||||||
|
final View.OnClickListener listener = view12 -> {
|
||||||
|
Log.d("Renderer", "clicked");
|
||||||
|
TransitionManager.beginDelayedTransition(buttonLayout);
|
||||||
|
|
||||||
|
if(buttonLayout.isShown()){
|
||||||
|
closeLayout(buttonLayout);
|
||||||
|
}else {
|
||||||
|
openLayout(buttonLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
view.setOnClickListener(listener);
|
||||||
|
view.requestFocus();
|
||||||
|
view.setOnFocusChangeListener((view1, hasFocus) -> {
|
||||||
|
if (!hasFocus && buttonLayout.isShown()) {
|
||||||
|
closeLayout(buttonLayout);
|
||||||
|
} else if (hasFocus && !buttonLayout.isShown()) {
|
||||||
|
listener.onClick(view1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cameraButton.setOnClickListener(view2 -> {
|
||||||
|
Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
||||||
|
DirectUpload directUpload = new DirectUpload(fragment, controller);
|
||||||
|
storeSharedPrefs();
|
||||||
|
directUpload.initiateCameraUpload();
|
||||||
|
});
|
||||||
|
|
||||||
|
galleryButton.setOnClickListener(view3 -> {
|
||||||
|
Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
|
||||||
|
DirectUpload directUpload = new DirectUpload(fragment, controller);
|
||||||
|
storeSharedPrefs();
|
||||||
|
directUpload.initiateGalleryUpload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeSharedPrefs() {
|
||||||
|
SharedPreferences.Editor editor = directPrefs.edit();
|
||||||
|
Timber.d("directPrefs stored");
|
||||||
|
editor.putString("Title", place.getName());
|
||||||
|
editor.putString("Desc", place.getLongDescription());
|
||||||
|
editor.putString("Category", place.getCategory());
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeLayout(LinearLayout buttonLayout){
|
||||||
|
buttonLayout.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openLayout(LinearLayout buttonLayout){
|
||||||
|
buttonLayout.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render() {
|
public void render() {
|
||||||
Place place = getContent();
|
ApplicationlessInjection.getInstance(getContext().getApplicationContext())
|
||||||
|
.getCommonsApplicationComponent().inject(this);
|
||||||
|
place = getContent();
|
||||||
tvName.setText(place.name);
|
tvName.setText(place.name);
|
||||||
String descriptionText = place.getLongDescription();
|
String descriptionText = place.getLongDescription();
|
||||||
tvDesc.setVisibility(View.VISIBLE);
|
|
||||||
if (descriptionText.equals("?")) {
|
if (descriptionText.equals("?")) {
|
||||||
descriptionText = getContext().getString(R.string.no_description_found);
|
descriptionText = getContext().getString(R.string.no_description_found);
|
||||||
tvDesc.setVisibility(View.INVISIBLE);
|
tvDesc.setVisibility(View.INVISIBLE);
|
||||||
|
|
@ -52,9 +151,61 @@ class PlaceRenderer extends Renderer<Place> {
|
||||||
tvDesc.setText(descriptionText);
|
tvDesc.setText(descriptionText);
|
||||||
distance.setText(place.distance);
|
distance.setText(place.distance);
|
||||||
icon.setImageResource(place.getLabel().getIcon());
|
icon.setImageResource(place.getLabel().getIcon());
|
||||||
|
|
||||||
|
directionsButton.setOnClickListener(view -> {
|
||||||
|
//Open map app at given position
|
||||||
|
Intent mapIntent = new Intent(Intent.ACTION_VIEW, place.location.getGmmIntentUri());
|
||||||
|
if (mapIntent.resolveActivity(view.getContext().getPackageManager()) != null) {
|
||||||
|
view.getContext().startActivity(mapIntent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
iconOverflow.setVisibility(showMenu() ? View.VISIBLE : View.GONE);
|
||||||
|
iconOverflow.setOnClickListener(v -> popupMenuListener());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PlaceClickedListener {
|
private void popupMenuListener() {
|
||||||
void placeClicked(Place place);
|
PopupMenu popupMenu = new PopupMenu(view.getContext(), iconOverflow);
|
||||||
|
popupMenu.inflate(R.menu.nearby_info_dialog_options);
|
||||||
|
|
||||||
|
MenuItem commonsArticle = popupMenu.getMenu()
|
||||||
|
.findItem(R.id.nearby_info_menu_commons_article);
|
||||||
|
MenuItem wikiDataArticle = popupMenu.getMenu()
|
||||||
|
.findItem(R.id.nearby_info_menu_wikidata_article);
|
||||||
|
MenuItem wikipediaArticle = popupMenu.getMenu()
|
||||||
|
.findItem(R.id.nearby_info_menu_wikipedia_article);
|
||||||
|
|
||||||
|
commonsArticle.setEnabled(place.hasCommonsLink());
|
||||||
|
wikiDataArticle.setEnabled(place.hasWikidataLink());
|
||||||
|
wikipediaArticle.setEnabled(place.hasWikipediaLink());
|
||||||
|
|
||||||
|
popupMenu.setOnMenuItemClickListener(item -> {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.nearby_info_menu_commons_article:
|
||||||
|
openWebView(place.siteLinks.getCommonsLink());
|
||||||
|
return true;
|
||||||
|
case R.id.nearby_info_menu_wikidata_article:
|
||||||
|
openWebView(place.siteLinks.getWikidataLink());
|
||||||
|
return true;
|
||||||
|
case R.id.nearby_info_menu_wikipedia_article:
|
||||||
|
openWebView(place.siteLinks.getWikipediaLink());
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
popupMenu.show();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void openWebView(Uri link) {
|
||||||
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, link);
|
||||||
|
view.getContext().startActivity(browserIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean showMenu() {
|
||||||
|
return place.hasCommonsLink() || place.hasWikidataLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -58,7 +58,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.mwapi.EventLog;
|
|
||||||
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;
|
||||||
|
|
@ -116,7 +116,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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when user taps the submit button.
|
* Called when user taps the submit button.
|
||||||
*/
|
*/
|
||||||
|
|
@ -214,6 +217,10 @@ public class ShareActivity
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isNearbyUpload() {
|
||||||
|
return isNearbyUpload;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
@ -240,6 +247,10 @@ public class ShareActivity
|
||||||
} else {
|
} else {
|
||||||
source = Contribution.SOURCE_EXTERNAL;
|
source = Contribution.SOURCE_EXTERNAL;
|
||||||
}
|
}
|
||||||
|
if (intent.hasExtra("isDirectUpload")) {
|
||||||
|
Timber.d("This was initiated by a direct upload from Nearby");
|
||||||
|
isNearbyUpload = true;
|
||||||
|
}
|
||||||
mimeType = intent.getType();
|
mimeType = intent.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package fr.free.nrw.commons.upload;
|
package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
@ -58,6 +60,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
|
||||||
@BindView(R.id.licenseSpinner) Spinner licenseSpinner;
|
@BindView(R.id.licenseSpinner) Spinner licenseSpinner;
|
||||||
|
|
||||||
@Inject @Named("default_preferences") SharedPreferences prefs;
|
@Inject @Named("default_preferences") SharedPreferences prefs;
|
||||||
|
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
|
||||||
|
|
||||||
private String license;
|
private String license;
|
||||||
private OnUploadActionInitiated uploadActionInitiatedHandler;
|
private OnUploadActionInitiated uploadActionInitiatedHandler;
|
||||||
|
|
@ -90,7 +93,6 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
uploadActionInitiatedHandler.uploadActionInitiated(title, desc);
|
uploadActionInitiatedHandler.uploadActionInitiated(title, desc);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +120,18 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
license = prefs.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
license = prefs.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
||||||
|
|
||||||
|
// If this is a direct upload from Nearby, autofill title and desc fields with the Place's values
|
||||||
|
boolean isNearbyUpload = ((ShareActivity) getActivity()).isNearbyUpload();
|
||||||
|
|
||||||
|
if (isNearbyUpload) {
|
||||||
|
String imageTitle = directPrefs.getString("Title", "");
|
||||||
|
String imageDesc = directPrefs.getString("Desc", "");
|
||||||
|
String imageCats = directPrefs.getString("Category", "");
|
||||||
|
Timber.d("Image title: " + imageTitle + ", image desc: " + imageDesc + ", image categories: " + imageCats);
|
||||||
|
titleEdit.setText(imageTitle);
|
||||||
|
descEdit.setText(imageDesc);
|
||||||
|
}
|
||||||
|
|
||||||
// check if this is the first time we have uploaded
|
// check if this is the first time we have uploaded
|
||||||
if (prefs.getString("Title", "").trim().length() == 0
|
if (prefs.getString("Title", "").trim().length() == 0
|
||||||
&& prefs.getString("Desc", "").trim().length() == 0) {
|
&& prefs.getString("Desc", "").trim().length() == 0) {
|
||||||
|
|
@ -278,6 +292,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StringFormatInvalid")
|
||||||
private void setLicenseSummary(String license) {
|
private void setLicenseSummary(String license) {
|
||||||
licenseSummaryView.setText(getString(R.string.share_license_summary, getString(Utils.licenseNameFor(license))));
|
licenseSummaryView.setText(getString(R.string.share_license_summary, getString(Utils.licenseNameFor(license))));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ public class ImageUtils {
|
||||||
|
|
||||||
while ((checkImageRightPosition <= loadImageWidth) && (checkImageLeftPosition < checkImageRightPosition)) {
|
while ((checkImageRightPosition <= loadImageWidth) && (checkImageLeftPosition < checkImageRightPosition)) {
|
||||||
while ((checkImageBottomPosition <= loadImageHeight) && (checkImageTopPosition < checkImageBottomPosition)) {
|
while ((checkImageBottomPosition <= loadImageHeight) && (checkImageTopPosition < checkImageBottomPosition)) {
|
||||||
Timber.d("left: " + checkImageLeftPosition + " right: " + checkImageRightPosition + " top: " + checkImageTopPosition + " bottom: " + checkImageBottomPosition);
|
Timber.v("left: " + checkImageLeftPosition + " right: " + checkImageRightPosition + " top: " + checkImageTopPosition + " bottom: " + checkImageBottomPosition);
|
||||||
|
|
||||||
Rect rect = new Rect(checkImageLeftPosition,checkImageTopPosition,checkImageRightPosition,checkImageBottomPosition);
|
Rect rect = new Rect(checkImageLeftPosition,checkImageTopPosition,checkImageRightPosition,checkImageBottomPosition);
|
||||||
totalDividedRectangles++;
|
totalDividedRectangles++;
|
||||||
|
|
|
||||||
17
app/src/main/res/anim/fab_close.xml
Normal file
17
app/src/main/res/anim/fab_close.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fillAfter="true">
|
||||||
|
<scale
|
||||||
|
android:duration="300"
|
||||||
|
android:fromXScale="1"
|
||||||
|
android:fromYScale="1"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"
|
||||||
|
android:toXScale="0.0"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:toYScale="0.0" />
|
||||||
|
<alpha android:fromAlpha="1.0"
|
||||||
|
android:toAlpha="0.0"
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:duration="300"/>
|
||||||
|
</set>
|
||||||
18
app/src/main/res/anim/fab_open.xml
Normal file
18
app/src/main/res/anim/fab_open.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fillAfter="true">
|
||||||
|
<scale
|
||||||
|
android:duration="300"
|
||||||
|
android:fromXScale="0.0"
|
||||||
|
android:fromYScale="0.0"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"
|
||||||
|
android:toXScale="1"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:toYScale="1" />
|
||||||
|
<alpha
|
||||||
|
android:fromAlpha="0.0"
|
||||||
|
android:toAlpha="1.0"
|
||||||
|
android:interpolator="@android:anim/accelerate_interpolator"
|
||||||
|
android:duration="300"/>
|
||||||
|
</set>
|
||||||
10
app/src/main/res/anim/rotate_backward.xml
Normal file
10
app/src/main/res/anim/rotate_backward.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fillAfter="true" >
|
||||||
|
<rotate android:fromDegrees="45"
|
||||||
|
android:toDegrees="0"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:duration="300"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"/>
|
||||||
|
</set>
|
||||||
10
app/src/main/res/anim/rotate_forward.xml
Normal file
10
app/src/main/res/anim/rotate_forward.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fillAfter="true" >
|
||||||
|
<rotate android:fromDegrees="0"
|
||||||
|
android:toDegrees="45"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:duration="300"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"/>
|
||||||
|
</set>
|
||||||
13
app/src/main/res/anim/slide_down.xml
Normal file
13
app/src/main/res/anim/slide_down.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fillAfter="true">
|
||||||
|
|
||||||
|
<scale
|
||||||
|
android:duration="300"
|
||||||
|
android:fromXScale="1.0"
|
||||||
|
android:fromYScale="0.0"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"
|
||||||
|
android:toXScale="1.0"
|
||||||
|
android:toYScale="1.0" />
|
||||||
|
|
||||||
|
</set>
|
||||||
13
app/src/main/res/anim/slide_up.xml
Normal file
13
app/src/main/res/anim/slide_up.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fillAfter="true" >
|
||||||
|
|
||||||
|
<scale
|
||||||
|
android:duration="300"
|
||||||
|
android:fromXScale="1.0"
|
||||||
|
android:fromYScale="1.0"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"
|
||||||
|
android:toXScale="1.0"
|
||||||
|
android:toYScale="0.0" />
|
||||||
|
|
||||||
|
</set>
|
||||||
7
app/src/main/res/color/button_color_selector.xml
Normal file
7
app/src/main/res/color/button_color_selector.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_enabled="false"
|
||||||
|
android:color="@color/opak_middle_grey" />
|
||||||
|
<item
|
||||||
|
android:color="@color/status_bar_blue" />
|
||||||
|
</selector>
|
||||||
8
app/src/main/res/color/text_color_selector.xml
Normal file
8
app/src/main/res/color/text_color_selector.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_enabled="false"
|
||||||
|
android:color="?attr/textDisabled" />
|
||||||
|
<item
|
||||||
|
android:color="?attr/textEnabled" />
|
||||||
|
</selector>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@color/pressed_button_light" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@color/focused_button_light"
|
||||||
|
/>
|
||||||
|
<item android:drawable="@android:color/transparent" />
|
||||||
|
</selector>
|
||||||
11
app/src/main/res/drawable-xhdpi/ic_directions_black_48dp.xml
Normal file
11
app/src/main/res/drawable-xhdpi/ic_directions_black_48dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:tint="@color/status_bar_blue"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M21.71,11.29l-9,-9c-0.39,-0.39 -1.02,-0.39 -1.41,0l-9,9c-0.39,0.39 -0.39,1.02 0,1.41l9,9c0.39,0.39 1.02,0.39 1.41,0l9,-9c0.39,-0.38 0.39,-1.01 0,-1.41zM14,14.5V12h-4v3H8v-4c0,-0.55 0.45,-1 1,-1h5V7.5l3.5,3.5 -3.5,3.5z"/>
|
||||||
|
</vector>
|
||||||
11
app/src/main/res/drawable-xhdpi/ic_wikidata_logo_48dp.xml
Normal file
11
app/src/main/res/drawable-xhdpi/ic_wikidata_logo_48dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector android:height="48dp"
|
||||||
|
android:viewportHeight="93.46232"
|
||||||
|
android:viewportWidth="102.1415"
|
||||||
|
android:width="48dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:tint="@color/status_bar_blue"
|
||||||
|
>
|
||||||
|
<path android:fillColor="#990000" android:pathData="m0.83,77.62 l3.71,0 0,-61.79 -3.71,0 0,61.79zM8.24,77.62 L19.36,77.62 19.36,15.84 8.24,15.84 8.24,77.62zM23.07,15.84 L23.07,77.62 34.19,77.62 34.19,15.84 23.07,15.84z"/>
|
||||||
|
<path android:fillColor="#339966" android:pathData="m89.8,77.62 l3.7,0 0,-61.79 -3.7,0 0,61.79zM97.21,15.84 L97.21,77.62 100.92,77.62 100.92,15.84 97.21,15.84zM37.9,77.62 L41.6,77.62 41.6,15.84 37.9,15.84 37.9,77.62zM45.31,15.84 L45.31,77.62 49.02,77.62 49.02,15.84 45.32,15.84z"/>
|
||||||
|
<path android:fillColor="#006699" android:pathData="m52.73,77.62 l11.12,0 0,-61.79 -11.12,0 0,61.79zM67.56,77.62 L71.26,77.62 71.26,15.84 67.56,15.84 67.56,77.62zM74.97,15.84 L74.97,77.62 86.09,77.62 86.09,15.84 74.98,15.84z"/>
|
||||||
|
</vector>
|
||||||
11
app/src/main/res/drawable-xhdpi/ic_wikipedia_logo_48dp.xml
Normal file
11
app/src/main/res/drawable-xhdpi/ic_wikipedia_logo_48dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector android:height="48dp"
|
||||||
|
android:viewportHeight="141.092"
|
||||||
|
android:viewportWidth="141.092"
|
||||||
|
android:width="48dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:tint="@color/status_bar_blue"
|
||||||
|
>
|
||||||
|
<path android:fillAlpha="1" android:fillColor="#000000"
|
||||||
|
android:pathData="M91.5,116.05 L73.43,73.49c-7.16,14.05 -15.09,28.64 -21.88,42.54 -0.04,0.07 -3.28,0.03 -3.28,-0.01C37.9,91.8 27.14,67.75 16.72,43.56 14.3,37.65 5.83,28.14 0.04,28.19 0.04,27.5 0.01,25.97 0,25.04L35.71,25.03l-0.02,3.11c-4.19,0.2 -11.44,2.87 -9.57,7.5 5.04,10.87 22.86,52.97 27.67,63.66 3.36,-6.58 12.75,-24.12 16.61,-31.53 -3.03,-6.22 -13.04,-29.43 -16.04,-35.27 -2.26,-3.81 -7.94,-4.28 -12.32,-4.34 0,-0.98 0.05,-1.73 0.03,-3.07l31.4,0.1 0,2.85c-4.25,0.12 -8.28,1.7 -6.45,5.76 4.22,8.77 6.69,15.01 10.57,23.11 1.24,-2.37 7.58,-15.39 10.61,-22.27 1.83,-4.57 -0.9,-6.28 -8.55,-6.49 0.1,-0.75 0.03,-2.26 0.1,-2.98 9.76,-0.04 24.5,-0.07 27.11,-0.11l0.01,2.97c-4.98,0.19 -10.14,2.85 -12.83,6.97l-13.06,27.08c1.43,3.59 13.99,31.47 15.31,34.56L123.29,34.34c-1.92,-5.05 -8.05,-6.17 -10.44,-6.23 0.02,-0.8 0.02,-2.03 0.03,-3.05l28.18,0.21 0.04,0.14 -0.05,2.68c-6.18,0.19 -10.01,3.49 -12.29,8.91 -5.62,12.68 -22.78,52.86 -34.24,79.05 -0.01,0.01 -3,-0 -3.01,-0.01z"
|
||||||
|
android:strokeAlpha="1" android:strokeColor="#00000000"/>
|
||||||
|
</vector>
|
||||||
BIN
app/src/main/res/drawable/current_location_marker.png
Normal file
BIN
app/src/main/res/drawable/current_location_marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 882 B |
9
app/src/main/res/drawable/ic_add_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_add_white_24dp.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||||
|
</vector>
|
||||||
10
app/src/main/res/drawable/ic_commons_icon_vector.xml
Normal file
10
app/src/main/res/drawable/ic_commons_icon_vector.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="342.03146"
|
||||||
|
android:viewportWidth="342.03104"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:tint="@color/button_color_selector">
|
||||||
|
<path android:fillColor="#000000" android:pathData="M146.6,340.1C113.2,333.3 84.6,314 66.1,286 34.6,238.1 39.8,173.2 78.5,132.3l6.9,-7.3 16.8,16.8 16.8,16.8 4.5,-4.4c2.5,-2.4 4.7,-4.2 4.9,-4 0.9,1 9,32 8.5,32.5 -0.5,0.5 -30.4,-7.2 -32.2,-8.2 -0.5,-0.3 1.1,-2.4 3.4,-4.8 4.2,-4.2 4.2,-4.3 2.4,-6.6 -1,-1.3 -3,-3.4 -4.5,-4.6l-2.7,-2.2 -4.7,6.2c-9,12 -15.3,27.5 -17.4,42.9 -1,7.1 -0.5,7.8 4.4,7.8 6.9,0 7.5,-0.6 7.5,-7.5l0,-6.3 15,8.6c8.3,4.7 15,8.9 15,9.2 -0,0.5 -26.5,15.8 -29.2,16.9 -0.4,0.2 -0.8,-2.6 -0.8,-6.3l0,-6.6 -5.9,0c-3.3,0 -6.1,0.3 -6.4,0.8 -0.9,1.6 1.6,15.2 4.4,23.8 3.4,10.3 9.3,21.2 14.9,27.6l3.8,4.4 4.3,-4.2 4.3,-4.2 -4.2,-4.3c-2.3,-2.4 -4.2,-4.6 -4.2,-4.9 0,-0.8 31.9,-9.2 32.6,-8.6 0.3,0.3 -1.4,7.9 -3.8,16.8l-4.4,16.3 -4.6,-4.2c-5.2,-4.8 -6.4,-4.7 -10.4,0.6l-2.7,3.6 4.3,3.7c10.6,9.1 30.3,17.4 44.4,18.6l7.6,0.6 0,-6.1 0,-6.1 -6.5,0c-3.6,0 -6.5,-0.3 -6.5,-0.7 0,-1 16.4,-29.3 17,-29.3 0.6,0 17,28.3 17,29.3 0,0.4 -2.9,0.7 -6.5,0.7l-6.5,0 0,6.1 0,6.1 7.6,-0.6c14.1,-1.2 33.8,-9.4 44.5,-18.6l4.4,-3.7 -2.2,-2.8c-1.2,-1.6 -3.1,-3.5 -4.2,-4.2 -1.8,-1.3 -2.4,-1 -6.6,2.9l-4.6,4.3 -3.7,-13.5c-5.1,-18.3 -5.4,-19.9 -3.9,-19.9 1.4,0 31.3,8 31.8,8.5 0.2,0.2 -1.6,2.4 -3.9,5l-4.3,4.6 4.2,4.2 4.2,4.2 3.8,-4.4c5.6,-6.4 11.5,-17.3 14.9,-27.6 2.8,-8.6 5.4,-22.1 4.4,-23.8 -0.2,-0.4 -3.1,-0.8 -6.4,-0.8l-5.9,0 0,6.6c0,3.6 -0.4,6.4 -0.8,6.3 -2.7,-1.1 -29.1,-16.4 -29.2,-16.9 -0,-0.3 6.7,-4.5 15,-9.2l15,-8.6 0,6.4 0,6.4 3.4,0.6c1.9,0.4 4.8,0.3 6.4,-0 2.8,-0.6 3,-0.9 2.5,-4.8 -1.8,-15.8 -8.7,-33.3 -17.8,-45.4l-4.7,-6.2 -2.7,2.2c-1.5,1.2 -3.5,3.3 -4.5,4.6 -1.8,2.3 -1.7,2.4 2.4,6.6 2.3,2.4 3.8,4.5 3.4,4.8 -1.8,1.1 -31.7,8.7 -32.2,8.2 -0.5,-0.5 7.6,-31.4 8.5,-32.5 0.2,-0.2 2.4,1.5 4.9,4l4.5,4.4 4.2,-4.2c3.5,-3.5 4,-4.4 2.9,-5.7 -2.1,-2.5 -9,-6.1 -22.1,-11.6 -17.1,-7.1 -26.4,-12.1 -33.6,-17.9 -10.7,-8.7 -19.3,-22.2 -24,-37.6 -1,-3.3 -1.9,-6.2 -2.1,-6.4 -0.1,-0.2 -5.2,1.4 -11.2,3.5 -6,2.1 -11.3,3.6 -11.6,3.2 -0.3,-0.3 1.9,-4.2 5,-8.5 9.2,-12.8 20.4,-38.4 28,-64.2l2.8,-9.3 3,4.8c16.2,26.1 40.8,71.5 39.3,73 -0.4,0.4 -2.2,-0.7 -3.9,-2.4 -3.9,-3.7 -8.1,-5.9 -13.1,-6.8 -3.7,-0.7 -3.8,-0.7 -3.1,2.2 2.4,9.9 9.8,20.2 17.8,24.9 2.2,1.3 11.7,5.7 21.1,9.7 20.6,8.9 28.7,14.1 39.7,25.7 16.7,17.5 26.7,36.9 31.9,61.4 3,14.3 3,35.1 -0.1,49.7 -10.6,50.7 -50.6,89.6 -101.1,98.5 -11.9,2.1 -34.9,1.8 -46.4,-0.5zM162.6,258.1c-26.3,-5.8 -40.9,-34.6 -29.6,-58.5 4.2,-9 10.8,-15.7 20,-20.3 7.3,-3.6 7.9,-3.7 18.1,-3.7 10.2,0 10.9,0.1 18.1,3.7 33,16.3 31.1,63.3 -3.1,76.8 -6.1,2.4 -17.3,3.4 -23.5,2z"/>
|
||||||
|
<path android:fillColor="#000000" android:pathData="M146.6,340.1C113.2,333.3 84.6,314 66.1,286 34.6,238.1 39.8,173.2 78.5,132.3l6.9,-7.3 16.8,16.8 16.8,16.8 4.5,-4.4c2.5,-2.4 4.7,-4.2 4.9,-4 0.9,1 9,32 8.5,32.5 -0.5,0.5 -30.4,-7.2 -32.2,-8.2 -0.5,-0.3 1.1,-2.4 3.4,-4.8 4.2,-4.2 4.2,-4.3 2.4,-6.6 -1,-1.3 -3,-3.4 -4.5,-4.6l-2.7,-2.2 -4.7,6.2c-9,12 -15.3,27.5 -17.4,42.9 -1,7.1 -0.5,7.8 4.4,7.8 6.9,0 7.5,-0.6 7.5,-7.5l0,-6.3 15,8.6c8.3,4.7 15,8.9 15,9.2 -0,0.5 -26.5,15.8 -29.2,16.9 -0.4,0.2 -0.8,-2.6 -0.8,-6.3l0,-6.6 -5.9,0c-3.3,0 -6.1,0.3 -6.4,0.8 -0.9,1.6 1.6,15.2 4.4,23.8 3.4,10.3 9.3,21.2 14.9,27.6l3.8,4.4 4.3,-4.2 4.3,-4.2 -4.2,-4.3c-2.3,-2.4 -4.2,-4.6 -4.2,-4.9 0,-0.8 31.9,-9.2 32.6,-8.6 0.3,0.3 -1.4,7.9 -3.8,16.8l-4.4,16.3 -4.6,-4.2c-5.2,-4.8 -6.4,-4.7 -10.4,0.6l-2.7,3.6 4.3,3.7c10.6,9.1 30.3,17.4 44.4,18.6l7.6,0.6 0,-6.1 0,-6.1 -6.5,0c-3.6,0 -6.5,-0.3 -6.5,-0.7 0,-1 16.4,-29.3 17,-29.3 0.6,0 17,28.3 17,29.3 0,0.4 -2.9,0.7 -6.5,0.7l-6.5,0 0,6.1 0,6.1 7.6,-0.6c14.1,-1.2 33.8,-9.4 44.5,-18.6l4.4,-3.7 -2.2,-2.8c-1.2,-1.6 -3.1,-3.5 -4.2,-4.2 -1.8,-1.3 -2.4,-1 -6.6,2.9l-4.6,4.3 -3.7,-13.5c-5.1,-18.3 -5.4,-19.9 -3.9,-19.9 1.4,0 31.3,8 31.8,8.5 0.2,0.2 -1.6,2.4 -3.9,5l-4.3,4.6 4.2,4.2 4.2,4.2 3.8,-4.4c5.6,-6.4 11.5,-17.3 14.9,-27.6 2.8,-8.6 5.4,-22.1 4.4,-23.8 -0.2,-0.4 -3.1,-0.8 -6.4,-0.8l-5.9,0 0,6.6c0,3.6 -0.4,6.4 -0.8,6.3 -2.7,-1.1 -29.1,-16.4 -29.2,-16.9 -0,-0.3 6.7,-4.5 15,-9.2l15,-8.6 0,6.4 0,6.4 3.4,0.6c1.9,0.4 4.8,0.3 6.4,-0 2.8,-0.6 3,-0.9 2.5,-4.8 -1.8,-15.8 -8.7,-33.3 -17.8,-45.4l-4.7,-6.2 -2.7,2.2c-1.5,1.2 -3.5,3.3 -4.5,4.6 -1.8,2.3 -1.7,2.4 2.4,6.6 2.3,2.4 3.8,4.5 3.4,4.8 -1.8,1.1 -31.7,8.7 -32.2,8.2 -0.5,-0.5 7.6,-31.4 8.5,-32.5 0.2,-0.2 2.4,1.5 4.9,4l4.5,4.4 4.2,-4.2c3.5,-3.5 4,-4.4 2.9,-5.7 -2.1,-2.5 -9,-6.1 -22.1,-11.6 -17.1,-7.1 -26.4,-12.1 -33.6,-17.9 -10.7,-8.7 -19.3,-22.2 -24,-37.6 -1,-3.3 -1.9,-6.2 -2.1,-6.4 -0.1,-0.2 -5.2,1.4 -11.2,3.5 -6,2.1 -11.3,3.6 -11.6,3.2 -0.3,-0.3 1.9,-4.2 5,-8.5 9.2,-12.8 20.4,-38.4 28,-64.2l2.8,-9.3 3,4.8c16.2,26.1 40.8,71.5 39.3,73 -0.4,0.4 -2.2,-0.7 -3.9,-2.4 -3.9,-3.7 -8.1,-5.9 -13.1,-6.8 -3.7,-0.7 -3.8,-0.7 -3.1,2.2 2.4,9.9 9.8,20.2 17.8,24.9 2.2,1.3 11.7,5.7 21.1,9.7 20.6,8.9 28.7,14.1 39.7,25.7 16.7,17.5 26.7,36.9 31.9,61.4 3,14.3 3,35.1 -0.1,49.7 -10.6,50.7 -50.6,89.6 -101.1,98.5 -11.9,2.1 -34.9,1.8 -46.4,-0.5zM162.6,258.1c-26.3,-5.8 -40.9,-34.6 -29.6,-58.5 4.2,-9 10.8,-15.7 20,-20.3 7.3,-3.6 7.9,-3.7 18.1,-3.7 10.2,0 10.9,0.1 18.1,3.7 33,16.3 31.1,63.3 -3.1,76.8 -6.1,2.4 -17.3,3.4 -23.5,2z"/>
|
||||||
|
</vector>
|
||||||
11
app/src/main/res/drawable/ic_directions_black_24dp.xml
Normal file
11
app/src/main/res/drawable/ic_directions_black_24dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:tint="@color/button_color_selector"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M21.71,11.29l-9,-9c-0.39,-0.39 -1.02,-0.39 -1.41,0l-9,9c-0.39,0.39 -0.39,1.02 0,1.41l9,9c0.39,0.39 1.02,0.39 1.41,0l9,-9c0.39,-0.38 0.39,-1.01 0,-1.41zM14,14.5V12h-4v3H8v-4c0,-0.55 0.45,-1 1,-1h5V7.5l3.5,3.5 -3.5,3.5z"/>
|
||||||
|
</vector>
|
||||||
10
app/src/main/res/drawable/ic_overflow.xml
Normal file
10
app/src/main/res/drawable/ic_overflow.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:tint="@color/status_bar_blue">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
|
||||||
|
android:fillColor="@android:color/black"/>
|
||||||
|
</vector>
|
||||||
11
app/src/main/res/drawable/ic_wikidata_logo_24dp.xml
Normal file
11
app/src/main/res/drawable/ic_wikidata_logo_24dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector android:height="24dp"
|
||||||
|
android:viewportHeight="93.46232"
|
||||||
|
android:viewportWidth="102.1415"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:tint="@color/button_color_selector"
|
||||||
|
>
|
||||||
|
<path android:fillColor="#990000" android:pathData="m0.83,77.62 l3.71,0 0,-61.79 -3.71,0 0,61.79zM8.24,77.62 L19.36,77.62 19.36,15.84 8.24,15.84 8.24,77.62zM23.07,15.84 L23.07,77.62 34.19,77.62 34.19,15.84 23.07,15.84z"/>
|
||||||
|
<path android:fillColor="#339966" android:pathData="m89.8,77.62 l3.7,0 0,-61.79 -3.7,0 0,61.79zM97.21,15.84 L97.21,77.62 100.92,77.62 100.92,15.84 97.21,15.84zM37.9,77.62 L41.6,77.62 41.6,15.84 37.9,15.84 37.9,77.62zM45.31,15.84 L45.31,77.62 49.02,77.62 49.02,15.84 45.32,15.84z"/>
|
||||||
|
<path android:fillColor="#006699" android:pathData="m52.73,77.62 l11.12,0 0,-61.79 -11.12,0 0,61.79zM67.56,77.62 L71.26,77.62 71.26,15.84 67.56,15.84 67.56,77.62zM74.97,15.84 L74.97,77.62 86.09,77.62 86.09,15.84 74.98,15.84z"/>
|
||||||
|
</vector>
|
||||||
11
app/src/main/res/drawable/ic_wikipedia_logo_24dp.xml
Normal file
11
app/src/main/res/drawable/ic_wikipedia_logo_24dp.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector android:height="24dp"
|
||||||
|
android:viewportHeight="141.092"
|
||||||
|
android:viewportWidth="141.092"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:tint="@color/button_color_selector"
|
||||||
|
>
|
||||||
|
<path android:fillAlpha="1" android:fillColor="#000000"
|
||||||
|
android:pathData="M91.5,116.05 L73.43,73.49c-7.16,14.05 -15.09,28.64 -21.88,42.54 -0.04,0.07 -3.28,0.03 -3.28,-0.01C37.9,91.8 27.14,67.75 16.72,43.56 14.3,37.65 5.83,28.14 0.04,28.19 0.04,27.5 0.01,25.97 0,25.04L35.71,25.03l-0.02,3.11c-4.19,0.2 -11.44,2.87 -9.57,7.5 5.04,10.87 22.86,52.97 27.67,63.66 3.36,-6.58 12.75,-24.12 16.61,-31.53 -3.03,-6.22 -13.04,-29.43 -16.04,-35.27 -2.26,-3.81 -7.94,-4.28 -12.32,-4.34 0,-0.98 0.05,-1.73 0.03,-3.07l31.4,0.1 0,2.85c-4.25,0.12 -8.28,1.7 -6.45,5.76 4.22,8.77 6.69,15.01 10.57,23.11 1.24,-2.37 7.58,-15.39 10.61,-22.27 1.83,-4.57 -0.9,-6.28 -8.55,-6.49 0.1,-0.75 0.03,-2.26 0.1,-2.98 9.76,-0.04 24.5,-0.07 27.11,-0.11l0.01,2.97c-4.98,0.19 -10.14,2.85 -12.83,6.97l-13.06,27.08c1.43,3.59 13.99,31.47 15.31,34.56L123.29,34.34c-1.92,-5.05 -8.05,-6.17 -10.44,-6.23 0.02,-0.8 0.02,-2.03 0.03,-3.05l28.18,0.21 0.04,0.14 -0.05,2.68c-6.18,0.19 -10.01,3.49 -12.29,8.91 -5.62,12.68 -22.78,52.86 -34.24,79.05 -0.01,0.01 -3,-0 -3.01,-0.01z"
|
||||||
|
android:strokeAlpha="1" android:strokeColor="#00000000"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -4,40 +4,155 @@
|
||||||
android:id="@+id/drawer_layout"
|
android:id="@+id/drawer_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<RelativeLayout
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/coordinator_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
>
|
||||||
<include
|
<RelativeLayout
|
||||||
android:id="@+id/toolbar"
|
|
||||||
layout="@layout/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<include
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/toolbar"
|
||||||
android:layout_height="match_parent"
|
layout="@layout/toolbar"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_below="@id/toolbar">
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
<android.support.v4.widget.SwipeRefreshLayout
|
|
||||||
android:id="@+id/swipe_container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<android.support.design.widget.NavigationView
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/toolbar"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</LinearLayout>
|
||||||
|
<android.support.design.widget.FloatingActionButton
|
||||||
|
android:id="@+id/fab_list"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:fabSize="mini"
|
||||||
|
android:layout_alignBottom="@id/toolbar"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginRight="28dp"
|
||||||
|
android:layout_marginBottom="-96dp"
|
||||||
|
android:visibility="invisible"
|
||||||
|
app:elevation="6dp"
|
||||||
|
app:pressedTranslationZ="12dp"
|
||||||
|
app:backgroundTint="@color/button_blue"
|
||||||
|
android:clickable="true"
|
||||||
|
app:srcCompat="@drawable/ic_list_white_24dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
/>
|
||||||
|
<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:id="@+id/navigation_view"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
||||||
192
app/src/main/res/layout/bottom_sheet_details.xml
Normal file
192
app/src/main/res/layout/bottom_sheet_details.xml
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="?attr/mainBackground"
|
||||||
|
app:layout_behavior="@string/bottom_sheet_behavior"
|
||||||
|
app:behavior_peekHeight="72dp"
|
||||||
|
app:behavior_hideable="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
|
||||||
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginLeft="16dp">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/category"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="@android:color/darker_gray"/>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/directionsButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
app:srcCompat="@drawable/ic_directions_black_24dp" />
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/directionsButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:textColor="@color/text_color_selector"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="@string/nearby_directions"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/wikidataButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
app:srcCompat="@drawable/ic_wikidata_logo_24dp" />
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/wikidataButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:textColor="@color/text_color_selector"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="@string/nearby_wikidata"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/wikipediaButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
app:srcCompat="@drawable/ic_wikipedia_logo_24dp"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/wikipediaButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:textColor="@color/text_color_selector"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="@string/nearby_wikipedia"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/commonsButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
app:srcCompat="@drawable/ic_commons_icon_vector"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/commonsButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:textColor="@color/text_color_selector"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="@string/nearby_commons"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="@android:color/darker_gray"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="72dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
25
app/src/main/res/layout/bottom_sheet_nearby.xml
Normal file
25
app/src/main/res/layout/bottom_sheet_nearby.xml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="480dp"
|
||||||
|
android:id="@+id/bottom_sheet"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="?attr/mainBackground"
|
||||||
|
app:layout_behavior="@string/bottom_sheet_behavior"
|
||||||
|
app:behavior_peekHeight="0dp"
|
||||||
|
app:behavior_hideable="true"
|
||||||
|
>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/container_sheet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
></FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:foreground="?selectableItemBackground"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:minHeight="72dp"
|
android:focusableInTouchMode="true"
|
||||||
>
|
android:minHeight="72dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon"
|
android:id="@+id/icon"
|
||||||
|
|
@ -32,6 +32,17 @@
|
||||||
tools:text="@string/placeholder_place_distance"
|
tools:text="@string/placeholder_place_distance"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/toggleArrow"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvName"
|
android:id="@+id/tvName"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
@ -65,4 +76,5 @@
|
||||||
tools:text="@string/placeholder_place_description"
|
tools:text="@string/placeholder_place_description"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
<include layout="@layout/nearby_row_button" />
|
||||||
|
</RelativeLayout>
|
||||||
124
app/src/main/res/layout/nearby_row_button.xml
Normal file
124
app/src/main/res/layout/nearby_row_button.xml
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/buttonLayout"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_below="@+id/icon"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/cameraButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:srcCompat="@drawable/ic_photo_camera_white_24dp"
|
||||||
|
android:tint="@color/button_blue"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/cameraButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="CAMERA"
|
||||||
|
android:visibility="gone"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/galleryButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:srcCompat="@drawable/ic_photo_white_24dp"
|
||||||
|
android:tint="@color/button_blue"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/galleryButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="GALLERY"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/directionsButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/button_background_selector"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:srcCompat="@drawable/ic_directions_black_24dp"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/directionsButtonText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="DIRECTIONS"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/iconOverflow"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:srcCompat="@drawable/ic_overflow"
|
||||||
|
android:duplicateParentState="true"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/iconOverflowText"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="MORE"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -3,17 +3,9 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
|
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_toggle_view"
|
android:id="@+id/action_display_list"
|
||||||
android:title="@string/toggle_view_button"
|
android:title="@string/display_list_button"
|
||||||
android:icon="@drawable/ic_map_white_24dp"
|
android:icon="@drawable/ic_list_white_24dp"
|
||||||
android:orderInCategory="1"
|
|
||||||
app:showAsAction="ifRoom"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_refresh"
|
|
||||||
android:title="@string/refresh_button"
|
|
||||||
android:icon="@drawable/ic_refresh_white_24dp"
|
|
||||||
android:orderInCategory="1"
|
android:orderInCategory="1"
|
||||||
app:showAsAction="ifRoom"
|
app:showAsAction="ifRoom"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,7 @@
|
||||||
<item android:id="@+id/nearby_info_menu_wikidata_article"
|
<item android:id="@+id/nearby_info_menu_wikidata_article"
|
||||||
android:title="@string/nearby_info_menu_wikidata_article"
|
android:title="@string/nearby_info_menu_wikidata_article"
|
||||||
/>
|
/>
|
||||||
|
<item android:id="@+id/nearby_info_menu_wikipedia_article"
|
||||||
|
android:title="@string/nearby_info_menu_wikipedia_article"
|
||||||
|
/>
|
||||||
</menu>
|
</menu>
|
||||||
|
|
@ -8,6 +8,13 @@
|
||||||
<attr name="uploadOverlayBackground" format="reference"/>
|
<attr name="uploadOverlayBackground" format="reference"/>
|
||||||
<attr name="spinnerTheme" format="reference"/>
|
<attr name="spinnerTheme" format="reference"/>
|
||||||
<attr name="iconsTheme" format="reference"/>
|
<attr name="iconsTheme" format="reference"/>
|
||||||
|
<attr name="bottomBar" format="reference"/>
|
||||||
|
<attr name="buttonBackgroundFocused" format="reference"/>
|
||||||
|
<attr name="buttonBackgroundPressed" format="reference"/>
|
||||||
|
<attr name="buttonFocused" format="reference"/>
|
||||||
|
<attr name="buttonPressed" format="reference"/>
|
||||||
|
<attr name="textDisabled" format="reference"/>
|
||||||
|
<attr name="textEnabled" format="reference"/>
|
||||||
|
|
||||||
<declare-styleable name="CompatTextView">
|
<declare-styleable name="CompatTextView">
|
||||||
<attr name="drawablePadding" format="dimension"/>
|
<attr name="drawablePadding" format="dimension"/>
|
||||||
|
|
|
||||||
|
|
@ -33,4 +33,20 @@
|
||||||
<color name="upload_overlay_background_dark">#77000000</color>
|
<color name="upload_overlay_background_dark">#77000000</color>
|
||||||
<color name="upload_overlay_background_light">#44000000</color>
|
<color name="upload_overlay_background_light">#44000000</color>
|
||||||
|
|
||||||
|
<color name="pressed_button_light">#64999999</color>
|
||||||
|
<color name="focused_button_light">#32999999</color>
|
||||||
|
<color name="disabled_button_text_color_light">#48000000</color>
|
||||||
|
<color name="enabled_button_text_color_light">#B0000000</color>
|
||||||
|
|
||||||
|
<color name="pressed_button_dark">#40CCCCCC</color>
|
||||||
|
<color name="focused_button_dark">#26CCCCCC</color>
|
||||||
|
<color name="disabled_button_text_color_dark">#717171</color>
|
||||||
|
<color name="enabled_button_text_color_dark">#FFFFFF</color>
|
||||||
|
|
||||||
|
<color name="button_blue">#0c609c</color>
|
||||||
|
|
||||||
|
<color name="bottom_bar_light">#E0E0E0</color>
|
||||||
|
<color name="bottom_bar_dark">#424242</color>
|
||||||
|
|
||||||
|
<color name="opak_middle_grey">#757575</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
<string name="categories_search_text_hint">Search categories</string>
|
<string name="categories_search_text_hint">Search categories</string>
|
||||||
<string name="menu_save_categories">Save</string>
|
<string name="menu_save_categories">Save</string>
|
||||||
<string name="refresh_button">Refresh</string>
|
<string name="refresh_button">Refresh</string>
|
||||||
|
<string name="display_list_button">List</string>
|
||||||
<string name="gps_disabled">GPS is disabled in your device. Would you like to enable it?</string>
|
<string name="gps_disabled">GPS is disabled in your device. Would you like to enable it?</string>
|
||||||
<string name="enable_gps">Enable GPS</string>
|
<string name="enable_gps">Enable GPS</string>
|
||||||
<string name="contributions_subtitle_zero">No uploads yet</string>
|
<string name="contributions_subtitle_zero">No uploads yet</string>
|
||||||
|
|
@ -217,6 +218,7 @@
|
||||||
<string name="no_description_found">no description found</string>
|
<string name="no_description_found">no description found</string>
|
||||||
<string name="nearby_info_menu_commons_article">Commons file page</string>
|
<string name="nearby_info_menu_commons_article">Commons file page</string>
|
||||||
<string name="nearby_info_menu_wikidata_article">Wikidata item</string>
|
<string name="nearby_info_menu_wikidata_article">Wikidata item</string>
|
||||||
|
<string name="nearby_info_menu_wikipedia_article">Wikipedia article</string>
|
||||||
<string name="error_while_cache">Error while caching pictures</string>
|
<string name="error_while_cache">Error while caching pictures</string>
|
||||||
<string name="title_info">A unique descriptive title for the file, which will serve as a filename. You may use plain language with spaces. Do not include the file extension</string>
|
<string name="title_info">A unique descriptive title for the file, which will serve as a filename. You may use plain language with spaces. Do not include the file extension</string>
|
||||||
<string name="description_info">Please describe the media as much as possible: Where was it taken? What does it show? What is the context? Please describe the objects or persons. Reveal information that can not be easily guessed, for instance the time of day if it is a landscape. If the media shows something unusual, please explain what makes it unusual.</string>
|
<string name="description_info">Please describe the media as much as possible: Where was it taken? What does it show? What is the context? Please describe the objects or persons. Reveal information that can not be easily guessed, for instance the time of day if it is a landscape. If the media shows something unusual, please explain what makes it unusual.</string>
|
||||||
|
|
@ -244,6 +246,10 @@
|
||||||
<string name="notifications_thank_you_edit">Thank you for making an edit</string>
|
<string name="notifications_thank_you_edit">Thank you for making an edit</string>
|
||||||
<string name="notifications_mention">%1$s mentioned you on %2$s.</string>
|
<string name="notifications_mention">%1$s mentioned you on %2$s.</string>
|
||||||
<string name="toggle_view_button">Toggle view</string>
|
<string name="toggle_view_button">Toggle view</string>
|
||||||
|
<string name="nearby_directions">DIRECTIONS</string>
|
||||||
|
<string name="nearby_wikidata">WIKIDATA</string>
|
||||||
|
<string name="nearby_wikipedia">WIKIPEDIA</string>
|
||||||
|
<string name="nearby_commons">COMMONS</string>
|
||||||
<string name="about_rate_us"><u>Rate Us</u></string>
|
<string name="about_rate_us"><u>Rate Us</u></string>
|
||||||
<string name="about_faq">Frequently Asked Questions</string>
|
<string name="about_faq">Frequently Asked Questions</string>
|
||||||
<string name="welcome_skip_button">Skip Tutorial</string>
|
<string name="welcome_skip_button">Skip Tutorial</string>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,11 @@
|
||||||
<item name="uploadOverlayBackground">@color/upload_overlay_background_dark</item>
|
<item name="uploadOverlayBackground">@color/upload_overlay_background_dark</item>
|
||||||
<item name="spinnerTheme">@style/DarkSpinnerTheme</item>
|
<item name="spinnerTheme">@style/DarkSpinnerTheme</item>
|
||||||
<item name="iconsTheme">@color/main_background_light</item>
|
<item name="iconsTheme">@color/main_background_light</item>
|
||||||
|
<item name="bottomBar">@color/bottom_bar_dark</item>
|
||||||
|
<item name="buttonBackgroundFocused">@color/focused_button_dark</item>
|
||||||
|
<item name="buttonBackgroundPressed">@color/pressed_button_dark</item>
|
||||||
|
<item name="textDisabled">@color/disabled_button_text_color_dark</item>
|
||||||
|
<item name="textEnabled">@color/enabled_button_text_color_dark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="LightAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="LightAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
|
@ -29,6 +34,11 @@
|
||||||
<item name="uploadOverlayBackground">@color/upload_overlay_background_light</item>
|
<item name="uploadOverlayBackground">@color/upload_overlay_background_light</item>
|
||||||
<item name="spinnerTheme">@style/LightSpinnerTheme</item>
|
<item name="spinnerTheme">@style/LightSpinnerTheme</item>
|
||||||
<item name="iconsTheme">@color/main_background_dark</item>
|
<item name="iconsTheme">@color/main_background_dark</item>
|
||||||
|
<item name="bottomBar">@color/bottom_bar_light</item>
|
||||||
|
<item name="buttonBackgroundFocused">@color/focused_button_light</item>
|
||||||
|
<item name="buttonBackgroundPressed">@color/pressed_button_light</item>
|
||||||
|
<item name="textDisabled">@color/disabled_button_text_color_light</item>
|
||||||
|
<item name="textEnabled">@color/enabled_button_text_color_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="DarkSpinnerTheme" parent="DarkAppTheme">
|
<style name="DarkSpinnerTheme" parent="DarkAppTheme">
|
||||||
|
|
|
||||||
|
|
@ -64,5 +64,4 @@
|
||||||
android:summary="@string/send_log_file_description"/>
|
android:summary="@string/send_log_file_description"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
@ -8,6 +8,7 @@ SELECT
|
||||||
(SAMPLE(COALESCE(?emoji0, ?emoji1)) as ?emoji)
|
(SAMPLE(COALESCE(?emoji0, ?emoji1)) as ?emoji)
|
||||||
?wikipediaArticle
|
?wikipediaArticle
|
||||||
?commonsArticle
|
?commonsArticle
|
||||||
|
(SAMPLE(?Commons_category) as ?Commons_category)
|
||||||
WHERE {
|
WHERE {
|
||||||
# Around given location...
|
# Around given location...
|
||||||
SERVICE wikibase:around {
|
SERVICE wikibase:around {
|
||||||
|
|
@ -23,6 +24,9 @@ SELECT
|
||||||
OPTIONAL {?item rdfs:label ?item_label_preferred_language. FILTER (lang(?item_label_preferred_language) = "${LANG}")}
|
OPTIONAL {?item rdfs:label ?item_label_preferred_language. FILTER (lang(?item_label_preferred_language) = "${LANG}")}
|
||||||
OPTIONAL {?item rdfs:label ?item_label_any_language}
|
OPTIONAL {?item rdfs:label ?item_label_any_language}
|
||||||
|
|
||||||
|
# Get Commons category (P373)
|
||||||
|
OPTIONAL { ?item wdt:P373 ?Commons_category. }
|
||||||
|
|
||||||
# Get the class label in the preferred language of the user, or any other language if no label is available in that language.
|
# Get the class label in the preferred language of the user, or any other language if no label is available in that language.
|
||||||
OPTIONAL {
|
OPTIONAL {
|
||||||
?item p:P31/ps:P31 ?classId.
|
?item p:P31/ps:P31 ?classId.
|
||||||
|
|
@ -35,10 +39,6 @@ SELECT
|
||||||
# Get emoji
|
# Get emoji
|
||||||
OPTIONAL { ?classId wdt:P487 ?emoji0. }
|
OPTIONAL { ?classId wdt:P487 ?emoji0. }
|
||||||
OPTIONAL { ?classId wdt:P279*/wdt:P487 ?emoji1. }
|
OPTIONAL { ?classId wdt:P279*/wdt:P487 ?emoji1. }
|
||||||
OPTIONAL {
|
|
||||||
?sitelink schema:about ?item .
|
|
||||||
?sitelink schema:inLanguage "en"
|
|
||||||
}
|
|
||||||
OPTIONAL {
|
OPTIONAL {
|
||||||
?wikipediaArticle schema:about ?item ;
|
?wikipediaArticle schema:about ?item ;
|
||||||
schema:isPartOf <https://en.wikipedia.org/> .
|
schema:isPartOf <https://en.wikipedia.org/> .
|
||||||
|
|
|
||||||
|
|
@ -33,8 +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,
|
||||||
"?", null, new LatLng(39.7392, -104.9903, 0), null);
|
"desc", null, new LatLng(39.7392, -104.9903, 0), null);
|
||||||
// ^ "?" is a special value for unknown class names from Wikidata query results
|
|
||||||
private Place clickedPlace;
|
private Place clickedPlace;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue