/** * Copyright (C) 2016 eBusiness Information * * This file is part of OSM Contributor. * * OSM Contributor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OSM Contributor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OSM Contributor. If not, see <http://www.gnu.org/licenses/>. */ package io.jawg.osmcontributor.ui.fragments; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.location.Location; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import com.github.clans.fab.FloatingActionButton; import com.github.clans.fab.FloatingActionMenu; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.PolylineOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; import io.jawg.osmcontributor.BuildConfig; import io.jawg.osmcontributor.OsmTemplateApplication; import io.jawg.osmcontributor.R; import io.jawg.osmcontributor.model.entities.Note; import io.jawg.osmcontributor.model.entities.Poi; import io.jawg.osmcontributor.model.entities.PoiNodeRef; import io.jawg.osmcontributor.model.entities.PoiType; import io.jawg.osmcontributor.model.entities.PoiTypeTag; import io.jawg.osmcontributor.model.entities.Way; import io.jawg.osmcontributor.model.events.PleaseDeletePoiEvent; import io.jawg.osmcontributor.model.events.PleaseRemoveArpiMarkerEvent; import io.jawg.osmcontributor.rest.events.SyncDownloadWayEvent; import io.jawg.osmcontributor.rest.events.SyncFinishUploadPoiEvent; import io.jawg.osmcontributor.rest.events.error.SyncConflictingNodeErrorEvent; import io.jawg.osmcontributor.rest.events.error.SyncDownloadRetrofitErrorEvent; import io.jawg.osmcontributor.rest.events.error.SyncNewNodeErrorEvent; import io.jawg.osmcontributor.rest.events.error.SyncUnauthorizedEvent; import io.jawg.osmcontributor.rest.events.error.SyncUploadNoteRetrofitErrorEvent; import io.jawg.osmcontributor.rest.events.error.SyncUploadRetrofitErrorEvent; import io.jawg.osmcontributor.rest.events.error.TooManyRequestsEvent; import io.jawg.osmcontributor.ui.activities.EditPoiActivity; import io.jawg.osmcontributor.ui.adapters.PoiTypePickerAdapter; import io.jawg.osmcontributor.ui.dialogs.NoteCommentDialogFragment; import io.jawg.osmcontributor.ui.events.edition.PleaseApplyNodeRefPositionChange; import io.jawg.osmcontributor.ui.events.edition.PleaseApplyPoiPositionChange; import io.jawg.osmcontributor.ui.events.map.AddressFoundEvent; import io.jawg.osmcontributor.ui.events.map.ChangeMapModeEvent; import io.jawg.osmcontributor.ui.events.map.EditionWaysLoadedEvent; import io.jawg.osmcontributor.ui.events.map.LastUsePoiTypeLoaded; import io.jawg.osmcontributor.ui.events.map.MapCenterValueEvent; import io.jawg.osmcontributor.ui.events.map.NewNoteCreatedEvent; import io.jawg.osmcontributor.ui.events.map.NewPoiTypeSelected; import io.jawg.osmcontributor.ui.events.map.OnBackPressedMapEvent; import io.jawg.osmcontributor.ui.events.map.PleaseApplyNoteFilterEvent; import io.jawg.osmcontributor.ui.events.map.PleaseApplyPoiFilter; import io.jawg.osmcontributor.ui.events.map.PleaseChangePoiPosition; import io.jawg.osmcontributor.ui.events.map.PleaseChangeToolbarColor; import io.jawg.osmcontributor.ui.events.map.PleaseChangeValuesDetailNoteFragmentEvent; import io.jawg.osmcontributor.ui.events.map.PleaseChangeValuesDetailPoiFragmentEvent; import io.jawg.osmcontributor.ui.events.map.PleaseCreateNoTagPoiEvent; import io.jawg.osmcontributor.ui.events.map.PleaseDeletePoiFromMapEvent; import io.jawg.osmcontributor.ui.events.map.PleaseDisplayTutorialEvent; import io.jawg.osmcontributor.ui.events.map.PleaseDuplicatePoiEvent; import io.jawg.osmcontributor.ui.events.map.PleaseGiveMeMapCenterEvent; import io.jawg.osmcontributor.ui.events.map.PleaseInitializeArpiEvent; import io.jawg.osmcontributor.ui.events.map.PleaseInitializeNoteDrawerEvent; import io.jawg.osmcontributor.ui.events.map.PleaseLoadEditWaysEvent; import io.jawg.osmcontributor.ui.events.map.PleaseLoadLastUsedPoiType; import io.jawg.osmcontributor.ui.events.map.PleaseOpenEditionEvent; import io.jawg.osmcontributor.ui.events.map.PleaseShowMeArpiglEvent; import io.jawg.osmcontributor.ui.events.map.PleaseSwitchMapStyleEvent; import io.jawg.osmcontributor.ui.events.map.PleaseSwitchWayEditionModeEvent; import io.jawg.osmcontributor.ui.events.map.PleaseToggleArpiEvent; import io.jawg.osmcontributor.ui.events.map.PleaseToggleDrawer; import io.jawg.osmcontributor.ui.events.map.PleaseToggleDrawerLock; import io.jawg.osmcontributor.ui.events.map.PoiNoTypeCreated; import io.jawg.osmcontributor.ui.events.note.ApplyNewCommentFailedEvent; import io.jawg.osmcontributor.ui.listeners.MapboxListener; import io.jawg.osmcontributor.ui.listeners.OnZoomAnimationFinishedListener; import io.jawg.osmcontributor.ui.listeners.OsmAnimatorUpdateListener; import io.jawg.osmcontributor.ui.listeners.OsmCreationAnimatorUpdateListener; import io.jawg.osmcontributor.ui.managers.tutorial.AddPoiTutoManager; import io.jawg.osmcontributor.ui.managers.tutorial.TutorialManager; import io.jawg.osmcontributor.ui.presenters.MapFragmentPresenter; import io.jawg.osmcontributor.ui.utils.BitmapHandler; import io.jawg.osmcontributor.ui.utils.MapMode; import io.jawg.osmcontributor.ui.utils.views.ButteryProgressBar; import io.jawg.osmcontributor.ui.utils.views.LocationMarkerViewAdapter; import io.jawg.osmcontributor.ui.utils.views.map.marker.LocationMarkerView; import io.jawg.osmcontributor.ui.utils.views.map.marker.LocationMarkerViewOptions; import io.jawg.osmcontributor.ui.utils.views.map.marker.WayMarker; import io.jawg.osmcontributor.ui.utils.views.map.marker.WayMarkerOptions; import io.jawg.osmcontributor.utils.ConfigManager; import io.jawg.osmcontributor.utils.FlavorUtils; import io.jawg.osmcontributor.utils.OsmAnswers; import io.jawg.osmcontributor.utils.StringUtils; import io.jawg.osmcontributor.utils.ways.Geocoder; import io.jawg.osmcontributor.utils.ways.LevelBar; import timber.log.Timber; public class MapFragment extends Fragment { private static final String LOCATION = "location"; private static final String ZOOM_LEVEL = "zoom level"; private static final String LEVEL = "level"; private static final String MARKER_TYPE = "MARKER_TYPE"; public static final String CREATION_MODE = "CREATION_MODE"; public static final String POI_TYPE_ID = "POI_TYPE_ID"; public static final String SELECTED_MARKER_ID = "SELECTED_MARKER_ID"; public static final String HIDDEN_POI_TYPE = "HIDDEN_POI_TYPE"; private static final String DISPLAY_OPEN_NOTES = "DISPLAY_OPEN_NOTES"; private static final String DISPLAY_CLOSED_NOTES = "DISPLAY_CLOSED_NOTES"; private LocationMarkerView markerSelected = null; private WayMarker wayMarkerSelected = null; // when resuming app we use this id to re-select the good marker private Long markerSelectedId = -1L; private MapMode mapMode = MapMode.DEFAULT; private boolean isMenuLoaded = false; private boolean pleaseSwitchToPoiSelected = false; private Map<Long, LocationMarkerViewOptions<Poi>> markersPoi; private Map<Long, LocationMarkerViewOptions<Note>> markersNotes; private Map<Long, WayMarkerOptions> markersNodeRef; private int maxPoiType; private PoiType poiTypeSelected; private ButteryProgressBar progressBar; private MapFragmentPresenter presenter; private MapboxListener mapboxListener; private MapboxMap mapboxMap; private Unbinder unbinder; private Location lastLocation; @Inject BitmapHandler bitmapHandler; @Inject EventBus eventBus; @BindView(R.id.mapview) MapView mapView; @BindView(R.id.poi_detail_wrapper) RelativeLayout poiDetailWrapper; @BindView(R.id.progressbar) RelativeLayout progressbarWrapper; @BindView(R.id.note_detail_wrapper) RelativeLayout noteDetailWrapper; @BindView(R.id.osm_copyright) TextView osmCopyrightTextView; @Inject SharedPreferences sharedPreferences; @Inject ConfigManager configManager; @BindView(R.id.zoom_level) TextView zoomLevelText; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); OsmTemplateApplication application = ((OsmTemplateApplication) getActivity().getApplication()); application.getOsmTemplateComponent().inject(this); measureMaxPoiType(); presenter = new MapFragmentPresenter(this); mapboxListener = new MapboxListener(this, eventBus); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_map, container, false); markersPoi = new HashMap<>(); markersNotes = new HashMap<>(); markersNodeRef = new HashMap<>(); unbinder = ButterKnife.bind(this, rootView); setHasOptionsMenu(true); zoomVectorial = configManager.getZoomVectorial(); if (savedInstanceState != null) { currentLevel = savedInstanceState.getDouble(LEVEL); selectedMarkerType = LocationMarkerView.MarkerType.values()[savedInstanceState.getInt(MARKER_TYPE)]; } instantiateProgressBar(); instantiateMapView(savedInstanceState); instantiateLevelBar(); instantiatePoiTypePicker(); instantiateCopyrightBar(); eventBus.register(this); eventBus.register(presenter); return rootView; } private void instantiateCopyrightBar() { osmCopyrightTextView.setText(Html.fromHtml(getString(R.string.osm_copyright))); } private void instantiateProgressBar() { progressBar = new ButteryProgressBar(getActivity()); progressBar.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 24)); RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); p.addRule(RelativeLayout.BELOW, R.id.poi_type_value_wrapper); progressBar.setVisibility(View.GONE); progressBar.setLayoutParams(p); progressbarWrapper.addView(progressBar); } private void instantiateLevelBar() { Drawable d = ContextCompat.getDrawable(getActivity(), R.drawable.level_thumb); levelBar.setThumb(d); levelBar.setDrawableHeight(d.getIntrinsicHeight()); levelBar.setLevel(currentLevel); levelBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { Timber.v("onProgressChanged"); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } private void instantiateMapBox(Bundle savedInstanceState) { // LocationView settings mapboxMap.getMyLocationViewSettings().setAccuracyAlpha(0); mapboxMap.getMyLocationViewSettings().setForegroundTintColor(ContextCompat.getColor(getActivity(), R.color.colorPrimaryTransparent)); // Set the map center and zoom to the saved values or use the default values getUserLocation(); CameraPosition.Builder cameraBuilder = new CameraPosition.Builder(); if (savedInstanceState == null) { double lat = sharedPreferences.getFloat("latitude", 0); double lon = sharedPreferences.getFloat("longitude", 0); if (lat != 0 && lon != 0) { cameraBuilder.target(new LatLng(lat, lon)).zoom(11); } } else { cameraBuilder.target((LatLng) savedInstanceState.getParcelable(LOCATION)) .zoom(savedInstanceState.getFloat(ZOOM_LEVEL)); } mapboxMap.setCameraPosition(cameraBuilder.build()); eventBus.post(new PleaseInitializeArpiEvent()); presenter.setForceRefreshPoi(); presenter.setForceRefreshNotes(); presenter.loadPoisIfNeeded(); eventBus.post(new PleaseInitializeNoteDrawerEvent(displayOpenNotes, displayClosedNotes)); if (poiTypePickerAdapter != null) { poiTypePickerAdapter.setExpertMode(sharedPreferences.getBoolean(getString(R.string.shared_prefs_expert_mode), false)); } mapboxListener.listen(mapboxMap, mapView); mapboxMap.getMarkerViewManager().addMarkerViewAdapter(new LocationMarkerViewAdapter(getActivity().getApplicationContext())); } private void instantiateMapView(final Bundle savedInstanceState) { if (mapView != null) { mapMode = MapMode.DEFAULT; mapView.onCreate(savedInstanceState); mapView.setStyleUrl(BuildConfig.MAP_STYLE); mapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(MapboxMap mapboxMap) { MapFragment.this.mapboxMap = mapboxMap; instantiateMapBox(savedInstanceState); } }); } } private void getUserLocation() { mapboxMap.setMyLocationEnabled(true); lastLocation = mapboxMap.getMyLocation(); if (lastLocation != null) { mapboxMap.setCameraPosition(new CameraPosition.Builder().target(new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude())).zoom(configManager.getDefaultZoom()).build()); } else { mapboxMap.setCameraPosition(new CameraPosition.Builder().target(configManager.getDefaultCenter()).zoom(configManager.getDefaultZoom()).build()); } } private void measureMaxPoiType() { DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float toolbarSize = getResources().getDimension(R.dimen.abc_action_bar_default_height_material) / displayMetrics.density; float dpHeight = displayMetrics.heightPixels / displayMetrics.density; // 80 size of one floating btn in dp // 180 size of the menu btn plus location btn // -1 because we always have note maxPoiType = (int) ((dpHeight - toolbarSize - 160) / 80) - 1; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (savedInstanceState != null) { Integer creationModeInt = savedInstanceState.getInt(CREATION_MODE); savePoiTypeId = savedInstanceState.getLong(POI_TYPE_ID); markerSelectedId = savedInstanceState.getLong(SELECTED_MARKER_ID, -1); mapMode = MapMode.values()[creationModeInt]; if (mapMode == MapMode.DETAIL_NOTE || mapMode == MapMode.DETAIL_POI || mapMode == MapMode.POI_POSITION_EDITION) { mapMode = MapMode.DEFAULT; } else if (mapMode == MapMode.NODE_REF_POSITION_EDITION) { mapMode = MapMode.WAY_EDITION; } long[] hidden = savedInstanceState.getLongArray(HIDDEN_POI_TYPE); if (hidden != null) { for (long l : hidden) { poiTypeHidden.add(l); } } displayOpenNotes = savedInstanceState.getBoolean(DISPLAY_OPEN_NOTES); displayClosedNotes = savedInstanceState.getBoolean(DISPLAY_CLOSED_NOTES); } } @Override public void onResume() { super.onResume(); mapView.onResume(); if (mapboxMap != null) { switchMode(MapMode.DEFAULT); presenter.setForceRefreshPoi(); presenter.setForceRefreshNotes(); presenter.loadPoisIfNeeded(); nextTuto(2); double lat = sharedPreferences.getFloat("latitude", 0); double lon = sharedPreferences.getFloat("longitude", 0); if (lat != 0 && lon != 0) { CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(lat, lon)) .zoom(mapboxMap.getCameraPosition().zoom) .build(); mapboxMap.setCameraPosition(cameraPosition); } else { getUserLocation(); } } } @Override public void onPause() { super.onPause(); mapView.onPause(); if (mapboxMap != null) { LatLng location = mapboxMap.getCameraPosition().target; sharedPreferences.edit().putFloat("latitude", (float) location.getLatitude()).apply(); sharedPreferences.edit().putFloat("longitude", (float) location.getLongitude()).apply(); mapboxMap.setMyLocationEnabled(false); } if (valueAnimator != null) { valueAnimator.cancel(); valueAnimator.removeAllListeners(); valueAnimator.removeAllUpdateListeners(); } } @Override public void onDestroy() { super.onDestroy(); if (mapView != null) { mapView.onDestroy(); } // Clear bitmapHandler even if activity leaks. bitmapHandler = null; } @Override public void onDestroyView() { super.onDestroyView(); progressBar.removeListeners(); unbinder.unbind(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); outState.putParcelable(LOCATION, mapboxMap.getCameraPosition().target); outState.putFloat(ZOOM_LEVEL, getZoomLevel()); outState.putInt(CREATION_MODE, mapMode.ordinal()); outState.putLong(POI_TYPE_ID, poiTypeSelected == null ? -1 : poiTypeSelected.getId()); outState.putDouble(LEVEL, currentLevel); outState.putBoolean(DISPLAY_OPEN_NOTES, displayOpenNotes); outState.putBoolean(DISPLAY_CLOSED_NOTES, displayClosedNotes); int markerType = markerSelected == null ? LocationMarkerView.MarkerType.NONE.ordinal() : markerSelected.getType().ordinal(); outState.putInt(MARKER_TYPE, markerType); if (markerSelected != null) { switch (markerSelected.getType()) { case POI: markerSelectedId = ((Poi) markerSelected.getRelatedObject()).getId(); break; case NODE_REF: markerSelectedId = ((PoiNodeRef) markerSelected.getRelatedObject()).getId(); break; case NOTE: markerSelectedId = ((Note) markerSelected.getRelatedObject()).getId(); break; } } else { markerSelectedId = -1L; } outState.putLong(SELECTED_MARKER_ID, markerSelectedId); long[] hidden = new long[poiTypeHidden.size()]; int index = 0; for (Long value : poiTypeHidden) { hidden[index] = value; index++; } outState.putLongArray(HIDDEN_POI_TYPE, hidden); } @Override public void onLowMemory() { super.onLowMemory(); mapView.onLowMemory(); } /*----------------------------------------------------------- * ACTIONBAR *---------------------------------------------------------*/ private MenuItem filter; private MenuItem confirm; private MenuItem downloadArea; private boolean homeActionBtnMode = true; @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); displayHomeButton(true); //show the home button confirm = menu.findItem(R.id.action_confirm_position); downloadArea = menu.findItem(R.id.action_download_area); filter = menu.findItem(R.id.action_filter_drawer); // the menu has too be created because we modify it depending on mode isMenuLoaded = true; if (pleaseSwitchToPoiSelected) { pleaseSwitchToPoiSelected = false; mapboxListener.onLocationMarkerClick(markerSelected); } else { switchMode(mapMode); } } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_confirm_position: confirmPosition(); break; case R.id.action_download_area: onDownloadZoneClick(); break; case android.R.id.home: if (homeActionBtnMode) { eventBus.post(new PleaseToggleDrawer()); } else { eventBus.post(new OnBackPressedMapEvent()); } break; default: super.onOptionsItemSelected(item); break; } return true; } private void confirmPosition() { LatLng newPoiPosition; LatLng pos; switch (mapMode) { case POI_CREATION: if (getZoomLevel() < zoomVectorial) { changeMapZoomSmooth(15d); } createPoi(); break; case NOTE_CREATION: pos = mapboxMap.getCameraPosition().target; NoteCommentDialogFragment dialog = NoteCommentDialogFragment.newInstance(pos.getLatitude(), pos.getLongitude()); dialog.show(getActivity().getFragmentManager(), "dialog"); break; case POI_POSITION_EDITION: Poi poi = (Poi) markerSelected.getRelatedObject(); newPoiPosition = mapboxMap.getCameraPosition().target; eventBus.post(new PleaseApplyPoiPositionChange(newPoiPosition, poi.getId())); markerSelected.setPosition(newPoiPosition); markerSelected.setIcon(IconFactory.getInstance(getActivity()).fromBitmap(bitmapHandler.getMarkerBitmap(poi.getType(), Poi.computeState(false, false, true)))); poi.setUpdated(true); mapboxMap.updateMarker(markerSelected); switchMode(MapMode.DETAIL_POI); break; case NODE_REF_POSITION_EDITION: PoiNodeRef poiNodeRef = wayMarkerSelected.getPoiNodeRef(); newPoiPosition = mapboxMap.getCameraPosition().target; eventBus.post(new PleaseApplyNodeRefPositionChange(newPoiPosition, poiNodeRef.getId())); wayMarkerSelected.setPosition(newPoiPosition); wayMarkerSelected.setIcon(IconFactory.getInstance(getActivity()).fromBitmap(bitmapHandler.getNodeRefBitmap(PoiNodeRef.State.SELECTED))); removePolyline(editionPolyline); switchMode(MapMode.WAY_EDITION); break; case DETAIL_POI: getActivity().finish(); break; default: break; } } //if is back will show the back arrow, else will display the menu icon private void toggleBackButton(boolean homeActionBtnMode) { ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); if (actionBar != null) { this.homeActionBtnMode = homeActionBtnMode; if (homeActionBtnMode) { actionBar.setHomeAsUpIndicator(R.drawable.menu); } else { actionBar.setHomeAsUpIndicator(R.drawable.back); } } } private void displayHomeButton(boolean show) { AppCompatActivity appCompatActivity = (AppCompatActivity) getActivity(); if (appCompatActivity != null) { ActionBar actionBar = appCompatActivity.getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(show); } } } @Subscribe(threadMode = ThreadMode.MAIN) public void onOnBackPressedMapEvent(OnBackPressedMapEvent event) { Timber.d("Received event OnBackPressedMap"); TutorialManager.forceDisplayAddTuto = false; switch (mapMode) { case POI_POSITION_EDITION: mapboxMap.updateMarker(markerSelected); switchMode(MapMode.DEFAULT); break; case NODE_REF_POSITION_EDITION: switchMode(MapMode.WAY_EDITION); removePolyline(editionPolyline); break; case WAY_EDITION: switchMode(MapMode.DEFAULT); break; case DETAIL_POI: case DETAIL_NOTE: case POI_CREATION: case NOTE_CREATION: case TYPE_PICKER: switchMode(MapMode.DEFAULT); InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mapView.getWindowToken(), 0); break; case ARPIGL: switchMode(MapMode.DEFAULT); eventBus.post(new PleaseToggleArpiEvent()); break; default: getActivity().finish(); break; } } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseGiveMeMapCenterEvent(PleaseGiveMeMapCenterEvent event) { eventBus.post(new MapCenterValueEvent(mapboxMap.getCameraPosition().target)); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseSwitchMapStyleEvent(PleaseSwitchMapStyleEvent event) { if (mapboxMap != null) { if (event.isSatelliteMode()) { mapboxMap.setStyleUrl("mapbox://styles/mapbox/satellite-streets-v9"); } else { mapboxMap.setStyleUrl("asset://mapnik.json"); } } } public void switchMode(MapMode mode) { mapMode = mode; Bitmap bitmap; switchToolbarMode(mapMode); editNodeRefPosition.setVisibility(View.GONE); progressBar.setVisibility(View.GONE); final MapMode.MapModeProperties properties = mode.getProperties(); if (properties.isUnSelectIcon()) { unselectMarker(); } showFloatingButtonAddPoi(properties.isShowAddPoiFab()); displayPoiTypePicker(); displayPoiDetailBanner(properties.isShowPoiBanner()); displayNoteDetailBanner(properties.isShowNodeBanner()); switch (mode) { case DETAIL_POI: break; case DETAIL_NOTE: break; case TYPE_PICKER: eventBus.post(new PleaseLoadLastUsedPoiType()); break; case POI_CREATION: animationPoiCreation(); break; case NOTE_CREATION: noteSelected(); animationPoiCreation(); break; case POI_POSITION_EDITION: // This marker is being moved bitmap = bitmapHandler.getMarkerBitmap(((Poi) markerSelected.getRelatedObject()).getType(), Poi.computeState(false, true, false)); creationPin.setImageBitmap(bitmap); break; case NODE_REF_POSITION_EDITION: wayCreationPin.setImageBitmap(bitmapHandler.getNodeRefBitmap(PoiNodeRef.State.MOVING)); break; case WAY_EDITION: if (getZoomLevel() < zoomVectorial) { changeMapZoomSmooth(configManager.getZoomVectorial()); } loadAreaForEdition(); break; default: poiTypeSelected = null; poiTypeEditText.setText(""); clearAllNodeRef(); switchToolbarMode(mapMode); displayHomeButton(true); unselectMarker(); break; } //the marker is displayed at the end of the animation creationPin.setVisibility(properties.isShowCreationPin() ? View.VISIBLE : View.GONE); wayCreationPin.setVisibility(properties.isShowCreationPin() ? View.VISIBLE : View.GONE); if (addPoiFloatingMenu.isOpened()) { addPoiFloatingMenu.toggle(true); } } private void switchToolbarMode(MapMode mode) { MapMode.MapModeProperties properties = mode.getProperties(); confirm.setVisible(properties.isShowConfirmBtn()); downloadArea.setVisible(properties.isShowDownloadArea()); filter.setVisible(!properties.isLockDrawer()); toggleBackButton(properties.isMenuBtn()); getActivity().setTitle(properties.getTitle(getActivity())); eventBus.post(new PleaseChangeToolbarColor(properties.isEditColor())); eventBus.post(new PleaseToggleDrawerLock(properties.isLockDrawer())); } /** * Show or hide the {@link ButteryProgressBar}. * * @param show Whether we should show the progressBar. */ public void showProgressBar(boolean show) { progressBar.setVisibility(show ? View.VISIBLE : View.GONE); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseSwitchWayEditionModeEvent(PleaseSwitchWayEditionModeEvent event) { if (getZoomLevel() < zoomVectorial) { changeMapZoomSmooth(zoomVectorial, new OnZoomAnimationFinishedListener() { @Override public void onZoomAnimationFinished() { switchMode(MapMode.WAY_EDITION); downloadAreaForEdition(); } }); eventBus.post(new PleaseToggleDrawer()); } else { switchMode(MapMode.WAY_EDITION); downloadAreaForEdition(); } } /** * Download data from backend. If we are in {@link MapMode#WAY_EDITION}, download ways * and if not, download Pois. */ public void onDownloadZoneClick() { if (mapMode == MapMode.WAY_EDITION) { downloadAreaForEdition(); } else { // If flavor Store, allow the download only if the zoom > 18 if (!FlavorUtils.isStore() || getZoomLevel() >= 16) { presenter.downloadAreaPoisAndNotes(); Toast.makeText(getActivity(), R.string.download_in_progress, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getActivity(), R.string.zoom_more, Toast.LENGTH_SHORT).show(); } } } private void defaultMap() { presenter.setForceRefreshPoi(); presenter.setForceRefreshNotes(); presenter.loadPoisIfNeeded(); switchMode(MapMode.DEFAULT); } public void unselectMarker() { if (markerSelected != null) { Bitmap bitmap = null; switch (markerSelected.getType()) { case POI: Poi poi = (Poi) markerSelected.getRelatedObject(); bitmap = bitmapHandler.getMarkerBitmap(poi.getType(), Poi.computeState(false, false, poi.getUpdated())); break; case NOTE: bitmap = bitmapHandler.getNoteBitmap(Note.computeState((Note) markerSelected.getRelatedObject(), false, false)); break; default: break; } if (bitmap != null) { markerSelected.setIcon(IconFactory.getInstance(getActivity()).fromBitmap(bitmap)); } markerSelectedId = -1L; markerSelected = null; } } public void unselectWayMarker() { if (wayMarkerSelected != null) { wayMarkerSelected.setIcon(IconFactory.getInstance(getActivity()).fromBitmap(bitmapHandler.getNodeRefBitmap(PoiNodeRef.State.NONE))); } } public void removeAllNotes() { for (LocationMarkerViewOptions<Note> markerNote : markersNotes.values()) { removeMarkerView(markerNote); } markersNotes.clear(); } public void removeAllPoiMarkers() { for (Long markerId : markersPoi.keySet()) { removeMarkerView(markersPoi.get(markerId)); } markersPoi.clear(); } public void removePoiMarkersNotIn(List<Long> poiIds) { Set<Long> idsToRemove = new HashSet<>(markersPoi.keySet()); idsToRemove.removeAll(poiIds); for (Long id : idsToRemove) { removeMarkerView(markersPoi.get(id)); } markersPoi.keySet().removeAll(idsToRemove); } public void removeNoteMarkersNotIn(List<Long> noteIds) { Set<Long> idsToRemove = new HashSet<>(markersNotes.keySet()); idsToRemove.removeAll(noteIds); for (Long id : idsToRemove) { removeMarkerView(markersNotes.get(id)); } markersNotes.keySet().removeAll(idsToRemove); } private void removeMarkerView(LocationMarkerViewOptions marker) { if (marker != null) { mapboxMap.removeMarker(marker.getMarker()); Object poi = marker.getMarker().getRelatedObject(); eventBus.post(new PleaseRemoveArpiMarkerEvent(poi)); } } private void removeWayMarker(WayMarkerOptions markerOptions) { mapboxMap.removeMarker(markerOptions.getMarker()); } private void removePolyline(PolylineOptions polylineOptions) { if (polylineOptions != null) { mapboxMap.removePolyline(polylineOptions.getPolyline()); } } public void reselectMarker() { // if I found the marker selected I click on it if (markerSelected != null) { if (isMenuLoaded) { mapboxListener.onLocationMarkerClick(markerSelected); } else { pleaseSwitchToPoiSelected = true; } } } public void addPoi(LocationMarkerViewOptions<Poi> marker) { markersPoi.put(marker.getMarker().getRelatedObject().getId(), marker); addPoiMarkerDependingOnFilters(marker); } public void addNote(LocationMarkerViewOptions<Note> marker) { markersNotes.put(marker.getMarker().getRelatedObject().getId(), marker); // add the note to the map addNoteMarkerDependingOnFilters(marker); } public LocationMarkerViewOptions<Note> getNote(Long id) { return markersNotes.get(id); } /*----------------------------------------------------------- * WAY EDITION *---------------------------------------------------------*/ @BindView(R.id.edit_way_point_position) FloatingActionButton editNodeRefPosition; @BindView(R.id.level_bar) LevelBar levelBar; @BindView(R.id.way_pin) ImageButton wayCreationPin; private boolean isVectorial = false; private double currentLevel = 0; private LocationMarkerView.MarkerType selectedMarkerType = LocationMarkerView.MarkerType.NONE; private int zoomVectorial; private Map<Long, PolylineOptions> polylinesWays = new HashMap<>(); private PolylineOptions editionPolyline; @OnClick(R.id.edit_way_point_position) public void editNodeRefPosition() { buildEditionPolygon(); switchMode(MapMode.NODE_REF_POSITION_EDITION); wayCreationPin.setVisibility(View.VISIBLE); hideMarker(wayMarkerSelected); } private void buildEditionPolygon() { // Current selected poiNodeRef PoiNodeRef currentPoiNodeRef = wayMarkerSelected.getPoiNodeRef(); // Polyline related to this poiNodeRef PolylineOptions currentPolyline = polylinesWays.get(currentPoiNodeRef.getId()); // Item of the poiNodeRef in the polilyne int indexOfPoiNodeRef = currentPolyline .getPoints() .indexOf(new LatLng(currentPoiNodeRef.getLatitude(), currentPoiNodeRef.getLongitude())); LatLng previousPoint = currentPolyline.getPoints().get(indexOfPoiNodeRef == 0 ? indexOfPoiNodeRef + 1 : indexOfPoiNodeRef - 1); LatLng nextPoint = currentPolyline.getPoints().get(indexOfPoiNodeRef == currentPolyline.getPoints().size() - 1 ? indexOfPoiNodeRef - 1 : indexOfPoiNodeRef + 1); editionPolyline = new PolylineOptions() .add(previousPoint, currentPolyline.getPoints().get(indexOfPoiNodeRef), nextPoint) .alpha(0.4f) .width(1.8f) .color(Color.parseColor("#F57C00")); mapboxMap.addPolyline(editionPolyline); } //get data from overpass private void downloadAreaForEdition() { if (getZoomLevel() >= zoomVectorial) { progressBar.setVisibility(View.VISIBLE); LatLngBounds viewLatLngBounds = getViewLatLngBounds(); eventBus.post(new SyncDownloadWayEvent(viewLatLngBounds)); } else { Toast.makeText(getActivity(), getString(R.string.zoom_to_edit), Toast.LENGTH_SHORT).show(); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onEditionWaysLoadedEvent(EditionWaysLoadedEvent event) { if (event.isRefreshFromOverpass()) { progressBar.setVisibility(View.GONE); } if (mapMode == MapMode.WAY_EDITION) { Timber.d("Showing nodesRefs : " + event.getWays().size()); clearAllNodeRef(); updateVectorials(event.getWays(), event.getLevels()); } } public void onCameraChangeUpdatePolyline() { if (editionPolyline != null) { List<LatLng> points = editionPolyline.getPoints(); points.set(1, mapboxMap.getCameraPosition().target); removePolyline(editionPolyline); editionPolyline = new PolylineOptions() .addAll(points) .alpha(0.4f) .width(1.8f) .color(Color.parseColor("#F57C00")); mapboxMap.addPolyline(editionPolyline); } } public void updateVectorials(Set<Way> ways, TreeSet<Double> levels) { for (Way way : ways) { mapboxMap.addPolyline(way.getPolylineOptions()); for (PoiNodeRef poiNodeRef : way.getPoiNodeRefs()) { WayMarkerOptions wayMarkerOptions = new WayMarkerOptions() .position(poiNodeRef.getPosition()) .poiNodeRef(poiNodeRef) .icon(IconFactory.getInstance(getActivity()).fromBitmap(bitmapHandler.getNodeRefBitmap(PoiNodeRef.State.NONE))); addWayMarker(wayMarkerOptions); markersNodeRef.put(poiNodeRef.getId(), wayMarkerOptions); polylinesWays.put(poiNodeRef.getId(), way.getPolylineOptions()); } } } //get data from the bd private void loadAreaForEdition() { if (getZoomLevel() >= zoomVectorial) { eventBus.post(new PleaseLoadEditWaysEvent(false)); } else { Toast.makeText(getActivity(), getString(R.string.zoom_to_edit), Toast.LENGTH_SHORT).show(); } } private void clearAllNodeRef() { for (WayMarkerOptions locationMarker : markersNodeRef.values()) { removeWayMarker(locationMarker); } for (PolylineOptions polylineOptions : polylinesWays.values()) { removePolyline(polylineOptions); } markersNodeRef.clear(); polylinesWays.clear(); } public void selectWayMarker() { editNodeRefPosition.setVisibility(View.VISIBLE); wayMarkerSelected.setIcon(IconFactory.getInstance(getActivity()).fromBitmap(bitmapHandler.getNodeRefBitmap(PoiNodeRef.State.SELECTED))); changeMapPositionSmooth(wayMarkerSelected.getPosition()); } /*----------------------------------------------------------- * POI CREATION *---------------------------------------------------------*/ @BindView(R.id.hand) ImageView handImageView; @BindView(R.id.add_poi_few_values) FloatingActionMenu addPoiFloatingMenu; @BindView(R.id.floating_btn_wrapper) RelativeLayout floatingBtnWrapper; @BindView(R.id.pin) ImageButton creationPin; ValueAnimator valueAnimator; private void createPoi() { LatLng pos = mapboxMap.getCameraPosition().target; boolean needTagEdition = false; for (PoiTypeTag poiTypeTag : poiTypeSelected.getTags()) { if (StringUtils.isEmpty(poiTypeTag.getValue())) { needTagEdition = true; break; } } if (needTagEdition) { Intent intent = new Intent(getActivity(), EditPoiActivity.class); intent.putExtra(EditPoiActivity.CREATION_MODE, true); intent.putExtra(EditPoiActivity.POI_LAT, pos.getLatitude()); intent.putExtra(EditPoiActivity.POI_LNG, pos.getLongitude()); intent.putExtra(EditPoiActivity.POI_LEVEL, isVectorial ? currentLevel : 0d); intent.putExtra(EditPoiActivity.POI_TYPE, poiTypeSelected.getId()); switchMode(MapMode.DEFAULT); getActivity().startActivityForResult(intent, EditPoiActivity.EDIT_POI_ACTIVITY_CODE); } else { eventBus.post(new PleaseCreateNoTagPoiEvent(poiTypeSelected, pos, isVectorial ? currentLevel : 0d)); switchMode(MapMode.DEFAULT); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onPoiNoTypeCreated(PoiNoTypeCreated event) { presenter.setForceRefreshPoi(); presenter.loadPoisIfNeeded(); } private void animationPoiCreation() { handImageView.setVisibility(View.VISIBLE); valueAnimator = ValueAnimator.ofFloat(0, OsmCreationAnimatorUpdateListener.STEPS_CENTER_ANIMATION); valueAnimator.setDuration(1000); valueAnimator.addListener(new OsmCreationAnimatorUpdateListener(mapboxMap, handImageView, getActivity())); valueAnimator.addUpdateListener(new OsmCreationAnimatorUpdateListener(mapboxMap, handImageView, getActivity())); valueAnimator.start(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onNewPoiTypeSelected(NewPoiTypeSelected event) { Timber.d("Received event NewPoiTypeSelected"); poiTypeSelected(event.getPoiType()); switchMode(MapMode.POI_CREATION); } private void poiTypeSelected(PoiType poiType) { poiTypeTextView.setText(poiType.getName()); poiTypeSelected = poiType; savePoiTypeId = 0; Bitmap bitmap; bitmap = bitmapHandler.getMarkerBitmap(poiType, Poi.computeState(false, true, false)); if (poiTypeHidden.contains(poiType.getId())) { poiTypeHidden.remove(poiType.getId()); applyPoiFilter(); } if (presenter.getNumberOfPoiTypes() > maxPoiType) { editPoiTypeBtn.setVisibility(View.VISIBLE); } creationPin.setImageBitmap(bitmap); creationPin.setVisibility(View.VISIBLE); } private void noteSelected() { Bitmap bitmap = bitmapHandler.getNoteBitmap(Note.computeState(null, false, true)); creationPin.setImageBitmap(bitmap); creationPin.setVisibility(View.VISIBLE); poiTypeSelected = null; } private void showFloatingButtonAddPoi(boolean show) { //animation show and hide if (show) { if (floatingBtnWrapper.getVisibility() == View.GONE) { Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_up_detail); floatingBtnWrapper.startAnimation(bottomUp); floatingBtnWrapper.setVisibility(View.VISIBLE); } } else { if (floatingBtnWrapper.getVisibility() == View.VISIBLE) { Animation upDown = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_down_detail); floatingBtnWrapper.startAnimation(upDown); floatingBtnWrapper.setVisibility(View.GONE); } } //which kind of add to display depending on screen size // if in store flavor show the spinner addPoiFloatingMenu.setVisibility(View.VISIBLE); addPoiFloatingMenu.setOnMenuButtonClickListener(new View.OnClickListener() { @Override public void onClick(View view) { easterEgg(); addPoiFloatingMenu.toggle(true); nextTuto(0); } }); } public void loadPoiTypeFloatingBtn() { if (addPoiFloatingMenu != null) { addPoiFloatingMenu.removeAllMenuButtons(); } FloatingActionButton floatingActionButton; //add note if (!FlavorUtils.isBus()) { floatingActionButton = new FloatingActionButton(getActivity()); floatingActionButton.setLabelText(getString(R.string.note)); floatingActionButton.setColorPressed(ContextCompat.getColor(getActivity(), R.color.material_green_700)); floatingActionButton.setColorNormal(ContextCompat.getColor(getActivity(), R.color.material_green_500)); floatingActionButton.setButtonSize(FloatingActionButton.SIZE_MINI); floatingActionButton.setImageDrawable(bitmapHandler.getIconWhite(null)); floatingActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { switchMode(MapMode.NOTE_CREATION); addPoiFloatingMenu.close(true); } }); addPoiFloatingMenu.addMenuButton(floatingActionButton); } if (presenter.getNumberOfPoiTypes() <= maxPoiType) { //add a btn per poiType for (final PoiType poiType : presenter.getPoiTypes()) { floatingActionButton = new FloatingActionButton(getActivity()); floatingActionButton.setLabelText(poiType.getName()); floatingActionButton.setColorPressed(ContextCompat.getColor(getActivity(), R.color.material_blue_grey_800)); floatingActionButton.setColorNormal(ContextCompat.getColor(getActivity(), R.color.material_blue_500)); floatingActionButton.setButtonSize(FloatingActionButton.SIZE_MINI); floatingActionButton.setImageDrawable(bitmapHandler.getIconWhite(poiType)); floatingActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (configManager.hasPoiAddition()) { switchMode(MapMode.POI_CREATION); poiTypeSelected(poiType); addPoiFloatingMenu.close(true); } else { Toast.makeText(getActivity(), getResources().getString(R.string.point_modification_forbidden), Toast.LENGTH_SHORT).show(); } } }); addPoiFloatingMenu.addMenuButton(floatingActionButton); } } else { // add a btn for all poiTypes floatingActionButton = new FloatingActionButton(getActivity()); floatingActionButton.setLabelText(getResources().getString(R.string.add_poi)); floatingActionButton.setColorPressed(ContextCompat.getColor(getActivity(), R.color.material_blue_grey_800)); floatingActionButton.setColorNormal(ContextCompat.getColor(getActivity(), R.color.material_blue_500)); floatingActionButton.setButtonSize(FloatingActionButton.SIZE_MINI); floatingActionButton.setImageDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.fab_poi)); floatingActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (configManager.hasPoiAddition()) { switchMode(MapMode.TYPE_PICKER); } else { Toast.makeText(getActivity(), getResources().getString(R.string.point_modification_forbidden), Toast.LENGTH_SHORT).show(); } } }); addPoiFloatingMenu.addMenuButton(floatingActionButton); } } public void loadPoiTypeSpinner() { poiTypePickerAdapter.addAll(presenter.getPoiTypes()); if (savePoiTypeId != 0) { for (PoiType poiType : presenter.getPoiTypes()) { if (poiType.getId().equals(savePoiTypeId)) { poiTypeSelected(poiType); } } } } /*----------------------------------------------------------- * POI EDITION *---------------------------------------------------------*/ @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseOpenEditionEvent(PleaseOpenEditionEvent event) { Timber.d("Received event PleaseOpenEdition"); Intent intent = new Intent(getActivity(), EditPoiActivity.class); intent.putExtra(EditPoiActivity.CREATION_MODE, false); intent.putExtra(EditPoiActivity.POI_ID, ((Poi) markerSelected.getRelatedObject()).getId()); startActivity(intent); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseChangePoiPosition(PleaseChangePoiPosition event) { Timber.d("Received event PleaseChangePoiPosition"); if (configManager.hasPoiModification()) { switchMode(MapMode.POI_POSITION_EDITION); creationPin.setVisibility(View.GONE); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, OsmAnimatorUpdateListener.STEPS_CENTER_ANIMATION); valueAnimator.setDuration(900); valueAnimator.addUpdateListener(new OsmAnimatorUpdateListener(mapboxMap.getCameraPosition().target, markerSelected.getPosition(), mapboxMap)); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { creationPin.setVisibility(View.VISIBLE); hideMarker(markerSelected); } }); valueAnimator.start(); } else { Toast.makeText(getActivity(), getResources().getString(R.string.point_modification_forbidden), Toast.LENGTH_SHORT).show(); } } /*----------------------------------------------------------- * POI DELETION *---------------------------------------------------------*/ @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseDeletePoiFromMapEvent(PleaseDeletePoiFromMapEvent event) { Poi poi = (Poi) markerSelected.getRelatedObject(); poi.setToDelete(true); removeMarkerView(markersPoi.get(poi.getId())); markersPoi.remove(poi.getId()); eventBus.post(new PleaseDeletePoiEvent(poi)); OsmAnswers.localPoiAction(poi.getType().getTechnicalName(), "delete"); switchMode(MapMode.DEFAULT); } /*----------------------------------------------------------- * POI DUPLICATION *---------------------------------------------------------*/ @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseDuplicatePoiFromMapEvent(PleaseDuplicatePoiEvent event) { Poi poi = (Poi) markerSelected.getRelatedObject(); poiTypeSelected(poi.getType()); mapboxMap.setCameraPosition( new CameraPosition.Builder().target(new LatLng(poi.getLatitude(), poi.getLongitude())).build()); switchMode(MapMode.POI_CREATION); } /*----------------------------------------------------------- * POI DETAIL *---------------------------------------------------------*/ private void displayPoiDetailBanner(boolean display) { if (display) { if (markerSelected != null) { Poi poi = (Poi) markerSelected.getRelatedObject(); eventBus.post(new PleaseChangeValuesDetailPoiFragmentEvent(poi)); } if (poiDetailWrapper.getVisibility() != View.VISIBLE) { Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_up_detail); poiDetailWrapper.startAnimation(bottomUp); poiDetailWrapper.setVisibility(View.VISIBLE); } } else { if (poiDetailWrapper.getVisibility() == View.VISIBLE) { Animation upDown = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_down_detail); poiDetailWrapper.startAnimation(upDown); poiDetailWrapper.setVisibility(View.GONE); } } } /*----------------------------------------------------------- * NOTE DETAIL *---------------------------------------------------------*/ private void displayNoteDetailBanner(boolean display) { if (display) { if (markerSelected != null && !markerSelected.getType().equals(LocationMarkerView.MarkerType.POI)) { eventBus.post(new PleaseChangeValuesDetailNoteFragmentEvent( (Note) markerSelected.getRelatedObject())); } if (noteDetailWrapper.getVisibility() != View.VISIBLE) { Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_up_detail); noteDetailWrapper.startAnimation(bottomUp); noteDetailWrapper.setVisibility(View.VISIBLE); } } else { if (noteDetailWrapper.getVisibility() == View.VISIBLE) { Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_down_detail); noteDetailWrapper.startAnimation(bottomUp); noteDetailWrapper.setVisibility(View.GONE); } } } /*----------------------------------------------------------- * MAP UTILS *---------------------------------------------------------*/ @BindView(R.id.localisation) FloatingActionButton floatingButtonLocalisation; @OnClick(R.id.localisation) public void setOnPosition() { Timber.d("Center position on user location"); getUserLocation(); if (lastLocation != null) { mapboxMap.setCameraPosition(new CameraPosition.Builder().target(new LatLng(lastLocation)).build()); } else { Toast.makeText(getActivity(), getResources().getString(R.string.location_not_found), Toast.LENGTH_SHORT).show(); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onChangeMapModeEvent(ChangeMapModeEvent event) { switchMode(event.getMapMode()); } public void setZoomLevelText(String zoom) { zoomLevelText.setText(zoom); } public LocationMarkerViewOptions getMarkerOptions(LocationMarkerView.MarkerType markerType, Long id) { switch (markerType) { case POI: return markersPoi.get(id); case NOTE: return markersNotes.get(id); default: return null; } } public LatLngBounds getViewLatLngBounds() { return mapboxMap.getProjection().getVisibleRegion().latLngBounds; } public float getZoomLevel() { return (float) mapboxMap.getCameraPosition().zoom; } public void changeMapZoomSmooth(final double zoom) { mapboxMap.easeCamera(new CameraUpdate() { @Override public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { return new CameraPosition.Builder().target(mapboxMap.getCameraPosition().target).zoom(zoom).build(); } }, 700); } public void changeMapZoomSmooth(final double zoom, final OnZoomAnimationFinishedListener onZoomAnimationFinishedListener) { mapboxMap.easeCamera(new CameraUpdate() { @Override public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { return new CameraPosition.Builder().target(mapboxMap.getCameraPosition().target).zoom(zoom).build(); } }, 700); new Handler().postDelayed(new Runnable() { @Override public void run() { onZoomAnimationFinishedListener.onZoomAnimationFinished(); } }, 750); } public void changeMapPositionSmooth(final LatLng newPosition) { mapboxMap.easeCamera(new CameraUpdate() { @Override public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { return new CameraPosition.Builder().target(newPosition).build(); } }, 700); } public void hideMarker(Marker marker) { marker.setIcon(IconFactory.getInstance(getActivity()).fromResource(R.drawable.hidden_marker)); } private void addMarkerView(LocationMarkerViewOptions markerOptions) { mapboxMap.addMarker(markerOptions); } private void addWayMarker(WayMarkerOptions wayMarkerOptions) { mapboxMap.addMarker(wayMarkerOptions); } /*----------------------------------------------------------- * EASTER EGG *---------------------------------------------------------*/ Long previousTime = System.currentTimeMillis(); int nbClick = 0; private void easterEgg() { Long time = System.currentTimeMillis(); if (time - previousTime < 500) { if (++nbClick == 4) { eventBus.post(new PleaseShowMeArpiglEvent()); eventBus.post(new PleaseToggleArpiEvent()); Toast.makeText(getActivity(), getString(R.string.easter_egg_activation), Toast.LENGTH_SHORT).show(); sharedPreferences.edit().putBoolean(getString(R.string.easter_egg), true).apply(); nbClick = 0; } } else { nbClick = 0; } previousTime = time; } /*----------------------------------------------------------- * SYNC *---------------------------------------------------------*/ @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncFinishUploadPoiEvent(SyncFinishUploadPoiEvent event) { boolean forceRefresh = event.getSuccessfullyAddedPoisCount() > 0 || event.getSuccessfullyUpdatedPoisCount() > 0 || event.getSuccessfullyDeletedPoisCount() > 0; if (forceRefresh) { presenter.setForceRefreshPoi(); presenter.loadPoisIfNeeded(); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onNewNoteCreatedEvent(NewNoteCreatedEvent event) { // a note has been created, select it markerSelectedId = event.getNoteId(); markerSelected = null; selectedMarkerType = LocationMarkerView.MarkerType.NOTE; presenter.setForceRefreshNotes(); presenter.loadPoisIfNeeded(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onApplyNewCommentFailedEvent(ApplyNewCommentFailedEvent event) { Toast.makeText(getActivity(), getString(R.string.failed_apply_comment), Toast.LENGTH_SHORT).show(); markerSelectedId = null; markerSelected = null; selectedMarkerType = LocationMarkerView.MarkerType.NONE; switchMode(MapMode.DEFAULT); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncUnauthorizedEvent(SyncUnauthorizedEvent event) { Toast.makeText(getActivity(), R.string.couldnt_connect_retrofit, Toast.LENGTH_LONG).show(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncDownloadRetrofitErrorEvent(SyncDownloadRetrofitErrorEvent event) { Toast.makeText(getActivity(), R.string.couldnt_download_retrofit, Toast.LENGTH_SHORT).show(); showProgressBar(false); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncConflictingNodeErrorEvent(SyncConflictingNodeErrorEvent event) { Toast.makeText(getActivity(), R.string.couldnt_update_node, Toast.LENGTH_LONG).show(); removePoiMarkerInError(event.getPoiIdInError()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncNewNodeErrorEvent(SyncNewNodeErrorEvent event) { Toast.makeText(getActivity(), R.string.couldnt_create_node, Toast.LENGTH_LONG).show(); removePoiMarkerInError(event.getPoiIdInError()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncUploadRetrofitErrorEvent(SyncUploadRetrofitErrorEvent event) { Toast.makeText(getActivity(), R.string.couldnt_upload_retrofit, Toast.LENGTH_SHORT).show(); removePoiMarkerInError(event.getPoiIdInError()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSyncUploadNoteRetrofitErrorEvent(SyncUploadNoteRetrofitErrorEvent event) { Toast.makeText(getActivity(), getString(R.string.couldnt_upload_retrofit), Toast.LENGTH_SHORT).show(); removeNoteMarkerInError(event.getNoteIdInError()); } // markers were added on the map the sync failed we remove them private void removePoiMarkerInError(Long id) { Marker m = markersPoi.remove(id).getMarker(); if (m != null) { mapboxMap.removeMarker(m); } defaultMap(); } // note was added on the map the sync failed we remove it private void removeNoteMarkerInError(Long id) { Marker m = markersNotes.remove(id).getMarker(); if (m != null) { mapboxMap.removeMarker(m); } defaultMap(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onTooManyRequestsEvent(TooManyRequestsEvent event) { progressBar.setVisibility(View.GONE); } /*----------------------------------------------------------- * PoiType picker *---------------------------------------------------------*/ @BindView(R.id.poi_type_value) EditText poiTypeEditText; @BindView(R.id.poi_type) TextView poiTypeTextView; @BindView(R.id.edit_poi_type) ImageButton editPoiTypeBtn; @BindView(R.id.autocomplete_list) ListView poiTypeListView; @BindView(R.id.poi_type_value_wrapper) RelativeLayout poiTypeHeaderWrapper; @OnClick(R.id.edit_poi_type) public void onEditPoiTypeWrapperClick() { editPoiType(); } @OnClick(R.id.poi_type_value_wrapper) public void onEditPoiTypeClick() { editPoiType(); } public void editPoiType() { if (mapMode == MapMode.POI_CREATION) { switchMode(MapMode.TYPE_PICKER); } } private long savePoiTypeId = 0; private PoiTypePickerAdapter poiTypePickerAdapter; private List<PoiType> autocompletePoiTypeValues = new ArrayList<>(); private void instantiatePoiTypePicker() { poiTypePickerAdapter = new PoiTypePickerAdapter(getActivity(), autocompletePoiTypeValues, poiTypeEditText, eventBus, bitmapHandler, sharedPreferences.getBoolean(getString(R.string.shared_prefs_expert_mode), false)); poiTypeListView.setAdapter(poiTypePickerAdapter); // Add Text Change Listener to EditText poiTypeEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // Call back the Adapter with current character to Filter poiTypePickerAdapter.getFilter().filter(s.toString()); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); } private void displayPoiTypePicker() { if (mapMode == MapMode.TYPE_PICKER) { if (poiTypeListView.getVisibility() != View.VISIBLE) { Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_up_poi_type); if (android.os.Build.VERSION.SDK_INT >= 21) { bottomUp.setInterpolator(getActivity(), android.R.interpolator.linear_out_slow_in); } //the text view will be changed to edit text at the end of the animation bottomUp.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { poiTypeEditText.setVisibility(View.VISIBLE); poiTypeTextView.setVisibility(View.GONE); editPoiTypeBtn.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { } }); poiTypeListView.startAnimation(bottomUp); poiTypeListView.setVisibility(View.VISIBLE); // animation of the edit text from the top if (poiTypeTextView.getVisibility() == View.GONE) { Animation slideTop = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_top_annimation); poiTypeHeaderWrapper.startAnimation(slideTop); poiTypeHeaderWrapper.setVisibility(View.VISIBLE); poiTypeEditText.setVisibility(View.VISIBLE); } } } else if (mapMode == MapMode.POI_CREATION) { if (poiTypeListView.getVisibility() == View.VISIBLE) { Animation upBottom = AnimationUtils.loadAnimation(getActivity(), R.anim.anim_down_poi_type); if (android.os.Build.VERSION.SDK_INT >= 21) { upBottom.setInterpolator(getActivity(), android.R.interpolator.linear_out_slow_in); } poiTypeListView.startAnimation(upBottom); } poiTypeListView.setVisibility(View.GONE); poiTypeEditText.setVisibility(View.GONE); // if we have few value we hide the editPoiType btn if (presenter.getNumberOfPoiTypes() > maxPoiType) { editPoiTypeBtn.setVisibility(View.VISIBLE); } poiTypeTextView.setVisibility(View.VISIBLE); } else if (mapMode == MapMode.NOTE_CREATION) { poiTypeHeaderWrapper.setVisibility(View.VISIBLE); poiTypeTextView.setVisibility(View.VISIBLE); poiTypeListView.setVisibility(View.GONE); poiTypeEditText.setVisibility(View.GONE); editPoiTypeBtn.setVisibility(View.GONE); poiTypeTextView.setText(getResources().getString(R.string.note)); } else { //For default behavior hide all poitype picker components poiTypeListView.setVisibility(View.GONE); poiTypeEditText.setVisibility(View.GONE); poiTypeTextView.setVisibility(View.GONE); editPoiTypeBtn.setVisibility(View.GONE); poiTypeHeaderWrapper.setVisibility(View.GONE); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onLastUsePoiTypeLoaded(LastUsePoiTypeLoaded event) { poiTypePickerAdapter.addAllLastUse(event.getAutocompleteLastUsePoiTypeValues()); poiTypeListView.setSelectionAfterHeaderView(); nextTuto(1); } /*----------------------------------------------------------- * ADDRESS *---------------------------------------------------------*/ @BindView(R.id.addressView) TextView addressView; @Inject Geocoder geocoder; @Subscribe(threadMode = ThreadMode.MAIN) public void onAddressFoundEvent(AddressFoundEvent event) { Timber.d("Received event AddressFound"); if (getZoomLevel() >= zoomVectorial) { addressView.setVisibility(View.VISIBLE); } addressView.setText(event.getAddress()); } /*----------------------------------------------------------- * FILTERS *---------------------------------------------------------*/ private List<Long> poiTypeHidden = new ArrayList<>(); private boolean displayOpenNotes = true; private boolean displayClosedNotes = true; public List<Long> getPoiTypeHidden() { return poiTypeHidden; } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseApplyPoiFilter(PleaseApplyPoiFilter event) { Timber.d("filtering Pois by type"); poiTypeHidden = event.getPoiTypeIdsToHide(); applyPoiFilter(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseApplyNoteFilterEvent(PleaseApplyNoteFilterEvent event) { Timber.d("filtering Notes"); displayOpenNotes = event.isDisplayOpenNotes(); displayClosedNotes = event.isDisplayClosedNotes(); applyNoteFilter(); } public void applyNoteFilter() { for (LocationMarkerViewOptions marker : markersNotes.values()) { removeMarkerView(marker); addNoteMarkerDependingOnFilters(marker); } } public void applyPoiFilter() { for (LocationMarkerViewOptions marker : markersPoi.values()) { removeMarkerView(marker); addPoiMarkerDependingOnFilters(marker); } } private void addNoteMarkerDependingOnFilters(LocationMarkerViewOptions<Note> markerOption) { Note note = markerOption.getMarker().getRelatedObject(); if ((displayOpenNotes && Note.STATUS_OPEN.equals(note.getStatus())) || Note.STATUS_SYNC.equals(note.getStatus()) || (displayClosedNotes && Note.STATUS_CLOSE.equals(note.getStatus()))) { addMarkerView(markerOption); } else if (mapMode.equals(MapMode.DETAIL_NOTE) && ((Note) markerSelected.getRelatedObject()).getId().equals(note.getId())) { switchMode(MapMode.DEFAULT); } creationPin.setVisibility(View.GONE); } private void addPoiMarkerDependingOnFilters(LocationMarkerViewOptions<Poi> markerOption) { Poi poi = markerOption.getMarker().getRelatedObject(); //if we are in vectorial mode we hide all poi not at the current level if (poi.getType() != null && !poiTypeHidden.contains(poi.getType().getId()) && (!isVectorial || poi.isAtLevel(currentLevel) || !poi.isOnLevels(levelBar.getLevels()))) { mapboxMap.addMarker(markerOption); } else if (mapMode.equals(MapMode.DETAIL_POI) && ((Poi) markerSelected.getRelatedObject()).getId().equals(poi.getId())) { //if the poi selected is hidden close the detail mode switchMode(MapMode.DEFAULT); } } /*----------------------------------------------------------- * TUTORIAL *---------------------------------------------------------*/ private AddPoiTutoManager addPoiTutoManager; @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseDisplayTutorialEvent(PleaseDisplayTutorialEvent event) { TutorialManager.forceDisplayAddTuto = true; TutorialManager.forceDisplaySyncTuto = true; TutorialManager.forceDisplayOfflineTuto = true; switchMode(MapMode.DEFAULT); Toast.makeText(getActivity(), getString(R.string.replay_tuto_info), Toast.LENGTH_LONG).show(); } private void nextTuto(int step) { if (addPoiTutoManager == null) { addPoiTutoManager = new AddPoiTutoManager(getActivity(), TutorialManager.forceDisplayAddTuto); } addPoiTutoManager.setForceDisplay(TutorialManager.forceDisplayAddTuto); switch (step) { // Display when the user clicks on the "+" button. case 0: addPoiTutoManager.addPoiBtnTuto(addPoiFloatingMenu); break; // Display when the user clicks on "Add Poi" button. case 1: addPoiTutoManager.choosePoiTypeTuto(poiTypeListView); break; // Display when a use add a poi on the map. case 2: addPoiTutoManager.synchronizedModificationsTuto(mapView); TutorialManager.forceDisplayAddTuto = false; break; } } public FloatingActionMenu getAddPoiFloatingMenu() { return addPoiFloatingMenu; } /*----------------------------------------------------------- * GETTERS AND SETTERS *---------------------------------------------------------*/ public int getZoomVectorial() { return zoomVectorial; } public MapMode getMapMode() { return mapMode; } public LocationMarkerView getMarkerSelected() { return markerSelected; } public void setMarkerSelected(LocationMarkerView markerSelected) { selectedMarkerType = markerSelected.getType(); this.markerSelected = markerSelected; } public void setWayMarkerSelected(WayMarker wayMarkerSelected) { this.wayMarkerSelected = wayMarkerSelected; } public Long getMarkerSelectedId() { return markerSelectedId; } public void setMarkerSelectedId(Long markerSelectedId) { this.markerSelectedId = markerSelectedId; } public LocationMarkerView.MarkerType getSelectedMarkerType() { return selectedMarkerType; } public BitmapHandler getBitmapHandler() { return bitmapHandler; } public LevelBar getLevelBar() { return levelBar; } public TextView getAddressView() { return addressView; } public boolean isVectorial() { return isVectorial; } public void setVectorial(boolean vectorial) { isVectorial = vectorial; } public Geocoder getGeocoder() { return geocoder; } public MapFragmentPresenter getPresenter() { return presenter; } }