mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Migration of locationpicker module from Java to Kotlin (#5981)
* Rename .java to .kt * Migrated location picker module from Java to Kotlin
This commit is contained in:
parent
fb1ef3212d
commit
771f370f9a
8 changed files with 807 additions and 841 deletions
|
|
@ -1,77 +0,0 @@
|
||||||
package fr.free.nrw.commons.LocationPicker;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import fr.free.nrw.commons.CameraPosition;
|
|
||||||
import fr.free.nrw.commons.Media;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for starting the activity
|
|
||||||
*/
|
|
||||||
public final class LocationPicker {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting camera position from the intent using constants
|
|
||||||
*
|
|
||||||
* @param data intent
|
|
||||||
* @return CameraPosition
|
|
||||||
*/
|
|
||||||
public static CameraPosition getCameraPosition(final Intent data) {
|
|
||||||
return data.getParcelableExtra(LocationPickerConstants.MAP_CAMERA_POSITION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class IntentBuilder {
|
|
||||||
|
|
||||||
private final Intent intent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new builder that creates an intent to launch the place picker activity.
|
|
||||||
*/
|
|
||||||
public IntentBuilder() {
|
|
||||||
intent = new Intent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and puts location in intent
|
|
||||||
* @param position CameraPosition
|
|
||||||
* @return LocationPicker.IntentBuilder
|
|
||||||
*/
|
|
||||||
public LocationPicker.IntentBuilder defaultLocation(
|
|
||||||
final CameraPosition position) {
|
|
||||||
intent.putExtra(LocationPickerConstants.MAP_CAMERA_POSITION, position);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and puts activity name in intent
|
|
||||||
* @param activity activity key
|
|
||||||
* @return LocationPicker.IntentBuilder
|
|
||||||
*/
|
|
||||||
public LocationPicker.IntentBuilder activityKey(
|
|
||||||
final String activity) {
|
|
||||||
intent.putExtra(LocationPickerConstants.ACTIVITY_KEY, activity);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and puts media in intent
|
|
||||||
* @param media Media
|
|
||||||
* @return LocationPicker.IntentBuilder
|
|
||||||
*/
|
|
||||||
public LocationPicker.IntentBuilder media(
|
|
||||||
final Media media) {
|
|
||||||
intent.putExtra(LocationPickerConstants.MEDIA, media);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and sets the activity
|
|
||||||
* @param activity Activity
|
|
||||||
* @return Intent
|
|
||||||
*/
|
|
||||||
public Intent build(final Activity activity) {
|
|
||||||
intent.setClass(activity, LocationPickerActivity.class);
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package fr.free.nrw.commons.LocationPicker
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import fr.free.nrw.commons.CameraPosition
|
||||||
|
import fr.free.nrw.commons.Media
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for starting the activity
|
||||||
|
*/
|
||||||
|
object LocationPicker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting camera position from the intent using constants
|
||||||
|
*
|
||||||
|
* @param data intent
|
||||||
|
* @return CameraPosition
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getCameraPosition(data: Intent): CameraPosition? {
|
||||||
|
return data.getParcelableExtra(LocationPickerConstants.MAP_CAMERA_POSITION)
|
||||||
|
}
|
||||||
|
|
||||||
|
class IntentBuilder
|
||||||
|
/**
|
||||||
|
* Creates a new builder that creates an intent to launch the place picker activity.
|
||||||
|
*/() {
|
||||||
|
|
||||||
|
private val intent: Intent = Intent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and puts location in intent
|
||||||
|
* @param position CameraPosition
|
||||||
|
* @return LocationPicker.IntentBuilder
|
||||||
|
*/
|
||||||
|
fun defaultLocation(position: CameraPosition): IntentBuilder {
|
||||||
|
intent.putExtra(LocationPickerConstants.MAP_CAMERA_POSITION, position)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and puts activity name in intent
|
||||||
|
* @param activity activity key
|
||||||
|
* @return LocationPicker.IntentBuilder
|
||||||
|
*/
|
||||||
|
fun activityKey(activity: String): IntentBuilder {
|
||||||
|
intent.putExtra(LocationPickerConstants.ACTIVITY_KEY, activity)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and puts media in intent
|
||||||
|
* @param media Media
|
||||||
|
* @return LocationPicker.IntentBuilder
|
||||||
|
*/
|
||||||
|
fun media(media: Media): IntentBuilder {
|
||||||
|
intent.putExtra(LocationPickerConstants.MEDIA, media)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and sets the activity
|
||||||
|
* @param activity Activity
|
||||||
|
* @return Intent
|
||||||
|
*/
|
||||||
|
fun build(activity: Activity): Intent {
|
||||||
|
intent.setClass(activity, LocationPickerActivity::class.java)
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,681 +0,0 @@
|
||||||
package fr.free.nrw.commons.LocationPicker;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION;
|
|
||||||
import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_ZOOM;
|
|
||||||
import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL;
|
|
||||||
|
|
||||||
import android.Manifest.permission;
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.location.LocationManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.animation.OvershootInterpolator;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
||||||
import fr.free.nrw.commons.CameraPosition;
|
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
|
||||||
import fr.free.nrw.commons.Media;
|
|
||||||
import fr.free.nrw.commons.R;
|
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
|
||||||
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient;
|
|
||||||
import fr.free.nrw.commons.coordinates.CoordinateEditHelper;
|
|
||||||
import fr.free.nrw.commons.filepicker.Constants;
|
|
||||||
import fr.free.nrw.commons.kvstore.BasicKvStore;
|
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
|
||||||
import fr.free.nrw.commons.location.LocationPermissionsHelper;
|
|
||||||
import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback;
|
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
|
||||||
import fr.free.nrw.commons.theme.BaseActivity;
|
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
|
||||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
|
||||||
import org.osmdroid.util.GeoPoint;
|
|
||||||
import org.osmdroid.util.constants.GeoConstants;
|
|
||||||
import org.osmdroid.views.CustomZoomButtonsController;
|
|
||||||
import org.osmdroid.views.overlay.Marker;
|
|
||||||
import org.osmdroid.views.overlay.Overlay;
|
|
||||||
import org.osmdroid.views.overlay.ScaleDiskOverlay;
|
|
||||||
import org.osmdroid.views.overlay.TilesOverlay;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helps to pick location and return the result with an intent
|
|
||||||
*/
|
|
||||||
public class LocationPickerActivity extends BaseActivity implements
|
|
||||||
LocationPermissionCallback {
|
|
||||||
/**
|
|
||||||
* coordinateEditHelper: helps to edit coordinates
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
CoordinateEditHelper coordinateEditHelper;
|
|
||||||
/**
|
|
||||||
* media : Media object
|
|
||||||
*/
|
|
||||||
private Media media;
|
|
||||||
/**
|
|
||||||
* cameraPosition : position of picker
|
|
||||||
*/
|
|
||||||
private CameraPosition cameraPosition;
|
|
||||||
/**
|
|
||||||
* markerImage : picker image
|
|
||||||
*/
|
|
||||||
private ImageView markerImage;
|
|
||||||
/**
|
|
||||||
* mapView : OSM Map
|
|
||||||
*/
|
|
||||||
private org.osmdroid.views.MapView mapView;
|
|
||||||
/**
|
|
||||||
* tvAttribution : credit
|
|
||||||
*/
|
|
||||||
private AppCompatTextView tvAttribution;
|
|
||||||
/**
|
|
||||||
* activity : activity key
|
|
||||||
*/
|
|
||||||
private String activity;
|
|
||||||
/**
|
|
||||||
* modifyLocationButton : button for start editing location
|
|
||||||
*/
|
|
||||||
Button modifyLocationButton;
|
|
||||||
/**
|
|
||||||
* removeLocationButton : button to remove location metadata
|
|
||||||
*/
|
|
||||||
Button removeLocationButton;
|
|
||||||
/**
|
|
||||||
* showInMapButton : button for showing in map
|
|
||||||
*/
|
|
||||||
TextView showInMapButton;
|
|
||||||
/**
|
|
||||||
* placeSelectedButton : fab for selecting location
|
|
||||||
*/
|
|
||||||
FloatingActionButton placeSelectedButton;
|
|
||||||
/**
|
|
||||||
* fabCenterOnLocation: button for center on location;
|
|
||||||
*/
|
|
||||||
FloatingActionButton fabCenterOnLocation;
|
|
||||||
/**
|
|
||||||
* shadow : imageview of shadow
|
|
||||||
*/
|
|
||||||
private ImageView shadow;
|
|
||||||
/**
|
|
||||||
* largeToolbarText : textView of shadow
|
|
||||||
*/
|
|
||||||
private TextView largeToolbarText;
|
|
||||||
/**
|
|
||||||
* smallToolbarText : textView of shadow
|
|
||||||
*/
|
|
||||||
private TextView smallToolbarText;
|
|
||||||
/**
|
|
||||||
* applicationKvStore : for storing values
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
@Named("default_preferences")
|
|
||||||
public
|
|
||||||
JsonKvStore applicationKvStore;
|
|
||||||
BasicKvStore store;
|
|
||||||
/**
|
|
||||||
* isDarkTheme: for keeping a track of the device theme and modifying the map theme accordingly
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
SystemThemeUtils systemThemeUtils;
|
|
||||||
private boolean isDarkTheme;
|
|
||||||
private boolean moveToCurrentLocation;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
LocationServiceManager locationManager;
|
|
||||||
LocationPermissionsHelper locationPermissionsHelper;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
SessionManager sessionManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constants
|
|
||||||
*/
|
|
||||||
private static final String CAMERA_POS = "cameraPosition";
|
|
||||||
private static final String ACTIVITY = "activity";
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
isDarkTheme = systemThemeUtils.isDeviceInNightMode();
|
|
||||||
moveToCurrentLocation = false;
|
|
||||||
store = new BasicKvStore(this, "LocationPermissions");
|
|
||||||
|
|
||||||
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
|
|
||||||
final ActionBar actionBar = getSupportActionBar();
|
|
||||||
if (actionBar != null) {
|
|
||||||
actionBar.hide();
|
|
||||||
}
|
|
||||||
setContentView(R.layout.activity_location_picker);
|
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
|
||||||
cameraPosition = getIntent()
|
|
||||||
.getParcelableExtra(LocationPickerConstants.MAP_CAMERA_POSITION);
|
|
||||||
activity = getIntent().getStringExtra(LocationPickerConstants.ACTIVITY_KEY);
|
|
||||||
media = getIntent().getParcelableExtra(LocationPickerConstants.MEDIA);
|
|
||||||
}else{
|
|
||||||
cameraPosition = savedInstanceState.getParcelable(CAMERA_POS);
|
|
||||||
activity = savedInstanceState.getString(ACTIVITY);
|
|
||||||
media = savedInstanceState.getParcelable("sMedia");
|
|
||||||
}
|
|
||||||
bindViews();
|
|
||||||
addBackButtonListener();
|
|
||||||
addPlaceSelectedButton();
|
|
||||||
addCredits();
|
|
||||||
getToolbarUI();
|
|
||||||
addCenterOnGPSButton();
|
|
||||||
|
|
||||||
org.osmdroid.config.Configuration.getInstance().load(getApplicationContext(),
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()));
|
|
||||||
|
|
||||||
mapView.setTileSource(TileSourceFactory.WIKIMEDIA);
|
|
||||||
mapView.setTilesScaledToDpi(true);
|
|
||||||
mapView.setMultiTouchControls(true);
|
|
||||||
|
|
||||||
org.osmdroid.config.Configuration.getInstance().getAdditionalHttpRequestProperties().put(
|
|
||||||
"Referer", "http://maps.wikimedia.org/"
|
|
||||||
);
|
|
||||||
mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
|
|
||||||
mapView.getController().setZoom(ZOOM_LEVEL);
|
|
||||||
mapView.setOnTouchListener((v, event) -> {
|
|
||||||
if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
|
||||||
if (markerImage.getTranslationY() == 0) {
|
|
||||||
markerImage.animate().translationY(-75)
|
|
||||||
.setInterpolator(new OvershootInterpolator()).setDuration(250).start();
|
|
||||||
}
|
|
||||||
} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
||||||
markerImage.animate().translationY(0)
|
|
||||||
.setInterpolator(new OvershootInterpolator()).setDuration(250).start();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if ("UploadActivity".equals(activity)) {
|
|
||||||
placeSelectedButton.setVisibility(View.GONE);
|
|
||||||
modifyLocationButton.setVisibility(View.VISIBLE);
|
|
||||||
removeLocationButton.setVisibility(View.VISIBLE);
|
|
||||||
showInMapButton.setVisibility(View.VISIBLE);
|
|
||||||
largeToolbarText.setText(getResources().getString(R.string.image_location));
|
|
||||||
smallToolbarText.setText(getResources().
|
|
||||||
getString(R.string.check_whether_location_is_correct));
|
|
||||||
fabCenterOnLocation.setVisibility(View.GONE);
|
|
||||||
markerImage.setVisibility(View.GONE);
|
|
||||||
shadow.setVisibility(View.GONE);
|
|
||||||
assert cameraPosition != null;
|
|
||||||
showSelectedLocationMarker(new GeoPoint(cameraPosition.getLatitude(),
|
|
||||||
cameraPosition.getLongitude()));
|
|
||||||
}
|
|
||||||
setupMapView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the center of the map to the specified coordinates
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private void moveMapTo(double latitude, double longitude){
|
|
||||||
if(mapView != null && mapView.getController() != null){
|
|
||||||
GeoPoint point = new GeoPoint(latitude, longitude);
|
|
||||||
|
|
||||||
mapView.getController().setCenter(point);
|
|
||||||
mapView.getController().animateTo(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the center of the map to the specified coordinates
|
|
||||||
* @param point The GeoPoint object which contains the coordinates to move to
|
|
||||||
*/
|
|
||||||
private void moveMapTo(GeoPoint point){
|
|
||||||
if(point != null){
|
|
||||||
moveMapTo(point.getLatitude(), point.getLongitude());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For showing credits
|
|
||||||
*/
|
|
||||||
private void addCredits() {
|
|
||||||
tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
|
|
||||||
tvAttribution.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For setting up Dark Theme
|
|
||||||
*/
|
|
||||||
private void darkThemeSetup() {
|
|
||||||
if (isDarkTheme) {
|
|
||||||
shadow.setColorFilter(Color.argb(255, 255, 255, 255));
|
|
||||||
mapView.getOverlayManager().getTilesOverlay()
|
|
||||||
.setColorFilter(TilesOverlay.INVERT_COLORS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clicking back button destroy locationPickerActivity
|
|
||||||
*/
|
|
||||||
private void addBackButtonListener() {
|
|
||||||
final ImageView backButton = findViewById(R.id.maplibre_place_picker_toolbar_back_button);
|
|
||||||
backButton.setOnClickListener(v -> {
|
|
||||||
finish();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds mapView and location picker icon
|
|
||||||
*/
|
|
||||||
private void bindViews() {
|
|
||||||
mapView = findViewById(R.id.map_view);
|
|
||||||
markerImage = findViewById(R.id.location_picker_image_view_marker);
|
|
||||||
tvAttribution = findViewById(R.id.tv_attribution);
|
|
||||||
modifyLocationButton = findViewById(R.id.modify_location);
|
|
||||||
removeLocationButton = findViewById(R.id.remove_location);
|
|
||||||
showInMapButton = findViewById(R.id.show_in_map);
|
|
||||||
showInMapButton.setText(getResources().getString(R.string.show_in_map_app).toUpperCase(
|
|
||||||
Locale.ROOT));
|
|
||||||
shadow = findViewById(R.id.location_picker_image_view_shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets toolbar color
|
|
||||||
*/
|
|
||||||
private void getToolbarUI() {
|
|
||||||
final ConstraintLayout toolbar = findViewById(R.id.location_picker_toolbar);
|
|
||||||
largeToolbarText = findViewById(R.id.location_picker_toolbar_primary_text_view);
|
|
||||||
smallToolbarText = findViewById(R.id.location_picker_toolbar_secondary_text_view);
|
|
||||||
toolbar.setBackgroundColor(getResources().getColor(R.color.primaryColor));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupMapView() {
|
|
||||||
requestLocationPermissions();
|
|
||||||
|
|
||||||
//If location metadata is available, move map to that location.
|
|
||||||
if(activity.equals("UploadActivity") || activity.equals("MediaActivity")){
|
|
||||||
moveMapToMediaLocation();
|
|
||||||
} else {
|
|
||||||
//If location metadata is not available, move map to device GPS location.
|
|
||||||
moveMapToGPSLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyLocationButton.setOnClickListener(v -> onClickModifyLocation());
|
|
||||||
removeLocationButton.setOnClickListener(v -> onClickRemoveLocation());
|
|
||||||
showInMapButton.setOnClickListener(v -> showInMapApp());
|
|
||||||
darkThemeSetup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles onclick event of modifyLocationButton
|
|
||||||
*/
|
|
||||||
private void onClickModifyLocation() {
|
|
||||||
placeSelectedButton.setVisibility(View.VISIBLE);
|
|
||||||
modifyLocationButton.setVisibility(View.GONE);
|
|
||||||
removeLocationButton.setVisibility(View.GONE);
|
|
||||||
showInMapButton.setVisibility(View.GONE);
|
|
||||||
markerImage.setVisibility(View.VISIBLE);
|
|
||||||
shadow.setVisibility(View.VISIBLE);
|
|
||||||
largeToolbarText.setText(getResources().getString(R.string.choose_a_location));
|
|
||||||
smallToolbarText.setText(getResources().getString(R.string.pan_and_zoom_to_adjust));
|
|
||||||
fabCenterOnLocation.setVisibility(View.VISIBLE);
|
|
||||||
removeSelectedLocationMarker();
|
|
||||||
moveMapToMediaLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles onclick event of removeLocationButton
|
|
||||||
*/
|
|
||||||
private void onClickRemoveLocation() {
|
|
||||||
DialogUtil.showAlertDialog(this,
|
|
||||||
getString(R.string.remove_location_warning_title),
|
|
||||||
getString(R.string.remove_location_warning_desc),
|
|
||||||
getString(R.string.continue_message),
|
|
||||||
getString(R.string.cancel), () -> removeLocationFromImage(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to remove the location from the picture
|
|
||||||
*/
|
|
||||||
private void removeLocationFromImage() {
|
|
||||||
if (media != null) {
|
|
||||||
getCompositeDisposable().add(coordinateEditHelper.makeCoordinatesEdit(getApplicationContext()
|
|
||||||
, media, "0.0", "0.0", "0.0f")
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(s -> {
|
|
||||||
Timber.d("Coordinates are removed from the image");
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
final Intent returningIntent = new Intent();
|
|
||||||
setResult(AppCompatActivity.RESULT_OK, returningIntent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the location in map app. Map will center on the location metadata, if available.
|
|
||||||
* If there is no location metadata, the map will center on the commons app map center.
|
|
||||||
*/
|
|
||||||
private void showInMapApp() {
|
|
||||||
fr.free.nrw.commons.location.LatLng position = null;
|
|
||||||
|
|
||||||
if(activity.equals("UploadActivity") && cameraPosition != null){
|
|
||||||
//location metadata is available
|
|
||||||
position = new fr.free.nrw.commons.location.LatLng(cameraPosition.getLatitude(),
|
|
||||||
cameraPosition.getLongitude(), 0.0f);
|
|
||||||
} else if(mapView != null){
|
|
||||||
//location metadata is not available
|
|
||||||
position = new fr.free.nrw.commons.location.LatLng(mapView.getMapCenter().getLatitude(),
|
|
||||||
mapView.getMapCenter().getLongitude(), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(position != null){
|
|
||||||
Utils.handleGeoCoordinates(this, position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the center of the map to the media's location, if that data
|
|
||||||
* is available.
|
|
||||||
*/
|
|
||||||
private void moveMapToMediaLocation() {
|
|
||||||
if (cameraPosition != null) {
|
|
||||||
|
|
||||||
GeoPoint point = new GeoPoint(cameraPosition.getLatitude(),
|
|
||||||
cameraPosition.getLongitude());
|
|
||||||
|
|
||||||
moveMapTo(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the center of the map to the device's GPS location, if that data is available.
|
|
||||||
*/
|
|
||||||
private void moveMapToGPSLocation(){
|
|
||||||
if(locationManager != null){
|
|
||||||
fr.free.nrw.commons.location.LatLng location = locationManager.getLastLocation();
|
|
||||||
|
|
||||||
if(location != null){
|
|
||||||
GeoPoint point = new GeoPoint(location.getLatitude(), location.getLongitude());
|
|
||||||
|
|
||||||
moveMapTo(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select the preferable location
|
|
||||||
*/
|
|
||||||
private void addPlaceSelectedButton() {
|
|
||||||
placeSelectedButton = findViewById(R.id.location_chosen_button);
|
|
||||||
placeSelectedButton.setOnClickListener(view -> placeSelected());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the intent with required data
|
|
||||||
*/
|
|
||||||
void placeSelected() {
|
|
||||||
if (activity.equals("NoLocationUploadActivity")) {
|
|
||||||
applicationKvStore.putString(LAST_LOCATION,
|
|
||||||
mapView.getMapCenter().getLatitude()
|
|
||||||
+ ","
|
|
||||||
+ mapView.getMapCenter().getLongitude());
|
|
||||||
applicationKvStore.putString(LAST_ZOOM, mapView.getZoomLevel() + "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (media == null) {
|
|
||||||
final Intent returningIntent = new Intent();
|
|
||||||
returningIntent.putExtra(LocationPickerConstants.MAP_CAMERA_POSITION,
|
|
||||||
new CameraPosition(mapView.getMapCenter().getLatitude(),
|
|
||||||
mapView.getMapCenter().getLongitude(), 14.0));
|
|
||||||
setResult(AppCompatActivity.RESULT_OK, returningIntent);
|
|
||||||
} else {
|
|
||||||
updateCoordinates(String.valueOf(mapView.getMapCenter().getLatitude()),
|
|
||||||
String.valueOf(mapView.getMapCenter().getLongitude()),
|
|
||||||
String.valueOf(0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetched coordinates are replaced with existing coordinates by a POST API call.
|
|
||||||
* @param Latitude to be added
|
|
||||||
* @param Longitude to be added
|
|
||||||
* @param Accuracy to be added
|
|
||||||
*/
|
|
||||||
public void updateCoordinates(final String Latitude, final String Longitude,
|
|
||||||
final String Accuracy) {
|
|
||||||
if (media == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
getCompositeDisposable().add(
|
|
||||||
coordinateEditHelper.makeCoordinatesEdit(getApplicationContext(), media,
|
|
||||||
Latitude, Longitude, Accuracy)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(s -> {
|
|
||||||
Timber.d("Coordinates are added.");
|
|
||||||
}));
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) {
|
|
||||||
final String username = sessionManager.getUserName();
|
|
||||||
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
|
|
||||||
this,
|
|
||||||
getString(R.string.invalid_login_message),
|
|
||||||
username
|
|
||||||
);
|
|
||||||
|
|
||||||
CommonsApplication.getInstance().clearApplicationData(
|
|
||||||
this, logoutListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Center the camera on the last saved location
|
|
||||||
*/
|
|
||||||
private void addCenterOnGPSButton() {
|
|
||||||
fabCenterOnLocation = findViewById(R.id.center_on_gps);
|
|
||||||
fabCenterOnLocation.setOnClickListener(view -> {
|
|
||||||
moveToCurrentLocation = true;
|
|
||||||
requestLocationPermissions();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds selected location marker on the map
|
|
||||||
*/
|
|
||||||
private void showSelectedLocationMarker(GeoPoint point) {
|
|
||||||
Drawable icon = ContextCompat.getDrawable(this, R.drawable.map_default_map_marker);
|
|
||||||
Marker marker = new Marker(mapView);
|
|
||||||
marker.setPosition(point);
|
|
||||||
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
|
|
||||||
marker.setIcon(icon);
|
|
||||||
marker.setInfoWindow(null);
|
|
||||||
mapView.getOverlays().add(marker);
|
|
||||||
mapView.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes selected location marker from the map
|
|
||||||
*/
|
|
||||||
private void removeSelectedLocationMarker() {
|
|
||||||
List<Overlay> overlays = mapView.getOverlays();
|
|
||||||
for (int i = 0; i < overlays.size(); i++) {
|
|
||||||
if (overlays.get(i) instanceof Marker) {
|
|
||||||
Marker item = (Marker) overlays.get(i);
|
|
||||||
if (cameraPosition.getLatitude() == item.getPosition().getLatitude()
|
|
||||||
&& cameraPosition.getLongitude() == item.getPosition().getLongitude()) {
|
|
||||||
mapView.getOverlays().remove(i);
|
|
||||||
mapView.invalidate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Center the map at user's current location
|
|
||||||
*/
|
|
||||||
private void requestLocationPermissions() {
|
|
||||||
locationPermissionsHelper = new LocationPermissionsHelper(
|
|
||||||
this, locationManager, this);
|
|
||||||
locationPermissionsHelper.requestForLocationAccess(R.string.location_permission_title,
|
|
||||||
R.string.upload_map_location_access);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(final int requestCode,
|
|
||||||
@NonNull final String[] permissions,
|
|
||||||
@NonNull final int[] grantResults) {
|
|
||||||
if (requestCode == Constants.RequestCodes.LOCATION
|
|
||||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
onLocationPermissionGranted();
|
|
||||||
} else {
|
|
||||||
onLocationPermissionDenied(getString(R.string.upload_map_location_access));
|
|
||||||
}
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
mapView.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
mapView.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLocationPermissionDenied(String toastMessage) {
|
|
||||||
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
|
|
||||||
permission.ACCESS_FINE_LOCATION)) {
|
|
||||||
if (!locationPermissionsHelper.checkLocationPermission(this)) {
|
|
||||||
if (store.getBoolean("isPermissionDenied", false)) {
|
|
||||||
// means user has denied location permission twice or checked the "Don't show again"
|
|
||||||
locationPermissionsHelper.showAppSettingsDialog(this,
|
|
||||||
R.string.upload_map_location_access);
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getBaseContext(), toastMessage, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
store.putBoolean("isPermissionDenied", true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getBaseContext(), toastMessage, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLocationPermissionGranted() {
|
|
||||||
if (moveToCurrentLocation || !(activity.equals("MediaActivity"))) {
|
|
||||||
if (locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) {
|
|
||||||
locationManager.requestLocationUpdatesFromProvider(
|
|
||||||
LocationManager.NETWORK_PROVIDER);
|
|
||||||
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
|
|
||||||
addMarkerAtGPSLocation();
|
|
||||||
} else {
|
|
||||||
addMarkerAtGPSLocation();
|
|
||||||
locationPermissionsHelper.showLocationOffDialog(this,
|
|
||||||
R.string.ask_to_turn_location_on_text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a marker to the map at the most recent GPS location
|
|
||||||
* (which may be the current GPS location).
|
|
||||||
*/
|
|
||||||
private void addMarkerAtGPSLocation() {
|
|
||||||
fr.free.nrw.commons.location.LatLng currLocation = locationManager.getLastLocation();
|
|
||||||
if (currLocation != null) {
|
|
||||||
GeoPoint currLocationGeopoint = new GeoPoint(currLocation.getLatitude(),
|
|
||||||
currLocation.getLongitude());
|
|
||||||
addLocationMarker(currLocationGeopoint);
|
|
||||||
markerImage.setTranslationY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addLocationMarker(GeoPoint geoPoint) {
|
|
||||||
if (moveToCurrentLocation) {
|
|
||||||
mapView.getOverlays().clear();
|
|
||||||
}
|
|
||||||
ScaleDiskOverlay diskOverlay =
|
|
||||||
new ScaleDiskOverlay(this,
|
|
||||||
geoPoint, 2000, GeoConstants.UnitOfMeasure.foot);
|
|
||||||
Paint circlePaint = new Paint();
|
|
||||||
circlePaint.setColor(Color.rgb(128, 128, 128));
|
|
||||||
circlePaint.setStyle(Paint.Style.STROKE);
|
|
||||||
circlePaint.setStrokeWidth(2f);
|
|
||||||
diskOverlay.setCirclePaint2(circlePaint);
|
|
||||||
Paint diskPaint = new Paint();
|
|
||||||
diskPaint.setColor(Color.argb(40, 128, 128, 128));
|
|
||||||
diskPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
|
||||||
diskOverlay.setCirclePaint1(diskPaint);
|
|
||||||
diskOverlay.setDisplaySizeMin(900);
|
|
||||||
diskOverlay.setDisplaySizeMax(1700);
|
|
||||||
mapView.getOverlays().add(diskOverlay);
|
|
||||||
org.osmdroid.views.overlay.Marker startMarker = new org.osmdroid.views.overlay.Marker(
|
|
||||||
mapView);
|
|
||||||
startMarker.setPosition(geoPoint);
|
|
||||||
startMarker.setAnchor(org.osmdroid.views.overlay.Marker.ANCHOR_CENTER,
|
|
||||||
org.osmdroid.views.overlay.Marker.ANCHOR_BOTTOM);
|
|
||||||
startMarker.setIcon(
|
|
||||||
ContextCompat.getDrawable(this, R.drawable.current_location_marker));
|
|
||||||
startMarker.setTitle("Your Location");
|
|
||||||
startMarker.setTextLabelFontSize(24);
|
|
||||||
mapView.getOverlays().add(startMarker);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the state of the activity
|
|
||||||
* @param outState Bundle
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
if(cameraPosition!=null){
|
|
||||||
outState.putParcelable(CAMERA_POS, cameraPosition);
|
|
||||||
}
|
|
||||||
if(activity!=null){
|
|
||||||
outState.putString(ACTIVITY, activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(media!=null){
|
|
||||||
outState.putParcelable("sMedia", media);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,678 @@
|
||||||
|
package fr.free.nrw.commons.LocationPicker
|
||||||
|
|
||||||
|
import android.Manifest.permission
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.location.LocationManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.preference.PreferenceManager
|
||||||
|
import android.text.Html
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.Window
|
||||||
|
import android.view.animation.OvershootInterpolator
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import fr.free.nrw.commons.CameraPosition
|
||||||
|
import fr.free.nrw.commons.CommonsApplication
|
||||||
|
import fr.free.nrw.commons.Media
|
||||||
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.Utils
|
||||||
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
|
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
|
||||||
|
import fr.free.nrw.commons.coordinates.CoordinateEditHelper
|
||||||
|
import fr.free.nrw.commons.filepicker.Constants
|
||||||
|
import fr.free.nrw.commons.kvstore.BasicKvStore
|
||||||
|
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||||
|
import fr.free.nrw.commons.location.LocationPermissionsHelper
|
||||||
|
import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback
|
||||||
|
import fr.free.nrw.commons.location.LocationServiceManager
|
||||||
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION
|
||||||
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_ZOOM
|
||||||
|
import fr.free.nrw.commons.utils.DialogUtil
|
||||||
|
import fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
||||||
|
import org.osmdroid.util.GeoPoint
|
||||||
|
import org.osmdroid.util.constants.GeoConstants
|
||||||
|
import org.osmdroid.views.CustomZoomButtonsController
|
||||||
|
import org.osmdroid.views.overlay.Marker
|
||||||
|
import org.osmdroid.views.overlay.ScaleDiskOverlay
|
||||||
|
import org.osmdroid.views.overlay.TilesOverlay
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Named
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helps to pick location and return the result with an intent
|
||||||
|
*/
|
||||||
|
class LocationPickerActivity : BaseActivity(), LocationPermissionCallback {
|
||||||
|
/**
|
||||||
|
* coordinateEditHelper: helps to edit coordinates
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
lateinit var coordinateEditHelper: CoordinateEditHelper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* media : Media object
|
||||||
|
*/
|
||||||
|
private var media: Media? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cameraPosition : position of picker
|
||||||
|
*/
|
||||||
|
private var cameraPosition: CameraPosition? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* markerImage : picker image
|
||||||
|
*/
|
||||||
|
private lateinit var markerImage: ImageView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mapView : OSM Map
|
||||||
|
*/
|
||||||
|
private var mapView: org.osmdroid.views.MapView? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tvAttribution : credit
|
||||||
|
*/
|
||||||
|
private lateinit var tvAttribution: AppCompatTextView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* activity : activity key
|
||||||
|
*/
|
||||||
|
private var activity: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* modifyLocationButton : button for start editing location
|
||||||
|
*/
|
||||||
|
private lateinit var modifyLocationButton: Button
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removeLocationButton : button to remove location metadata
|
||||||
|
*/
|
||||||
|
private lateinit var removeLocationButton: Button
|
||||||
|
|
||||||
|
/**
|
||||||
|
* showInMapButton : button for showing in map
|
||||||
|
*/
|
||||||
|
private lateinit var showInMapButton: TextView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* placeSelectedButton : fab for selecting location
|
||||||
|
*/
|
||||||
|
private lateinit var placeSelectedButton: FloatingActionButton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fabCenterOnLocation: button for center on location;
|
||||||
|
*/
|
||||||
|
private lateinit var fabCenterOnLocation: FloatingActionButton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shadow : imageview of shadow
|
||||||
|
*/
|
||||||
|
private lateinit var shadow: ImageView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* largeToolbarText : textView of shadow
|
||||||
|
*/
|
||||||
|
private lateinit var largeToolbarText: TextView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smallToolbarText : textView of shadow
|
||||||
|
*/
|
||||||
|
private lateinit var smallToolbarText: TextView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* applicationKvStore : for storing values
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
@field: Named("default_preferences")
|
||||||
|
lateinit var applicationKvStore: JsonKvStore
|
||||||
|
private lateinit var store: BasicKvStore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isDarkTheme: for keeping a track of the device theme and modifying the map theme accordingly
|
||||||
|
*/
|
||||||
|
private var isDarkTheme: Boolean = false
|
||||||
|
private var moveToCurrentLocation: Boolean = false
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var locationManager: LocationServiceManager
|
||||||
|
private lateinit var locationPermissionsHelper: LocationPermissionsHelper
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var sessionManager: SessionManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants
|
||||||
|
*/
|
||||||
|
companion object {
|
||||||
|
private const val CAMERA_POS = "cameraPosition"
|
||||||
|
private const val ACTIVITY = "activity"
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
requestWindowFeature(Window.FEATURE_ACTION_BAR)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
isDarkTheme = systemThemeUtils.isDeviceInNightMode()
|
||||||
|
moveToCurrentLocation = false
|
||||||
|
store = BasicKvStore(this, "LocationPermissions")
|
||||||
|
|
||||||
|
requestWindowFeature(Window.FEATURE_ACTION_BAR)
|
||||||
|
supportActionBar?.hide()
|
||||||
|
setContentView(R.layout.activity_location_picker)
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
cameraPosition = intent.getParcelableExtra(LocationPickerConstants.MAP_CAMERA_POSITION)
|
||||||
|
activity = intent.getStringExtra(LocationPickerConstants.ACTIVITY_KEY)
|
||||||
|
media = intent.getParcelableExtra(LocationPickerConstants.MEDIA)
|
||||||
|
} else {
|
||||||
|
cameraPosition = savedInstanceState.getParcelable(CAMERA_POS)
|
||||||
|
activity = savedInstanceState.getString(ACTIVITY)
|
||||||
|
media = savedInstanceState.getParcelable("sMedia")
|
||||||
|
}
|
||||||
|
|
||||||
|
bindViews()
|
||||||
|
addBackButtonListener()
|
||||||
|
addPlaceSelectedButton()
|
||||||
|
addCredits()
|
||||||
|
getToolbarUI()
|
||||||
|
addCenterOnGPSButton()
|
||||||
|
|
||||||
|
org.osmdroid.config.Configuration.getInstance()
|
||||||
|
.load(
|
||||||
|
applicationContext, PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
applicationContext
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
mapView?.setTileSource(TileSourceFactory.WIKIMEDIA)
|
||||||
|
mapView?.setTilesScaledToDpi(true)
|
||||||
|
mapView?.setMultiTouchControls(true)
|
||||||
|
|
||||||
|
org.osmdroid.config.Configuration.getInstance().additionalHttpRequestProperties["Referer"] =
|
||||||
|
"http://maps.wikimedia.org/"
|
||||||
|
mapView?.zoomController?.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
||||||
|
mapView?.controller?.setZoom(ZOOM_LEVEL.toDouble())
|
||||||
|
mapView?.setOnTouchListener { _, event ->
|
||||||
|
when (event.action) {
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
if (markerImage.translationY == 0f) {
|
||||||
|
markerImage.animate().translationY(-75f)
|
||||||
|
.setInterpolator(OvershootInterpolator()).duration = 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
markerImage.animate().translationY(0f)
|
||||||
|
.setInterpolator(OvershootInterpolator()).duration = 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activity == "UploadActivity") {
|
||||||
|
placeSelectedButton.visibility = View.GONE
|
||||||
|
modifyLocationButton.visibility = View.VISIBLE
|
||||||
|
removeLocationButton.visibility = View.VISIBLE
|
||||||
|
showInMapButton.visibility = View.VISIBLE
|
||||||
|
largeToolbarText.text = getString(R.string.image_location)
|
||||||
|
smallToolbarText.text = getString(R.string.check_whether_location_is_correct)
|
||||||
|
fabCenterOnLocation.visibility = View.GONE
|
||||||
|
markerImage.visibility = View.GONE
|
||||||
|
shadow.visibility = View.GONE
|
||||||
|
cameraPosition?.let {
|
||||||
|
showSelectedLocationMarker(GeoPoint(it.latitude, it.longitude))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setupMapView()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the center of the map to the specified coordinates
|
||||||
|
*/
|
||||||
|
private fun moveMapTo(latitude: Double, longitude: Double) {
|
||||||
|
mapView?.controller?.let {
|
||||||
|
val point = GeoPoint(latitude, longitude)
|
||||||
|
it.setCenter(point)
|
||||||
|
it.animateTo(point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the center of the map to the specified coordinates
|
||||||
|
* @param point The GeoPoint object which contains the coordinates to move to
|
||||||
|
*/
|
||||||
|
private fun moveMapTo(point: GeoPoint?) {
|
||||||
|
point?.let {
|
||||||
|
moveMapTo(it.latitude, it.longitude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For showing credits
|
||||||
|
*/
|
||||||
|
private fun addCredits() {
|
||||||
|
tvAttribution.text = Html.fromHtml(getString(R.string.map_attribution))
|
||||||
|
tvAttribution.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For setting up Dark Theme
|
||||||
|
*/
|
||||||
|
private fun darkThemeSetup() {
|
||||||
|
if (isDarkTheme) {
|
||||||
|
shadow.setColorFilter(Color.argb(255, 255, 255, 255))
|
||||||
|
mapView?.overlayManager?.tilesOverlay?.setColorFilter(TilesOverlay.INVERT_COLORS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clicking back button destroy locationPickerActivity
|
||||||
|
*/
|
||||||
|
private fun addBackButtonListener() {
|
||||||
|
val backButton = findViewById<ImageView>(R.id.maplibre_place_picker_toolbar_back_button)
|
||||||
|
backButton.setOnClickListener {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds mapView and location picker icon
|
||||||
|
*/
|
||||||
|
private fun bindViews() {
|
||||||
|
mapView = findViewById(R.id.map_view)
|
||||||
|
markerImage = findViewById(R.id.location_picker_image_view_marker)
|
||||||
|
tvAttribution = findViewById(R.id.tv_attribution)
|
||||||
|
modifyLocationButton = findViewById(R.id.modify_location)
|
||||||
|
removeLocationButton = findViewById(R.id.remove_location)
|
||||||
|
showInMapButton = findViewById(R.id.show_in_map)
|
||||||
|
showInMapButton.text = getString(R.string.show_in_map_app).uppercase(Locale.ROOT)
|
||||||
|
shadow = findViewById(R.id.location_picker_image_view_shadow)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets toolbar color
|
||||||
|
*/
|
||||||
|
private fun getToolbarUI() {
|
||||||
|
val toolbar: ConstraintLayout = findViewById(R.id.location_picker_toolbar)
|
||||||
|
largeToolbarText = findViewById(R.id.location_picker_toolbar_primary_text_view)
|
||||||
|
smallToolbarText = findViewById(R.id.location_picker_toolbar_secondary_text_view)
|
||||||
|
toolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.primaryColor))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupMapView() {
|
||||||
|
requestLocationPermissions()
|
||||||
|
|
||||||
|
//If location metadata is available, move map to that location.
|
||||||
|
if (activity == "UploadActivity" || activity == "MediaActivity") {
|
||||||
|
moveMapToMediaLocation()
|
||||||
|
} else {
|
||||||
|
//If location metadata is not available, move map to device GPS location.
|
||||||
|
moveMapToGPSLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyLocationButton.setOnClickListener { onClickModifyLocation() }
|
||||||
|
removeLocationButton.setOnClickListener { onClickRemoveLocation() }
|
||||||
|
showInMapButton.setOnClickListener { showInMapApp() }
|
||||||
|
darkThemeSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles onClick event of modifyLocationButton
|
||||||
|
*/
|
||||||
|
private fun onClickModifyLocation() {
|
||||||
|
placeSelectedButton.visibility = View.VISIBLE
|
||||||
|
modifyLocationButton.visibility = View.GONE
|
||||||
|
removeLocationButton.visibility = View.GONE
|
||||||
|
showInMapButton.visibility = View.GONE
|
||||||
|
markerImage.visibility = View.VISIBLE
|
||||||
|
shadow.visibility = View.VISIBLE
|
||||||
|
largeToolbarText.text = getString(R.string.choose_a_location)
|
||||||
|
smallToolbarText.text = getString(R.string.pan_and_zoom_to_adjust)
|
||||||
|
fabCenterOnLocation.visibility = View.VISIBLE
|
||||||
|
removeSelectedLocationMarker()
|
||||||
|
moveMapToMediaLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles onClick event of removeLocationButton
|
||||||
|
*/
|
||||||
|
private fun onClickRemoveLocation() {
|
||||||
|
DialogUtil.showAlertDialog(
|
||||||
|
this,
|
||||||
|
getString(R.string.remove_location_warning_title),
|
||||||
|
getString(R.string.remove_location_warning_desc),
|
||||||
|
getString(R.string.continue_message),
|
||||||
|
getString(R.string.cancel),
|
||||||
|
{ removeLocationFromImage() },
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes location metadata from the image
|
||||||
|
*/
|
||||||
|
private fun removeLocationFromImage() {
|
||||||
|
media?.let {
|
||||||
|
compositeDisposable.add(
|
||||||
|
coordinateEditHelper.makeCoordinatesEdit(
|
||||||
|
applicationContext, it, "0.0", "0.0", "0.0f"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe { _ ->
|
||||||
|
Timber.d("Coordinates removed from the image")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setResult(RESULT_OK, Intent())
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show location in map app
|
||||||
|
*/
|
||||||
|
private fun showInMapApp() {
|
||||||
|
val position = when {
|
||||||
|
//location metadata is available
|
||||||
|
activity == "UploadActivity" && cameraPosition != null -> {
|
||||||
|
fr.free.nrw.commons.location.LatLng(cameraPosition!!.latitude, cameraPosition!!.longitude, 0.0f)
|
||||||
|
}
|
||||||
|
//location metadata is not available
|
||||||
|
mapView != null -> {
|
||||||
|
fr.free.nrw.commons.location.LatLng(
|
||||||
|
mapView?.mapCenter?.latitude!!,
|
||||||
|
mapView?.mapCenter?.longitude!!,
|
||||||
|
0.0f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
position?.let { Utils.handleGeoCoordinates(this, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves map to media's location
|
||||||
|
*/
|
||||||
|
private fun moveMapToMediaLocation() {
|
||||||
|
cameraPosition?.let {
|
||||||
|
moveMapTo(GeoPoint(it.latitude, it.longitude))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves map to GPS location
|
||||||
|
*/
|
||||||
|
private fun moveMapToGPSLocation() {
|
||||||
|
locationManager.lastLocation?.let {
|
||||||
|
moveMapTo(GeoPoint(it.latitude, it.longitude))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds "Place Selected" button
|
||||||
|
*/
|
||||||
|
private fun addPlaceSelectedButton() {
|
||||||
|
placeSelectedButton = findViewById(R.id.location_chosen_button)
|
||||||
|
placeSelectedButton.setOnClickListener { placeSelected() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles "Place Selected" action
|
||||||
|
*/
|
||||||
|
private fun placeSelected() {
|
||||||
|
if (activity == "NoLocationUploadActivity") {
|
||||||
|
applicationKvStore.putString(
|
||||||
|
LAST_LOCATION,
|
||||||
|
"${mapView?.mapCenter?.latitude},${mapView?.mapCenter?.longitude}"
|
||||||
|
)
|
||||||
|
applicationKvStore.putString(LAST_ZOOM, mapView?.zoomLevel?.toString()!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (media == null) {
|
||||||
|
val intent = Intent().apply {
|
||||||
|
putExtra(
|
||||||
|
LocationPickerConstants.MAP_CAMERA_POSITION,
|
||||||
|
CameraPosition(mapView?.mapCenter?.latitude!!, mapView?.mapCenter?.longitude!!, 14.0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setResult(RESULT_OK, intent)
|
||||||
|
} else {
|
||||||
|
updateCoordinates(
|
||||||
|
mapView?.mapCenter?.latitude.toString(),
|
||||||
|
mapView?.mapCenter?.longitude.toString(),
|
||||||
|
"0.0f"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates image with new coordinates
|
||||||
|
*/
|
||||||
|
fun updateCoordinates(latitude: String, longitude: String, accuracy: String) {
|
||||||
|
media?.let {
|
||||||
|
try {
|
||||||
|
compositeDisposable.add(
|
||||||
|
coordinateEditHelper.makeCoordinatesEdit(
|
||||||
|
applicationContext,
|
||||||
|
it,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
accuracy
|
||||||
|
).subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe { _ ->
|
||||||
|
Timber.d("Coordinates updated")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e.localizedMessage == CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE) {
|
||||||
|
val username = sessionManager.userName
|
||||||
|
CommonsApplication.BaseLogoutListener(
|
||||||
|
this,
|
||||||
|
getString(R.string.invalid_login_message)
|
||||||
|
, username
|
||||||
|
).let {
|
||||||
|
CommonsApplication.instance.clearApplicationData(this, it)
|
||||||
|
}
|
||||||
|
} else { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a button to center the map at user's location
|
||||||
|
*/
|
||||||
|
private fun addCenterOnGPSButton() {
|
||||||
|
fabCenterOnLocation = findViewById(R.id.center_on_gps)
|
||||||
|
fabCenterOnLocation.setOnClickListener {
|
||||||
|
moveToCurrentLocation = true
|
||||||
|
requestLocationPermissions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a selected location marker
|
||||||
|
*/
|
||||||
|
private fun showSelectedLocationMarker(point: GeoPoint) {
|
||||||
|
val icon = ContextCompat.getDrawable(this, R.drawable.map_default_map_marker)
|
||||||
|
Marker(mapView).apply {
|
||||||
|
position = point
|
||||||
|
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||||
|
setIcon(icon)
|
||||||
|
infoWindow = null
|
||||||
|
mapView?.overlays?.add(this)
|
||||||
|
}
|
||||||
|
mapView?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes selected location marker
|
||||||
|
*/
|
||||||
|
private fun removeSelectedLocationMarker() {
|
||||||
|
val overlays = mapView?.overlays
|
||||||
|
overlays?.filterIsInstance<Marker>()?.firstOrNull {
|
||||||
|
it.position.latitude ==
|
||||||
|
cameraPosition?.latitude && it.position.longitude == cameraPosition?.longitude
|
||||||
|
}?.let {
|
||||||
|
overlays.remove(it)
|
||||||
|
mapView?.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centers map at user's location
|
||||||
|
*/
|
||||||
|
private fun requestLocationPermissions() {
|
||||||
|
locationPermissionsHelper = LocationPermissionsHelper(this, locationManager, this)
|
||||||
|
locationPermissionsHelper.requestForLocationAccess(
|
||||||
|
R.string.location_permission_title,
|
||||||
|
R.string.upload_map_location_access
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
|
if (requestCode == Constants.RequestCodes.LOCATION && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
onLocationPermissionGranted()
|
||||||
|
} else {
|
||||||
|
onLocationPermissionDenied(getString(R.string.upload_map_location_access))
|
||||||
|
}
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
mapView?.onResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
mapView?.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLocationPermissionDenied(toastMessage: String) {
|
||||||
|
val isDeniedBefore = store.getBoolean("isPermissionDenied", false)
|
||||||
|
val showRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, permission.ACCESS_FINE_LOCATION)
|
||||||
|
|
||||||
|
if (!showRationale) {
|
||||||
|
if (!locationPermissionsHelper.checkLocationPermission(this)) {
|
||||||
|
if (isDeniedBefore) {
|
||||||
|
locationPermissionsHelper.showAppSettingsDialog(this, R.string.upload_map_location_access)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
store.putBoolean("isPermissionDenied", true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLocationPermissionGranted() {
|
||||||
|
if (moveToCurrentLocation || activity != "MediaActivity") {
|
||||||
|
if (locationPermissionsHelper.isLocationAccessToAppsTurnedOn) {
|
||||||
|
locationManager.requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER)
|
||||||
|
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER)
|
||||||
|
addMarkerAtGPSLocation()
|
||||||
|
} else {
|
||||||
|
addMarkerAtGPSLocation()
|
||||||
|
locationPermissionsHelper.showLocationOffDialog(this, R.string.ask_to_turn_location_on_text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a marker at the user's GPS location
|
||||||
|
*/
|
||||||
|
private fun addMarkerAtGPSLocation() {
|
||||||
|
locationManager.lastLocation?.let {
|
||||||
|
addLocationMarker(GeoPoint(it.latitude, it.longitude))
|
||||||
|
markerImage.translationY = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addLocationMarker(geoPoint: GeoPoint) {
|
||||||
|
if (moveToCurrentLocation) {
|
||||||
|
mapView?.overlays?.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
val diskOverlay = ScaleDiskOverlay(
|
||||||
|
this,
|
||||||
|
geoPoint,
|
||||||
|
2000,
|
||||||
|
GeoConstants.UnitOfMeasure.foot
|
||||||
|
)
|
||||||
|
|
||||||
|
val circlePaint = Paint().apply {
|
||||||
|
color = Color.rgb(128, 128, 128)
|
||||||
|
style = Paint.Style.STROKE
|
||||||
|
strokeWidth = 2f
|
||||||
|
}
|
||||||
|
diskOverlay.setCirclePaint2(circlePaint)
|
||||||
|
|
||||||
|
val diskPaint = Paint().apply {
|
||||||
|
color = Color.argb(40, 128, 128, 128)
|
||||||
|
style = Paint.Style.FILL_AND_STROKE
|
||||||
|
}
|
||||||
|
diskOverlay.setCirclePaint1(diskPaint)
|
||||||
|
|
||||||
|
diskOverlay.setDisplaySizeMin(900)
|
||||||
|
diskOverlay.setDisplaySizeMax(1700)
|
||||||
|
|
||||||
|
mapView?.overlays?.add(diskOverlay)
|
||||||
|
|
||||||
|
val startMarker = Marker(mapView).apply {
|
||||||
|
position = geoPoint
|
||||||
|
setAnchor(
|
||||||
|
Marker.ANCHOR_CENTER,
|
||||||
|
Marker.ANCHOR_BOTTOM
|
||||||
|
)
|
||||||
|
icon = ContextCompat.getDrawable(this@LocationPickerActivity, R.drawable.current_location_marker)
|
||||||
|
title = "Your Location"
|
||||||
|
textLabelFontSize = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
mapView?.overlays?.add(startMarker)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the state of the activity
|
||||||
|
* @param outState Bundle
|
||||||
|
*/
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
|
||||||
|
cameraPosition?.let {
|
||||||
|
outState.putParcelable(CAMERA_POS, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
activity?.let {
|
||||||
|
outState.putString(ACTIVITY, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
media?.let {
|
||||||
|
outState.putParcelable("sMedia", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package fr.free.nrw.commons.LocationPicker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constants need for location picking
|
|
||||||
*/
|
|
||||||
public final class LocationPickerConstants {
|
|
||||||
|
|
||||||
public static final String ACTIVITY_KEY
|
|
||||||
= "location.picker.activity";
|
|
||||||
|
|
||||||
public static final String MAP_CAMERA_POSITION
|
|
||||||
= "location.picker.cameraPosition";
|
|
||||||
|
|
||||||
public static final String MEDIA
|
|
||||||
= "location.picker.media";
|
|
||||||
|
|
||||||
|
|
||||||
private LocationPickerConstants() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package fr.free.nrw.commons.LocationPicker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants need for location picking
|
||||||
|
*/
|
||||||
|
object LocationPickerConstants {
|
||||||
|
|
||||||
|
const val ACTIVITY_KEY = "location.picker.activity"
|
||||||
|
|
||||||
|
const val MAP_CAMERA_POSITION = "location.picker.cameraPosition"
|
||||||
|
|
||||||
|
const val MEDIA = "location.picker.media"
|
||||||
|
}
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
package fr.free.nrw.commons.LocationPicker;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import fr.free.nrw.commons.CameraPosition;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Observes live camera position data
|
|
||||||
*/
|
|
||||||
public class LocationPickerViewModel extends AndroidViewModel implements Callback<CameraPosition> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapping CameraPosition with MutableLiveData
|
|
||||||
*/
|
|
||||||
private final MutableLiveData<CameraPosition> result = new MutableLiveData<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for this class
|
|
||||||
*
|
|
||||||
* @param application Application
|
|
||||||
*/
|
|
||||||
public LocationPickerViewModel(@NonNull final Application application) {
|
|
||||||
super(application);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responses on camera position changing
|
|
||||||
*
|
|
||||||
* @param call Call<CameraPosition>
|
|
||||||
* @param response Response<CameraPosition>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onResponse(final @NotNull Call<CameraPosition> call,
|
|
||||||
final Response<CameraPosition> response) {
|
|
||||||
if (response.body() == null) {
|
|
||||||
result.setValue(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result.setValue(response.body());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(final @NotNull Call<CameraPosition> call, final @NotNull Throwable t) {
|
|
||||||
Timber.e(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets live CameraPosition
|
|
||||||
*
|
|
||||||
* @return MutableLiveData<CameraPosition>
|
|
||||||
*/
|
|
||||||
public MutableLiveData<CameraPosition> getResult() {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package fr.free.nrw.commons.LocationPicker
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import fr.free.nrw.commons.CameraPosition
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observes live camera position data
|
||||||
|
*/
|
||||||
|
class LocationPickerViewModel(
|
||||||
|
application: Application
|
||||||
|
): AndroidViewModel(application), Callback<CameraPosition> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapping CameraPosition with MutableLiveData
|
||||||
|
*/
|
||||||
|
val result = MutableLiveData<CameraPosition?>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responses on camera position changing
|
||||||
|
*
|
||||||
|
* @param call Call<CameraPosition>
|
||||||
|
* @param response Response<CameraPosition>
|
||||||
|
*/
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<CameraPosition>,
|
||||||
|
response: Response<CameraPosition>
|
||||||
|
) {
|
||||||
|
if(response.body() == null) {
|
||||||
|
result.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.value = response.body()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<CameraPosition>, t: Throwable) {
|
||||||
|
Timber.e(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue