From ea2d0cfa609c27003136a842ea912e4fe4b75ba7 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Fri, 16 Aug 2019 15:41:26 +0300 Subject: [PATCH] Remove unused classes, do not forget centerMapToPlace doesn't work on this branch --- app/build.gradle | 2 + .../nrw/commons/nearby/NearbyFragment.java | 723 ----------- .../nrw/commons/nearby/NearbyMapFragment.java | 1100 ----------------- .../nearby/NearbyNotificationCardView.java | 2 +- .../nrw/commons/nearby/PlaceRenderer.java | 2 +- 5 files changed, 4 insertions(+), 1825 deletions(-) delete mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyFragment.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java diff --git a/app/build.gradle b/app/build.gradle index 8ceb6b543..1e4c8d1b5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,6 +83,8 @@ dependencies { implementation "androidx.cardview:cardview:1.0.0" implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation "androidx.exifinterface:exifinterface:1.0.0" + //swipe_layout + implementation 'com.daimajia.swipelayout:library:1.2.0@aar' //metadata extractor implementation 'com.drewnoakes:metadata-extractor:2.11.0' } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyFragment.java deleted file mode 100644 index ec00043d6..000000000 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyFragment.java +++ /dev/null @@ -1,723 +0,0 @@ -package fr.free.nrw.commons.nearby; - -import android.Manifest; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.ProgressBar; - -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.snackbar.Snackbar; -import com.google.gson.Gson; - -import java.util.List; - -import javax.inject.Inject; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; -import butterknife.BindView; -import butterknife.ButterKnife; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.contributions.MainActivity; -import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.location.LocationServiceManager; -import fr.free.nrw.commons.location.LocationUpdateListener; -import fr.free.nrw.commons.utils.FragmentUtils; -import fr.free.nrw.commons.utils.NetworkUtils; -import fr.free.nrw.commons.utils.PermissionUtils; -import fr.free.nrw.commons.utils.ViewUtil; -import fr.free.nrw.commons.wikidata.WikidataEditListener; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import timber.log.Timber; - -import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION; -import static fr.free.nrw.commons.contributions.MainActivity.NEARBY_TAB_POSITION; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED; - -public class NearbyFragment extends CommonsDaggerSupportFragment - implements LocationUpdateListener, - WikidataEditListener.WikidataP18EditListener { - - @BindView(R.id.progressBar) - ProgressBar progressBar; - @BindView(R.id.bottom_sheet) - LinearLayout bottomSheet; - @BindView(R.id.bottom_sheet_details) - LinearLayout bottomSheetDetails; - @BindView(R.id.transparentView) - View transparentView; - @BindView(R.id.container_sheet) - FrameLayout frameLayout; - @BindView(R.id.loading_nearby_list) - ConstraintLayout loading_nearby_layout; - - @Inject - LocationServiceManager locationManager; - @Inject - NearbyController nearbyController; - @Inject - WikidataEditListener wikidataEditListener; - @Inject Gson gson; - - public 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(); - private Bundle bundle; - private BottomSheetBehavior bottomSheetBehavior; // Behavior for list bottom sheet - private BottomSheetBehavior bottomSheetBehaviorForDetails; // Behavior for details bottom sheet - - private LatLng curLatLng; - private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed - public View view; - private Snackbar snackbar; - - private LatLng lastKnownLocation; - private LatLng customLatLng; - - private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; - private BroadcastReceiver broadcastReceiver; - - private boolean onOrientationChanged = false; - private boolean populateForCurrentLocation = false; - private boolean isNetworkErrorOccured = false; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setRetainInstance(true); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_nearby, container, false); - ButterKnife.bind(this, view); - - /*// Resume the fragment if exist - resumeFragment();*/ - bundle = new Bundle(); - initBottomSheetBehaviour(); - this.view = view; - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - if (savedInstanceState != null) { - onOrientationChanged = true; - } - } - - /** - * Hide or expand bottom sheet according to states of all sheets - */ - public void listOptionMenuItemClicked() { - if(bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_COLLAPSED || bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_HIDDEN){ - bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN); - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); - }else if(bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED){ - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - } - } - - /** - * Resume fragments if they exists - */ - private void resumeFragment() { - // Find the retained fragment on activity restarts - nearbyMapFragment = getMapFragment(); - nearbyListFragment = getListFragment(); - addNetworkBroadcastReceiver(); - } - - /** - * Returns the map fragment added to child fragment manager previously, if exists. - */ - private NearbyMapFragment getMapFragment() { - return (NearbyMapFragment) getChildFragmentManager().findFragmentByTag(TAG_RETAINED_MAP_FRAGMENT); - } - - private void removeMapFragment() { - if (nearbyMapFragment != null) { - FragmentManager fm = getFragmentManager(); - fm.beginTransaction().remove(nearbyMapFragment).commit(); - nearbyMapFragment = null; - } - } - - - /** - * Returns the list fragment added to child fragment manager previously, if exists. - */ - private NearbyListFragment getListFragment() { - return (NearbyListFragment) getChildFragmentManager().findFragmentByTag(TAG_RETAINED_LIST_FRAGMENT); - } - - private void removeListFragment() { - if (nearbyListFragment != null) { - FragmentManager fm = getFragmentManager(); - fm.beginTransaction().remove(nearbyListFragment).commit(); - nearbyListFragment = null; - } - } - - /** - * Initialize bottom sheet behaviour (sheet for map list.) Set height 9/16 of all window. - * Add callback for bottom sheet changes, so that we can sync it with bottom sheet for details - * (sheet for nearby details) - */ - private void initBottomSheetBehaviour() { - - transparentView.setAlpha(0); - bottomSheet.getLayoutParams().height = getActivity().getWindowManager() - .getDefaultDisplay().getHeight() / 16 * 9; - bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); - bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { - - @Override - public void onStateChanged(View bottomSheet, int unusedNewState) { - prepareViewsForSheetPosition(); - } - - @Override - public void onSlide(View bottomSheet, float slideOffset) { - - } - }); - - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - bottomSheetBehaviorForDetails = BottomSheetBehavior.from(bottomSheetDetails); - bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN); - } - - /** - * Sets camera position, zoom level according to sheet positions - */ - private void prepareViewsForSheetPosition() { - // TODO - } - - @Override - public void onLocationChangedSignificantly(LatLng latLng) { - refreshView(LOCATION_SIGNIFICANTLY_CHANGED); - } - - @Override - public void onLocationChangedSlightly(LatLng latLng) { - refreshView(LOCATION_SLIGHTLY_CHANGED); - } - - - @Override - public void onLocationChangedMedium(LatLng latLng) { - // For nearby map actions, there are no differences between 500 meter location change (aka medium change) and slight change - refreshView(LOCATION_SLIGHTLY_CHANGED); - } - - @Override - public void onWikidataEditSuccessful() { - // Do not refresh nearby map if we are checking other areas with search this area button - if (nearbyMapFragment != null && !nearbyMapFragment.searchThisAreaModeOn) { - refreshView(MAP_UPDATED); - } - } - - /** - * This method should be the single point to load/refresh nearby places - * - * @param locationChangeType defines if location changed significantly or slightly - */ - private void refreshView(LocationServiceManager.LocationChangeType locationChangeType) { - Timber.d("Refreshing nearby places"); - if (lockNearbyView) { - return; - } - - if (!NetworkUtils.isInternetConnectionEstablished(getActivity())) { - hideProgressBar(); - return; - } - - registerLocationUpdates(); - LatLng lastLocation = locationManager.getLastLocation(); - - if (curLatLng != null && curLatLng.equals(lastLocation) - && !locationChangeType.equals(MAP_UPDATED)) { //refresh view only if location has changed - // Two exceptional cases to refresh nearby map manually. - if (!onOrientationChanged) { - return; - } - - } - curLatLng = lastLocation; - - if (locationChangeType.equals(PERMISSION_JUST_GRANTED)) { - curLatLng = lastKnownLocation; - } - - if (curLatLng == null) { - Timber.d("Skipping update of nearby places as location is unavailable"); - return; - } - - /* - onOrientation changed is true whenever activities orientation changes. After orientation - change we want to refresh map significantly, doesn't matter if location changed significantly - or not. Thus, we included onOrientationChanged boolean to if clause - */ - if (locationChangeType.equals(LOCATION_SIGNIFICANTLY_CHANGED) - || locationChangeType.equals(PERMISSION_JUST_GRANTED) - || locationChangeType.equals(MAP_UPDATED) - || onOrientationChanged) { - progressBar.setVisibility(View.VISIBLE); - - //TODO: This hack inserts curLatLng before populatePlaces is called (see #1440). Ideally a proper fix should be found - String gsonCurLatLng = gson.toJson(curLatLng); - bundle.clear(); - bundle.putString("CurLatLng", gsonCurLatLng); - - compositeDisposable.add(Observable.fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curLatLng, curLatLng, false, true)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlaces, - throwable -> { - Timber.d(throwable); - showErrorMessage(getString(R.string.error_fetching_nearby_places)); - progressBar.setVisibility(View.GONE); - })); - - } else if (locationChangeType - .equals(LOCATION_SLIGHTLY_CHANGED) && nearbyMapFragment != null) { - String gsonCurLatLng = gson.toJson(curLatLng); - bundle.putString("CurLatLng", gsonCurLatLng); - updateMapFragment(false,true, null, null); - } - - if (nearbyMapFragment != null && nearbyMapFragment.searchThisAreaButton != null) { - nearbyMapFragment.searchThisAreaButton.setVisibility(View.GONE); - } - } - - /** - * This method should be used with "Search this are button". This method will search nearby - * points around any custom location (target location when user clicked on search this area) - * button. It populates places for custom location. - * @param customLatLng Custom area which we will search around - */ - void refreshViewForCustomLocation(LatLng customLatLng, boolean refreshForCurrentLocation) { - if (customLatLng == null) { - // If null, return - return; - } - - populateForCurrentLocation = refreshForCurrentLocation; - this.customLatLng = customLatLng; - compositeDisposable.add(Observable.fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curLatLng, customLatLng, false, populateForCurrentLocation)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlacesFromCustomLocation, - throwable -> { - Timber.d(throwable); - showErrorMessage(getString(R.string.error_fetching_nearby_places)); - })); - - if (nearbyMapFragment != null) { - nearbyMapFragment.searchThisAreaButton.setVisibility(View.GONE); - } - } - - /** - * Populates places for custom location, should be used for finding nearby places around a - * location where you are not at. - * @param nearbyPlacesInfo This variable has place list information and distances. - */ - private void populatePlacesFromCustomLocation(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { - if (nearbyMapFragment != null) { - nearbyMapFragment.searchThisAreaButtonProgressBar.setVisibility(View.GONE); - } - - if (nearbyMapFragment != null && curLatLng != null) { - if (!populateForCurrentLocation) { - nearbyMapFragment.updateMapSignificantlyForCustomLocation(customLatLng, nearbyPlacesInfo.placeList); - } else { - updateMapFragment(true,true, customLatLng, nearbyPlacesInfo); - } - updateListFragmentForCustomLocation(nearbyPlacesInfo.placeList); - } - } - - /** - * Turns nearby place lists and boundary coordinates into gson and update map and list fragments - * accordingly - * @param nearbyPlacesInfo a variable holds both nearby place list and boundary coordinates - */ - private void populatePlaces(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { - Timber.d("Populating nearby places"); - List placeList = nearbyPlacesInfo.placeList; - LatLng[] boundaryCoordinates = nearbyPlacesInfo.boundaryCoordinates; - String gsonPlaceList = gson.toJson(placeList); - String gsonCurLatLng = gson.toJson(curLatLng); - String gsonBoundaryCoordinates = gson.toJson(boundaryCoordinates); - - if (placeList.size() == 0) { - ViewUtil.showShortSnackbar(view.findViewById(R.id.container), R.string.no_nearby); - } - - bundle.putString("PlaceList", gsonPlaceList); - bundle.putString("BoundaryCoord", gsonBoundaryCoordinates); - - // First time to init fragments - if (nearbyMapFragment == null) { - Timber.d("Init map fragment for the first time"); - lockNearbyView(true); - setMapFragment(); - setListFragment(); - hideProgressBar(); - lockNearbyView(false); - } else { - // There are fragments, just update the map and list - Timber.d("Map fragment already exists, just update the map and list"); - updateMapFragment(false,false, null, null); - updateListFragment(); - } - } - - /** - * Lock nearby view updates while updating map or list. Because we don't want new update calls - * when we already updating for old location update. - * @param lock true if we should lock nearby map - */ - private void lockNearbyView(boolean lock) { - if (lock) { - lockNearbyView = true; - locationManager.unregisterLocationManager(); - locationManager.removeLocationListener(this); - } else { - lockNearbyView = false; - registerLocationUpdates(); - locationManager.addLocationListener(this); - } - } - - /** - * Updates map fragment, - * For slight update: camera follows users location - * For significant update: nearby markers are removed and new markers added again - * Slight updates stop if user is checking another area of map - * - * @param updateViaButton search this area button is clicked - * @param isSlightUpdate Means no need to update markers, just follow user location with camera - * @param customLatLng Will be used for updates for other locations than users current location. - * Ie. when we use search this area feature - * @param nearbyPlacesInfo Includes nearby places list and boundary coordinates - */ - private void updateMapFragment(boolean updateViaButton, boolean isSlightUpdate, @Nullable LatLng customLatLng, @Nullable NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { - /* - 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 && !nearbyMapFragment.isCurrentLocationMarkerVisible() && !onOrientationChanged) { - Timber.d("Do not update the map, user is not seeing current location marker" + - " means they are checking around and moving on map"); - return; - } - - - if (nearbyMapFragment != null && curLatLng != 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 - && !nearbyMapFragment.checkingAround - && !nearbyMapFragment.searchThisAreaModeOn - && !onOrientationChanged - && (curLatLng.getLatitude() < nearbyMapFragment.boundaryCoordinates[0].getLatitude() - || curLatLng.getLatitude() > nearbyMapFragment.boundaryCoordinates[1].getLatitude() - || curLatLng.getLongitude() < nearbyMapFragment.boundaryCoordinates[2].getLongitude() - || curLatLng.getLongitude() > nearbyMapFragment.boundaryCoordinates[3].getLongitude())) { - // populate places - compositeDisposable.add(Observable.fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curLatLng, curLatLng, false, updateViaButton)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlaces, - throwable -> { - Timber.d(throwable); - showErrorMessage(getString(R.string.error_fetching_nearby_places)); - progressBar.setVisibility(View.GONE); - })); - nearbyMapFragment.setBundleForUpdates(bundle); - nearbyMapFragment.updateMapSignificantlyForCurrentLocation(); - updateListFragment(); - return; - } - - if (updateViaButton) { - nearbyMapFragment.updateMapSignificantlyForCustomLocation(customLatLng, nearbyPlacesInfo.placeList); - return; - } - - /* - If this is the map update just after orientation change, then it is not a slight update - anymore. We want to significantly update map after each orientation change - */ - if (onOrientationChanged) { - isSlightUpdate = false; - onOrientationChanged = false; - } - - if (isSlightUpdate) { - nearbyMapFragment.setBundleForUpdates(bundle); - nearbyMapFragment.updateMapSlightly(); - } else { - nearbyMapFragment.setBundleForUpdates(bundle); - nearbyMapFragment.updateMapSignificantlyForCurrentLocation(); - updateListFragment(); - } - } else { - lockNearbyView(true); - setMapFragment(); - setListFragment(); - hideProgressBar(); - lockNearbyView(false); - } - } - - /** - * Updates already existing list fragment with bundle includes nearby places and boundary - * coordinates - */ - private void updateListFragment() { - nearbyListFragment.setBundleForUpdates(bundle); - nearbyListFragment.updateNearbyListSignificantly(); - } - - /** - * Updates nearby list for custom location, will be used with search this area method. When you - * want to search for a place where you are not at. - * @param placeList List of places around your manually chosen target location from map. - */ - private void updateListFragmentForCustomLocation(List placeList) { - nearbyListFragment.updateNearbyListSignificantlyForCustomLocation(placeList); - } - - /** - * Calls fragment for map view. - */ - private void setMapFragment() { - FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction(); - nearbyMapFragment = new NearbyMapFragment(); - nearbyMapFragment.setArguments(bundle); - fragmentTransaction.replace(R.id.container, nearbyMapFragment, TAG_RETAINED_MAP_FRAGMENT); - fragmentTransaction.commitAllowingStateLoss(); - } - - /** - * Calls fragment for list view. - */ - private void setListFragment() { - loading_nearby_layout.setVisibility(View.GONE); - frameLayout.setVisibility(View.VISIBLE); - FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction(); - nearbyListFragment = new NearbyListFragment(); - nearbyListFragment.setArguments(bundle); - fragmentTransaction.replace(R.id.container_sheet, nearbyListFragment, TAG_RETAINED_LIST_FRAGMENT); - initBottomSheetBehaviour(); - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - fragmentTransaction.commitAllowingStateLoss(); - } - - /** - * Hides progress bar - */ - private void hideProgressBar() { - if (progressBar != null) { - progressBar.setVisibility(View.GONE); - } - } - - /** - * This method first checks if the location permissions has been granted and then register the location manager for updates. - */ - private void registerLocationUpdates() { - locationManager.registerLocationManager(); - } - - private void showErrorMessage(String message) { - ViewUtil.showLongToast(getActivity(), message); - } - - /** - * Adds network broadcast receiver to recognize connection established - */ - private void addNetworkBroadcastReceiver() { - if (!FragmentUtils.isFragmentUIActive(this)) { - return; - } - - if (broadcastReceiver != null) { - return; - } - - IntentFilter intentFilter = new IntentFilter(NETWORK_INTENT_ACTION); - - broadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getActivity() != null) { - if (NetworkUtils.isInternetConnectionEstablished(getActivity())) { - if (isNetworkErrorOccured) { - refreshView(LOCATION_SIGNIFICANTLY_CHANGED); - isNetworkErrorOccured = false; - } - - if (snackbar != null) { - snackbar.dismiss(); - snackbar = null; - } - } else { - if (snackbar == null) { - snackbar = Snackbar.make(view, R.string.no_internet, Snackbar.LENGTH_INDEFINITE); - if (nearbyMapFragment != null && nearbyMapFragment.searchThisAreaButton != null) { - nearbyMapFragment.searchThisAreaButton.setVisibility(View.GONE); - } - } - - isNetworkErrorOccured = true; - snackbar.show(); - } - } - } - }; - - getActivity().registerReceiver(broadcastReceiver, intentFilter); - } - - @Override - public void onResume() { - super.onResume(); - // Resume the fragment if exist - if (((MainActivity) getActivity()).viewPager.getCurrentItem() == NEARBY_TAB_POSITION) { - checkPermissionsAndPerformAction(this::resumeFragment); - } else { - resumeFragment(); - } - } - - /** - * Perform nearby operations on nearby tab selected - * @param onOrientationChanged pass orientation changed info to fragment - */ - public void onTabSelected(boolean onOrientationChanged) { - Timber.d("On nearby tab selected"); - this.onOrientationChanged = onOrientationChanged; - checkPermissionsAndPerformAction(this::performNearbyOperations); - } - - private void checkPermissionsAndPerformAction(Runnable runnable) { - PermissionUtils.checkPermissionsAndPerformAction(getActivity(), - Manifest.permission.ACCESS_FINE_LOCATION, - runnable, - () -> ((MainActivity) getActivity()).viewPager.setCurrentItem(CONTRIBUTIONS_TAB_POSITION), - R.string.location_permission_title, - R.string.location_permission_rationale_nearby); - } - - /** - * Calls nearby operations in required order. - */ - private void performNearbyOperations() { - locationManager.addLocationListener(this); - registerLocationUpdates(); - lockNearbyView = false; - addNetworkBroadcastReceiver(); - refreshView(LOCATION_SIGNIFICANTLY_CHANGED); - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - wikidataEditListener.setAuthenticationStateListener(this); - } - - @Override - public void onDestroy() { - super.onDestroy(); - wikidataEditListener.setAuthenticationStateListener(null); - } - - @Override - public void onDetach() { - super.onDetach(); - snackbar = null; - broadcastReceiver = null; - wikidataEditListener.setAuthenticationStateListener(null); - } - - @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(getActivity().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(); - - } - if (broadcastReceiver != null) { - getActivity().unregisterReceiver(broadcastReceiver); - broadcastReceiver = null; - } - - if (locationManager != null) { - locationManager.removeLocationListener(this); - locationManager.unregisterLocationManager(); - } - } - - - /** - * Centers the map in nearby fragment to a given place - * @param place is new center of the map - */ - public void centerMapToPlace(Place place) { - if (nearbyMapFragment != null) { - nearbyMapFragment.centerMapToPlace(place); - } - } - - public boolean isBottomSheetExpanded() { return bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED; - } -} - - diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java deleted file mode 100644 index 67c41c951..000000000 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ /dev/null @@ -1,1100 +0,0 @@ -package fr.free.nrw.commons.nearby; - -import android.animation.ObjectAnimator; -import android.animation.TypeEvaluator; -import android.animation.ValueAnimator; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.net.Uri; -import android.os.Bundle; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -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.PolygonOptions; -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.Style; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.MapboxMapOptions; -import com.mapbox.mapboxsdk.plugins.localization.LocalizationPlugin; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Named; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; -import butterknife.BindView; -import butterknife.ButterKnife; -import dagger.android.support.DaggerFragment; -import fr.free.nrw.commons.CommonsApplication; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.Utils; -import fr.free.nrw.commons.auth.LoginActivity; -import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; -import fr.free.nrw.commons.contributions.ContributionController; -import fr.free.nrw.commons.kvstore.JsonKvStore; -import fr.free.nrw.commons.utils.LocationUtils; -import fr.free.nrw.commons.utils.NetworkUtils; -import fr.free.nrw.commons.utils.UiUtils; -import fr.free.nrw.commons.utils.ViewUtil; -import timber.log.Timber; - -import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; -import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; - -public class NearbyMapFragment extends DaggerFragment { - - public MapView mapView; - private List baseMarkerOptions; - private fr.free.nrw.commons.location.LatLng curLatLng; - public fr.free.nrw.commons.location.LatLng[] boundaryCoordinates; - private List bookmarkedplaces; - - @BindView(R.id.bottom_sheet) - View bottomSheetList; - - @BindView(R.id.bottom_sheet_details) - View bottomSheetDetails; - - @BindView(R.id.wikipediaButton) - LinearLayout wikipediaButton; - - @BindView(R.id.wikidataButton) - LinearLayout wikidataButton; - - @BindView(R.id.directionsButton) - LinearLayout directionsButton; - - @BindView(R.id.commonsButton) - LinearLayout commonsButton; - - @BindView(R.id.bookmarkButton) - LinearLayout bookmarkButton; - - @BindView(R.id.fab_plus) - FloatingActionButton fabPlus; - - @BindView(R.id.fab_camera) - FloatingActionButton fabCamera; - - @BindView(R.id.fab_gallery) - FloatingActionButton fabGallery; - - @BindView(R.id.fab_recenter) - FloatingActionButton fabRecenter; - - @BindView(R.id.transparentView) - View transparentView; - - @BindView(R.id.description) - TextView description; - - @BindView(R.id.title) - TextView title; - - @BindView(R.id.category) - TextView distance; - - @BindView(R.id.icon) - ImageView icon; - - @BindView(R.id.bookmarkButtonImage) - ImageView bookmarkButtonImage; - - @BindView(R.id.wikidataButtonText) - TextView wikidataButtonText; - - @BindView(R.id.wikipediaButtonText) - TextView wikipediaButtonText; - - @BindView(R.id.commonsButtonText) - TextView commonsButtonText; - - @BindView(R.id.directionsButtonText) - TextView directionsButtonText; - - @BindView(R.id.search_this_area_button) - Button searchThisAreaButton; - - @BindView(R.id.search_this_area_button_progress_bar) - ProgressBar searchThisAreaButtonProgressBar; - - private BottomSheetBehavior bottomSheetListBehavior; - private BottomSheetBehavior bottomSheetDetailsBehavior; - - private boolean isFabOpen = false; - private Animation rotate_backward; - private Animation fab_close; - private Animation fab_open; - private Animation rotate_forward; - - private Place place; - private Marker selected; - private Marker currentLocationMarker; - public MapboxMap mapboxMap; - private PolygonOptions currentLocationPolygonOptions; - - - private boolean isBottomListSheetExpanded; - private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06; - private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04; - - public boolean searchThisAreaModeOn = false; - public boolean checkingAround = false; - - private Bundle bundleForUpdates;// Carry information from activity about changed nearby places and current location - private boolean searchedAroundCurrentLocation = true; - - @Inject @Named("default_preferences") JsonKvStore applicationKvStore; - @Inject BookmarkLocationsDao bookmarkLocationDao; - @Inject ContributionController controller; - @Inject Gson gson; - - private static final double ZOOM_LEVEL = 14f; - - public NearbyMapFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Timber.d("Nearby map fragment created"); - - Bundle bundle = this.getArguments(); - if (bundle != null) { - String gsonPlaceList = bundle.getString("PlaceList"); - String gsonLatLng = bundle.getString("CurLatLng"); - Type listType = new TypeToken>() { - }.getType(); - String gsonBoundaryCoordinates = bundle.getString("BoundaryCoord"); - List placeList = gson.fromJson(gsonPlaceList, listType); - Type curLatLngType = new TypeToken() { - }.getType(); - Type gsonBoundaryCoordinatesType = new TypeToken() {}.getType(); - curLatLng = gson.fromJson(gsonLatLng, curLatLngType); - baseMarkerOptions = NearbyController - .loadAttractionsFromLocationToBaseMarkerOptions(curLatLng, - placeList, - getActivity(), - bookmarkLocationDao.getAllBookmarksLocations()); - boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType); - } - if (curLatLng != null) { - Mapbox.getInstance(getActivity(), - getString(R.string.mapbox_commons_app_token)); - Mapbox.getTelemetry().setUserTelemetryRequestState(false); - } - setRetainInstance(true); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - Timber.d("onCreateView called"); - if (curLatLng != null) { - Timber.d("curLatLng found, setting up map view..."); - setupMapView(savedInstanceState); - } - setHasOptionsMenu(false); - - 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; - }); - } - - - /** - * Updates map slightly means it doesn't updates all nearby markers around. It just updates - * location tracker marker of user. - */ - public void updateMapSlightly() { - Timber.d("updateMapSlightly called, bundle is:"+ bundleForUpdates); - if (mapboxMap != null) { - if (bundleForUpdates != null) { - String gsonLatLng = bundleForUpdates.getString("CurLatLng"); - Type curLatLngType = new TypeToken() {}.getType(); - curLatLng = gson.fromJson(gsonLatLng, curLatLngType); - } - updateMapToTrackPosition(); - } - - } - - /** - * Updates map significantly means it updates nearby markers and location tracker marker. It is - * called when user is out of boundaries (south, north, east or west) of markers drawn by - * previous nearby call. - */ - public void updateMapSignificantlyForCurrentLocation() { - Timber.d("updateMapSignificantlyForCurrentLocation called, bundle is:"+ bundleForUpdates); - if (mapboxMap != null) { - if (bundleForUpdates != null) { - String gsonPlaceList = bundleForUpdates.getString("PlaceList"); - String gsonLatLng = bundleForUpdates.getString("CurLatLng"); - String gsonBoundaryCoordinates = bundleForUpdates.getString("BoundaryCoord"); - Type listType = new TypeToken>() {}.getType(); - List placeList = gson.fromJson(gsonPlaceList, listType); - Type curLatLngType = new TypeToken() {}.getType(); - Type gsonBoundaryCoordinatesType = new TypeToken() {}.getType(); - curLatLng = gson.fromJson(gsonLatLng, curLatLngType); - baseMarkerOptions = NearbyController - .loadAttractionsFromLocationToBaseMarkerOptions(curLatLng, - placeList, - getActivity(), - bookmarkLocationDao.getAllBookmarksLocations()); - boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType); - } - mapboxMap.clear(); - addCurrentLocationMarker(mapboxMap); - updateMapToTrackPosition(); - // We are trying to find nearby places around our current location, thus custom parameter is nullified - addNearbyMarkersToMapBoxMap(null); - } - } - - /** - * Initialize all views. - * TODO: View elements that are part of NearbyFragment should ideally be not accessed directly in NearbyMapFragment. - */ - private void initViews() { - Timber.d("initViews called"); - View view = ((NearbyFragment)getParentFragment()).view; - ButterKnife.bind(this, view); - - bottomSheetListBehavior = BottomSheetBehavior.from(bottomSheetList); - bottomSheetDetailsBehavior = BottomSheetBehavior.from(bottomSheetDetails); - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - bottomSheetDetails.setVisibility(View.VISIBLE); - - fab_open = AnimationUtils.loadAnimation(getParentFragment().getActivity(), R.anim.fab_open); - fab_close = AnimationUtils.loadAnimation(getParentFragment().getActivity(), R.anim.fab_close); - rotate_forward = AnimationUtils.loadAnimation(getParentFragment().getActivity(), R.anim.rotate_forward); - rotate_backward = AnimationUtils.loadAnimation(getParentFragment().getActivity(), R.anim.rotate_backward); - - - } - - /** - * Will be used for map vew updates for custom locations (ie. with search this area method). - * Clears the map, adds current location marker, adds nearby markers around custom location, - * re-enables map gestures which was locked during place load, remove progress bar. - * @param customLatLng custom location that we will search around - * @param placeList places around of custom location - */ - public void updateMapSignificantlyForCustomLocation(fr.free.nrw.commons.location.LatLng customLatLng, List placeList) { - List customBaseMarkerOptions = NearbyController - .loadAttractionsFromLocationToBaseMarkerOptions(curLatLng, // Curlatlang will be used to calculate distances - placeList, - getActivity(), - bookmarkLocationDao.getAllBookmarksLocations()); - mapboxMap.clear(); - // We are trying to find nearby places around our custom searched area, thus custom parameter is nonnull - addNearbyMarkersToMapBoxMap(customBaseMarkerOptions); - addCurrentLocationMarker(mapboxMap); - // Re-enable mapbox gestures on custom location markers load - mapboxMap.getUiSettings().setAllGesturesEnabled(true); - searchThisAreaButtonProgressBar.setVisibility(View.GONE); - } - // 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 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 ; - - // Do not update camera position is search this area mode on - if (!searchThisAreaModeOn) { - if (ViewUtil.isPortrait(getActivity())){ - position = new CameraPosition.Builder() - .target(isBottomListSheetExpanded ? - new LatLng(curMapBoxLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT, - curMapBoxLatLng.getLongitude()) - : curMapBoxLatLng ) // Sets the new camera position - .zoom(isBottomListSheetExpanded ? - ZOOM_LEVEL // zoom level is fixed when bottom sheet is expanded - :mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - }else { - position = new CameraPosition.Builder() - .target(isBottomListSheetExpanded ? - new LatLng(curMapBoxLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE, - curMapBoxLatLng.getLongitude()) - : curMapBoxLatLng ) // Sets the new camera position - .zoom(isBottomListSheetExpanded ? - ZOOM_LEVEL // zoom level is fixed when bottom sheet is expanded - :mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - } - - mapboxMap.animateCamera(CameraUpdateFactory - .newCameraPosition(position), 1000); - } - } - } - - /** - * Sets click listeners of FABs, and 2 bottom sheets - */ - private void setListeners() { - fabPlus.setOnClickListener(view -> { - if (applicationKvStore.getBoolean("login_skipped", false)) { - // prompt the user to login - new AlertDialog.Builder(getContext()) - .setMessage(R.string.login_alert_message) - .setPositiveButton(R.string.login, (dialog, which) -> { - // logout of the app - BaseLogoutListener logoutListener = new BaseLogoutListener(); - CommonsApplication app = (CommonsApplication) getActivity().getApplication(); - app.clearApplicationData(getContext(), logoutListener); - - }) - .show(); - }else { - animateFAB(isFabOpen); - } - }); - - bottomSheetDetails.setOnClickListener(view -> { - if (bottomSheetDetailsBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) { - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); - } else { - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - } - }); - - fabRecenter.setOnClickListener(view -> { - if (curLatLng != null) { - mapView.getMapAsync(mapboxMap -> { - CameraPosition position; - - if (ViewUtil.isPortrait(getActivity())){ - position = new CameraPosition.Builder() - .target(isBottomListSheetExpanded ? - new LatLng(curLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT, - curLatLng.getLongitude()) - : new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude(), 0)) // Sets the new camera position - .zoom(isBottomListSheetExpanded ? - ZOOM_LEVEL - :mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - }else { - position = new CameraPosition.Builder() - .target(isBottomListSheetExpanded ? - new LatLng(curLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE, - curLatLng.getLongitude()) - : new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude(), 0)) // Sets the new camera position - .zoom(isBottomListSheetExpanded ? - ZOOM_LEVEL - :mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - } - - mapboxMap.animateCamera(CameraUpdateFactory - .newCameraPosition(position), 1000); - - }); - } - }); - - 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); - } - } - - @Override - public void onSlide(@NonNull View bottomSheet, float slideOffset) { - - } - }); - - // Remove button text if they exceed 1 line or if internal layout has not been built - // Only need to check for directions button because it is the longest - if (directionsButtonText.getLineCount() > 1 || directionsButtonText.getLineCount() == 0) { - wikipediaButtonText.setVisibility(View.GONE); - wikidataButtonText.setVisibility(View.GONE); - commonsButtonText.setVisibility(View.GONE); - directionsButtonText.setVisibility(View.GONE); - } - title.setOnLongClickListener(view -> { - Utils.copy("place",title.getText().toString(),getContext()); - Toast.makeText(getContext(),"Text copied to clipboard",Toast.LENGTH_SHORT).show(); - return true; - } - ); - title.setOnClickListener(view -> { - if (bottomSheetDetailsBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) { - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); - } else { - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - } - }); - } - - /** - * Sets up map view of first time it created, it passes MapBoxMap options and style assets. - * @param savedInstanceState bundle coming from Nearby Fragment - */ - private void setupMapView(Bundle savedInstanceState) { - Timber.d("setupMapView called"); - boolean isDarkTheme = applicationKvStore.getBoolean("theme", false); - MapboxMapOptions options = new MapboxMapOptions() - .compassGravity(Gravity.BOTTOM | Gravity.LEFT) - .compassMargins(new int[]{12, 0, 0, 24}) - .styleUrl(isDarkTheme ? Style.DARK : Style.OUTDOORS) - .logoEnabled(true) - .attributionEnabled(true) - .camera(new CameraPosition.Builder() - .target(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude())) - .zoom(ZOOM_LEVEL) - .build()); - - if (!getParentFragment().getActivity().isFinishing()) { - mapView = new MapView(getParentFragment().getActivity(), options); - // create map - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(mapboxMap -> { - LocalizationPlugin localizationPlugin = new LocalizationPlugin(mapView, mapboxMap); - - try { - localizationPlugin.matchMapLanguageWithDeviceDefault(); - } catch (RuntimeException exception) { - Timber.d(exception.toString()); - } - - NearbyMapFragment.this.mapboxMap = mapboxMap; - addMapMovementListeners(); - updateMapSignificantlyForCurrentLocation(); - }); - } - } - - /** - * Adds map movement listener to understand swiping with fingers. So that we can display search - * this area button to search nearby places for other locations - */ - private void addMapMovementListeners() { - - mapboxMap.addOnCameraMoveListener(() -> { - - if (NearbyController.currentLocation != null) { // If our nearby markers are calculated at least once - - if (searchThisAreaButton.getVisibility() == View.GONE && NetworkUtils.isInternetConnectionEstablished(getContext())) { - searchThisAreaButton.setVisibility(View.VISIBLE); - } - double distance = mapboxMap.getCameraPosition().target - .distanceTo(new LatLng(NearbyController.currentLocation.getLatitude() - , NearbyController.currentLocation.getLongitude())); - - if (distance > NearbyController.searchedRadius*1000*3/4) { //Convert to meter, and compare if our distance is bigger than 3/4 or our searched area - checkingAround = true; - if (!searchThisAreaModeOn) { // If we are changing mode, then change click action - searchThisAreaModeOn = true; - searchThisAreaButton.setOnClickListener(view -> { - searchThisAreaModeOn = true; - // Lock map operations during search this area operation - mapboxMap.getUiSettings().setAllGesturesEnabled(false); - searchThisAreaButtonProgressBar.setVisibility(View.VISIBLE); - searchThisAreaButton.setVisibility(View.GONE); - searchedAroundCurrentLocation = false; - ((NearbyFragment)getParentFragment()) - .refreshViewForCustomLocation(LocationUtils - .mapBoxLatLngToCommonsLatLng(mapboxMap.getCameraPosition().target), false); - }); - } - - } else { - checkingAround = false; - if (searchThisAreaModeOn) { - searchThisAreaModeOn = false; // This flag will help us to understand should we folor users location or not - searchThisAreaButton.setOnClickListener(view -> { - searchThisAreaModeOn = true; - // Lock map operations during search this area operation - mapboxMap.getUiSettings().setAllGesturesEnabled(false); - searchThisAreaButtonProgressBar.setVisibility(View.GONE); - fabRecenter.callOnClick(); - searchThisAreaButton.setVisibility(View.GONE); - searchedAroundCurrentLocation = true; - ((NearbyFragment)getParentFragment()) - .refreshViewForCustomLocation(LocationUtils - .mapBoxLatLngToCommonsLatLng(mapboxMap.getCameraPosition().target), true); - }); - } - if (searchedAroundCurrentLocation) { - searchThisAreaButton.setVisibility(View.GONE); - } - } - } - }); - } - - /** - * onLogoutComplete is called after shared preferences and data stored in local database are cleared. - */ - private class BaseLogoutListener implements CommonsApplication.LogoutListener { - @Override - public void onLogoutComplete() { - Timber.d("Logout complete callback received."); - Intent nearbyIntent = new Intent( getActivity(), LoginActivity.class); - nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(nearbyIntent); - getActivity().finish(); - } - } - - /** - * Adds a marker for the user's current position. Adds a - * circle which uses the accuracy * 2, to draw a circle - * which represents the user's position with an accuracy - * of 95%. - * - * Should be called only on creation of mapboxMap, there - * is other method to update markers location with users - * move. - */ - private void addCurrentLocationMarker(MapboxMap mapboxMap) { - Timber.d("addCurrentLocationMarker is called"); - 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())); - currentLocationMarkerOptions.setIcon(icon); // Set custom icon - - currentLocationMarker = mapboxMap.addMarker(currentLocationMarkerOptions); - - List circle = createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(), - curLatLng.getAccuracy() * 2, 100); - - currentLocationPolygonOptions = new PolygonOptions() - .addAll(circle) - .strokeColor(Color.parseColor("#55000000")) - .fillColor(Color.parseColor("#11000000")); - mapboxMap.addPolygon(currentLocationPolygonOptions); - } - - /** - * Checks whether current location marker is in visible region or not - * @return true if point is in region - */ - public boolean isCurrentLocationMarkerVisible() { - if (currentLocationMarker != null) { - return mapboxMap.getProjection().getVisibleRegion().latLngBounds.contains(currentLocationMarker.getPosition()); - } else { - return false; - } - } - - /** - * Adds markers for nearby places to mapbox map - */ - private void addNearbyMarkersToMapBoxMap(@Nullable List customNearbyBaseMarker) { - List baseMarkerOptions; - Timber.d("addNearbyMarkersToMapBoxMap is called"); - if (customNearbyBaseMarker != null) { - // If we try to update nearby points for a custom location choosen from map (we are not there) - baseMarkerOptions = customNearbyBaseMarker; - } else { - // If we try to display nearby markers around our curret location - baseMarkerOptions = this.baseMarkerOptions; - } - mapboxMap.addMarkers(baseMarkerOptions); - mapboxMap.setOnInfoWindowCloseListener(marker -> { - if (marker == selected) { - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - } - }); - mapView.getMapAsync(mapboxMap -> { - mapboxMap.addMarkers(baseMarkerOptions); - fabRecenter.setVisibility(View.VISIBLE); - 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. - * Takes the center latitude, center longitude of the circle, - * the radius in meter and the number of nodes of the circle. - * - * @return List List of LatLng points of the circle. - */ - private List createCircleArray( - double centerLat, double centerLong, float radius, int nodes) { - List circle = new ArrayList<>(); - float radiusKilometer = radius / 1000; - double radiusLong = radiusKilometer - / (111.320 * Math.cos(centerLat * Math.PI / 180)); - double radiusLat = radiusKilometer / 110.574; - - for (int i = 0; i < nodes; i++) { - double theta = ((double) i / (double) nodes) * (2 * Math.PI); - double nodeLongitude = centerLong + radiusLong * Math.cos(theta); - double nodeLatitude = centerLat + radiusLat * Math.sin(theta); - circle.add(new LatLng(nodeLatitude, nodeLongitude)); - } - return circle; - } - - /** - * If nearby details bottom sheet state is collapsed: show fab plus - * If nearby details bottom sheet state is expanded: show fab plus - * If nearby details bottom sheet state is hidden: hide all fabs - * @param bottomSheetState - */ - 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(); - if (this.getView() != null) { - this.getView().requestFocus(); - } - break; - } - } - - /** - * Hides all fabs - */ - 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, ((NearbyFragment)getParentFragment()).view.findViewById(R.id.bottom_sheet_details).getId()); - fabPlus.show(); - - addAnchorToSmallFABs(fabGallery, ((NearbyFragment)getParentFragment()).view.findViewById(R.id.empty_view).getId()); - - addAnchorToSmallFABs(fabCamera, ((NearbyFragment)getParentFragment()).view.findViewById(R.id.empty_view1).getId()); - } - - - /* - * Add anchors 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 anchors 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); - } - - /** - * Same bottom sheet carries information for all nearby places, so we need to pass information - * (title, description, distance and links) to view on nearby marker click - * @param place Place of clicked nearby marker - */ - private void passInfoToSheet(Place place) { - this.place = place; - updateBookmarkButtonImage(this.place); - - bookmarkButton.setOnClickListener(view -> { - boolean isBookmarked = bookmarkLocationDao.updateBookmarkLocation(this.place); - updateBookmarkButtonImage(this.place); - updateMarker(isBookmarked, this.place); - }); - - wikipediaButton.setVisibility(place.hasWikipediaLink()?View.VISIBLE:View.GONE); - wikipediaButton.setOnClickListener(view -> openWebView(this.place.siteLinks.getWikipediaLink())); - - wikidataButton.setVisibility(place.hasWikidataLink()?View.VISIBLE:View.GONE); - wikidataButton.setOnClickListener(view -> openWebView(this.place.siteLinks.getWikidataLink())); - - directionsButton.setOnClickListener(view -> Utils.handleGeoCoordinates(getActivity(), this.place.getLocation())); - - commonsButton.setVisibility(this.place.hasCommonsLink()?View.VISIBLE:View.GONE); - commonsButton.setOnClickListener(view -> openWebView(this.place.siteLinks.getCommonsLink())); - - icon.setImageResource(this.place.getLabel().getIcon()); - - title.setText(this.place.name); - distance.setText(this.place.distance); - description.setText(this.place.getLongDescription()); - - fabCamera.setOnClickListener(view -> { - if (fabCamera.isShown()) { - Timber.d("Camera button tapped. Place: %s", this.place.toString()); - storeSharedPrefs(); - controller.initiateCameraPick(getActivity()); - } - }); - - fabGallery.setOnClickListener(view -> { - if (fabGallery.isShown()) { - Timber.d("Gallery button tapped. Place: %s", this.place.toString()); - storeSharedPrefs(); - controller.initiateGalleryPick(getActivity(), false); - } - }); - } - - public void updateBookmarkButtonImage(Place place) { - int bookmarkIcon; - if (bookmarkLocationDao.findBookmarkLocation(place)) { - bookmarkIcon = R.drawable.ic_round_star_filled_24px; - } else { - bookmarkIcon = R.drawable.ic_round_star_border_24px; - } - if (bookmarkButtonImage != null) { - bookmarkButtonImage.setImageResource(bookmarkIcon); - } - } - - void storeSharedPrefs() { - Timber.d("Store place object %s", place.toString()); - applicationKvStore.putJson(PLACE_OBJECT, place); - } - - private void openWebView(Uri link) { - Utils.handleWebUrl(getContext(), link); - } - - /** - * Starts animation of fab plus (turning on opening) and other FABs - * @param isFabOpen state of FAB buttons, open when clicked on fab button, closed on other click - */ - private void animateFAB(boolean isFabOpen) { - this.isFabOpen = !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; - } - } - - /** - * Hides camera and gallery FABs, turn back plus FAB - * @param 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; - } - } - - /** - * This bundle is sent whenever and update for nearby map comes, not for recreation, for updates - */ - public void setBundleForUpdates(Bundle bundleForUpdates) { - this.bundleForUpdates = bundleForUpdates; - } - - @Override - public void onStart() { - if (mapView != null) { - mapView.onStart(); - } - super.onStart(); - } - - @Override - public void onPause() { - if (mapView != null) { - mapView.onPause(); - } - bookmarkedplaces = bookmarkLocationDao.getAllBookmarksLocations(); - super.onPause(); - } - - @Override - public void onResume() { - super.onResume(); - if (mapView != null) { - mapView.onResume(); - } - if (mapboxMap != null) { - mapboxMap.getUiSettings().setAllGesturesEnabled(true); - } - searchThisAreaModeOn = false; - checkingAround = false; - searchedAroundCurrentLocation = true; - boundaryCoordinates = null; - initViews(); - setListeners(); - transparentView.setClickable(false); - transparentView.setAlpha(0); - if (bookmarkedplaces != null) { - for (Place place : bookmarkedplaces) { - if (!bookmarkLocationDao.findBookmarkLocation(place)) { - updateMarker(false, place); - } - } - } - } - - @Override - public void onStop() { - if (mapView != null) { - mapView.onStop(); - } - super.onStop(); - } - - @Override - public void onDestroyView() { - if (mapView != null) { - mapView.onDestroy(); - } - selected = null; - currentLocationMarker = null; - - super.onDestroyView(); - } - - private static class LatLngEvaluator implements TypeEvaluator { - // 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; - } - } - - /** - * Centers the map in nearby fragment to a given place - * @param place is new center of the map - */ - public void centerMapToPlace(Place place) { - mapView.getMapAsync(mapboxMap1 -> { - CameraPosition position = new CameraPosition.Builder() - .target(isBottomListSheetExpanded ? - new LatLng(place.location.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE, - place.getLocation().getLongitude()) - : new LatLng(place.getLocation().getLatitude(), place.getLocation().getLongitude(), 0)) // Sets the new camera position - .zoom(isBottomListSheetExpanded ? - ZOOM_LEVEL - :mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000); - }); - } - - - public void updateMarker(boolean isBookmarked, Place place) { - - VectorDrawableCompat vectorDrawable; - if (isBookmarked) { - vectorDrawable = VectorDrawableCompat.create( - getContext().getResources(), R.drawable.ic_custom_bookmark_marker, getContext().getTheme() - ); - } - else { - vectorDrawable = VectorDrawableCompat.create( - getContext().getResources(), R.drawable.ic_custom_map_marker, getContext().getTheme() - ); - } - for(Marker marker: mapboxMap.getMarkers()){ - if(marker.getTitle()!=null && marker.getTitle().equals(place.getName())){ - - Bitmap icon = UiUtils.getBitmap(vectorDrawable); - - String distance = formatDistanceBetween(curLatLng, place.location); - place.setDistance(distance); - - NearbyBaseMarker nearbyBaseMarker = new NearbyBaseMarker(); - nearbyBaseMarker.title(place.name); - nearbyBaseMarker.position( - new com.mapbox.mapboxsdk.geometry.LatLng( - place.location.getLatitude(), - place.location.getLongitude())); - nearbyBaseMarker.place(place); - nearbyBaseMarker.icon(IconFactory.getInstance(getContext()) - .fromBitmap(icon)); - marker.setIcon(IconFactory.getInstance(getContext()).fromBitmap(icon)); - } - } - - } - - -} - diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNotificationCardView.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNotificationCardView.java index 30acedb8a..21eaafb0c 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNotificationCardView.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNotificationCardView.java @@ -90,7 +90,7 @@ public class NearbyNotificationCardView extends SwipableCardView { m.viewPager.setCurrentItem(NEARBY_TAB_POSITION); // Center the map to the place - ((NearbyFragment) m.contributionsActivityPagerAdapter.getItem(NEARBY_TAB_POSITION)).centerMapToPlace(place); + //((NearbyFragment) m.contributionsActivityPagerAdapter.getItem(NEARBY_TAB_POSITION)).centerMapToPlace(place); }); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java index 9470aa71f..4d202cbf2 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java @@ -117,7 +117,7 @@ public class PlaceRenderer extends Renderer { } } if (onBookmarkClick == null) { - ((NearbyFragment) fragment.getParentFragment()).centerMapToPlace(place); + //((NearbyFragment) fragment.getParentFragment()).centerMapToPlace(place); } }; view.setOnClickListener(listener);