diff --git a/app/src/main/java/it/danieleverducci/nextcloudmaps/activity/main/MainActivity.java b/app/src/main/java/it/danieleverducci/nextcloudmaps/activity/main/MainActivity.java index 0eb3c28..49d6087 100644 --- a/app/src/main/java/it/danieleverducci/nextcloudmaps/activity/main/MainActivity.java +++ b/app/src/main/java/it/danieleverducci/nextcloudmaps/activity/main/MainActivity.java @@ -17,10 +17,14 @@ package it.danieleverducci.nextcloudmaps.activity.main; +import android.Manifest; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; import android.view.View; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; @@ -48,12 +52,14 @@ import it.danieleverducci.nextcloudmaps.utils.SettingsManager; public class MainActivity extends NextcloudMapsStyledActivity { private static final String TAG = "MainActivity"; + private static final int PERMISSION_REQUEST_CODE = 3890; private static final String NAVIGATION_KEY_ADD_GEOFAVORITE_FROM_GPS = "add_from_gps"; private static final String NAVIGATION_KEY_ADD_GEOFAVORITE_FROM_MAP = "add_from_map"; private static final String NAVIGATION_KEY_SHOW_ABOUT = "about"; private static final String NAVIGATION_KEY_SWITCH_ACCOUNT = "switch_account"; + private ArrayList onGpsPermissionGrantedListener = new ArrayList<>(); private DrawerLayout drawerLayout; private boolean isFabOpen = false; @@ -66,12 +72,44 @@ public class MainActivity extends NextcloudMapsStyledActivity { public void showMap() { replaceFragment(new GeofavoriteMapFragment()); + SettingsManager.setGeofavoriteListShownAsMap(this, true); } public void showList() { replaceFragment(new GeofavoriteListFragment()); + SettingsManager.setGeofavoriteListShownAsMap(this, false); } + public void addOnGpsPermissionGrantedListener(OnGpsPermissionGrantedListener l) { + onGpsPermissionGrantedListener.add(l); + } + + public void removeOnGpsPermissionGrantedListener(OnGpsPermissionGrantedListener l) { + onGpsPermissionGrantedListener.remove(l); + } + + public void requestGpsPermissions() { + ActivityCompat.requestPermissions( + this, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + PERMISSION_REQUEST_CODE + ); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + if (requestCode == PERMISSION_REQUEST_CODE && permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION)) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + for (OnGpsPermissionGrantedListener l : onGpsPermissionGrantedListener) { + l.onGpsPermissionGranted(); + } + } + } + } + + @Override protected void onCreate(Bundle savedInstanceState) { @@ -184,4 +222,8 @@ public class MainActivity extends NextcloudMapsStyledActivity { } + public interface OnGpsPermissionGrantedListener { + public void onGpsPermissionGranted(); + } + } \ No newline at end of file diff --git a/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteListFragment.java b/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteListFragment.java index c91cd33..5935ad9 100644 --- a/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteListFragment.java +++ b/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteListFragment.java @@ -80,8 +80,6 @@ public class GeofavoriteListFragment extends GeofavoritesFragment implements Sor return false; }); - //setSupportActionBar(toolbar); - homeToolbar.setOnClickListener(view -> updateToolbars(false)); AppCompatImageButton menuButton = v.findViewById(R.id.menu_button); @@ -121,7 +119,7 @@ public class GeofavoriteListFragment extends GeofavoritesFragment implements Sor geofavoriteAdapter.setSortRule(sortRule); // Register for data source events - mGeofavoritesFragmentViewModel.getIsUpdating().observe(this, new Observer() { + mGeofavoritesFragmentViewModel.getIsUpdating().observe(getViewLifecycleOwner(), new Observer() { @Override public void onChanged(@Nullable Boolean changed) { if(Boolean.TRUE.equals(changed)){ @@ -132,7 +130,7 @@ public class GeofavoriteListFragment extends GeofavoritesFragment implements Sor } } }); - mGeofavoritesFragmentViewModel.getGeofavorites().observe(this, new Observer>() { + mGeofavoritesFragmentViewModel.getGeofavorites().observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(List geofavorites) { geofavoriteAdapter.setGeofavoriteList(geofavorites); diff --git a/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteMapFragment.java b/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteMapFragment.java index 1770596..188eae9 100644 --- a/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteMapFragment.java +++ b/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoriteMapFragment.java @@ -1,7 +1,10 @@ package it.danieleverducci.nextcloudmaps.fragments; +import android.Manifest; +import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,23 +12,32 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; +import androidx.core.app.ActivityCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.lifecycle.Observer; +import org.osmdroid.api.IMapController; +import org.osmdroid.events.MapEventsReceiver; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.MapEventsOverlay; import org.osmdroid.views.overlay.Marker; -import org.osmdroid.views.overlay.infowindow.MarkerInfoWindow; +import org.osmdroid.views.overlay.infowindow.InfoWindow; +import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider; +import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay; import java.util.List; +import java.util.Set; import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.activity.main.MainActivity; import it.danieleverducci.nextcloudmaps.model.Geofavorite; import it.danieleverducci.nextcloudmaps.utils.MapUtils; +import it.danieleverducci.nextcloudmaps.utils.SettingsManager; import it.danieleverducci.nextcloudmaps.views.GeofavMarkerInfoWindow; -public class GeofavoriteMapFragment extends GeofavoritesFragment { +public class GeofavoriteMapFragment extends GeofavoritesFragment implements MainActivity.OnGpsPermissionGrantedListener { + private MapView map; @Override @@ -39,7 +51,21 @@ public class GeofavoriteMapFragment extends GeofavoritesFragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_geofavorite_map, container, false); + + // Setup map map = v.findViewById(R.id.map); + MapEventsOverlay meo = new MapEventsOverlay(requireContext(), new MapEventsReceiver() { + @Override + public boolean singleTapConfirmedHelper(GeoPoint p) { + InfoWindow.closeAllInfoWindowsOn(map); + return false; + } + + @Override + public boolean longPressHelper(GeoPoint p) {return false;} + }); + map.getOverlays().add(0, meo); + showUserPosition(); // Setup view listeners View showListButton = v.findViewById(R.id.view_mode_list); @@ -70,17 +96,90 @@ public class GeofavoriteMapFragment extends GeofavoritesFragment { return v; } + @Override + public void onStart() { + super.onStart(); + + ((MainActivity)requireActivity()).addOnGpsPermissionGrantedListener(this); + } + + @Override + public void onStop() { + super.onStop(); + + ((MainActivity)requireActivity()).removeOnGpsPermissionGrantedListener(this); + SettingsManager.setLastMapPosition( + requireContext(), + map.getMapCenter().getLatitude(), + map.getMapCenter().getLongitude(), + map.getZoomLevelDouble() + ); + } + @Override public void onSearch(String query) { // TODO: filter } + @Override + public void onGpsPermissionGranted() { + showUserPosition(); + } + + private void showUserPosition() { + // Center map on last position + double[] pos = SettingsManager.getLastMapPosition(requireContext()); + IMapController mapController = map.getController(); + mapController.setCenter(new GeoPoint(pos[0], pos[1])); + mapController.setZoom(pos[2]); + + // Check if user granted location permission + if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && + ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED + ) { + // User didn't grant permission. Ask it. + ((MainActivity)requireActivity()).requestGpsPermissions(); + return; + } + + MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(requireContext()), map); + mLocationOverlay.enableMyLocation(); + mLocationOverlay.runOnFirstFix(() -> requireActivity().runOnUiThread(() -> map.getController().animateTo(mLocationOverlay.getMyLocation()))); + + map.getOverlays().add(mLocationOverlay); + + } + private void addMarker(Geofavorite geofavorite){ GeoPoint pos = new GeoPoint(geofavorite.getLat(), geofavorite.getLng()); + // Set icon and color Drawable icon = DrawableCompat.wrap(AppCompatResources.getDrawable(requireContext(), R.drawable.ic_list_pin)); DrawableCompat.setTint(icon, geofavorite.categoryColor()); + // Set infowindow (popup opened on marker click) and its listeners + GeofavMarkerInfoWindow iw = new GeofavMarkerInfoWindow(map, geofavorite); + iw.setOnGeofavMarkerInfoWindowClickListener(new GeofavMarkerInfoWindow.OnGeofavMarkerInfoWindowClickListener() { + @Override + public void onGeofavMarkerInfoWindowEditClick() { + openGeofavorite(geofavorite); + } + @Override + public void onGeofavMarkerInfoWindowShareClick() { + shareGeofavorite(geofavorite); + } + @Override + public void onGeofavMarkerInfoWindowNavClick() { + navigateToGeofavorite(geofavorite); + + } + @Override + public void onGeofavMarkerInfoWindowDeleteClick() { + deleteGeofavorite(geofavorite); + } + }); + + // Set marker Marker m = new Marker(map); m.setPosition(pos); m.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM); @@ -88,7 +187,7 @@ public class GeofavoriteMapFragment extends GeofavoritesFragment { m.setTitle(geofavorite.getName()); m.setSnippet(geofavorite.getComment()); m.setSubDescription(geofavorite.getCategory()); - m.setInfoWindow(new GeofavMarkerInfoWindow(map)); + m.setInfoWindow(iw); map.getOverlays().add(m); } } diff --git a/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoritesFragment.java b/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoritesFragment.java index dbff7f0..be51b06 100644 --- a/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoritesFragment.java +++ b/app/src/main/java/it/danieleverducci/nextcloudmaps/fragments/GeofavoritesFragment.java @@ -14,6 +14,7 @@ import androidx.lifecycle.ViewModelProvider; import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity; import it.danieleverducci.nextcloudmaps.activity.main.GeofavoritesFragmentViewModel; +import it.danieleverducci.nextcloudmaps.activity.main.MainActivity; import it.danieleverducci.nextcloudmaps.model.Geofavorite; import it.danieleverducci.nextcloudmaps.utils.IntentGenerator; diff --git a/app/src/main/java/it/danieleverducci/nextcloudmaps/utils/SettingsManager.java b/app/src/main/java/it/danieleverducci/nextcloudmaps/utils/SettingsManager.java index c07cf65..97e72a8 100644 --- a/app/src/main/java/it/danieleverducci/nextcloudmaps/utils/SettingsManager.java +++ b/app/src/main/java/it/danieleverducci/nextcloudmaps/utils/SettingsManager.java @@ -1,12 +1,17 @@ package it.danieleverducci.nextcloudmaps.utils; import android.content.Context; +import android.content.SharedPreferences; + import androidx.preference.PreferenceManager; import it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter; public class SettingsManager { static private final String SETTING_SORT_BY = "SETTING_SORT_BY"; static private final String SETTING_LAST_SELECTED_LIST_VIEW = "SETTING_LAST_SELECTED_LIST_VIEW"; + static private final String SETTING_LAST_MAP_POSITION_LAT = "SETTING_LAST_MAP_POSITION_LAT"; + static private final String SETTING_LAST_MAP_POSITION_LNG = "SETTING_LAST_MAP_POSITION_LNG"; + static private final String SETTING_LAST_MAP_POSITION_ZOOM = "SETTING_LAST_MAP_POSITION_ZOOM"; public static int getGeofavoriteListSortBy(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) @@ -27,4 +32,26 @@ public class SettingsManager { PreferenceManager.getDefaultSharedPreferences(context) .edit().putBoolean(SETTING_LAST_SELECTED_LIST_VIEW, value).apply(); } + + /** + * Returns the last saved position + * @param context + * @return double[lat,lng,zoom] + */ + public static double[] getLastMapPosition(Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + return new double[] { + (double) sp.getFloat(SETTING_LAST_MAP_POSITION_LAT, 0.0f), + (double) sp.getFloat(SETTING_LAST_MAP_POSITION_LNG, 0.0f), + (double) sp.getFloat(SETTING_LAST_MAP_POSITION_ZOOM, 10.0f), + }; + } + + public static void setLastMapPosition(Context context, double lat, double lng, double zoom) { + PreferenceManager.getDefaultSharedPreferences(context).edit() + .putFloat(SETTING_LAST_MAP_POSITION_LAT, (float)lat) + .putFloat(SETTING_LAST_MAP_POSITION_LNG, (float)lng) + .putFloat(SETTING_LAST_MAP_POSITION_ZOOM, (float)zoom) + .apply(); + } } diff --git a/app/src/main/java/it/danieleverducci/nextcloudmaps/views/GeofavMarkerInfoWindow.java b/app/src/main/java/it/danieleverducci/nextcloudmaps/views/GeofavMarkerInfoWindow.java index 417f95a..d73b5ec 100644 --- a/app/src/main/java/it/danieleverducci/nextcloudmaps/views/GeofavMarkerInfoWindow.java +++ b/app/src/main/java/it/danieleverducci/nextcloudmaps/views/GeofavMarkerInfoWindow.java @@ -1,25 +1,60 @@ package it.danieleverducci.nextcloudmaps.views; +import android.view.View; + import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.infowindow.InfoWindow; import org.osmdroid.views.overlay.infowindow.MarkerInfoWindow; import it.danieleverducci.nextcloudmaps.R; +import it.danieleverducci.nextcloudmaps.model.Geofavorite; -public class GeofavMarkerInfoWindow extends MarkerInfoWindow { - /** - * @param mapView - */ - public GeofavMarkerInfoWindow(MapView mapView) { +public class GeofavMarkerInfoWindow extends MarkerInfoWindow implements View.OnClickListener { + private OnGeofavMarkerInfoWindowClickListener onGeofavMarkerInfoWindowClickListener; + + public GeofavMarkerInfoWindow(MapView mapView, Geofavorite geofavorite) { super(R.layout.infowindow_geofav, mapView); + + getView().findViewById(R.id.action_icon_share).setOnClickListener(this); + getView().findViewById(R.id.action_icon_nav).setOnClickListener(this); + getView().findViewById(R.id.action_icon_delete).setOnClickListener(this); + getView().findViewById(R.id.action_icon_edit).setOnClickListener(this); + } + + public void setOnGeofavMarkerInfoWindowClickListener(OnGeofavMarkerInfoWindowClickListener l) { + this.onGeofavMarkerInfoWindowClickListener = l; } @Override public void onOpen(Object item) { + InfoWindow.closeAllInfoWindowsOn(getMapView()); super.onOpen(item); } + @Override - public void onClose() { - super.onClose(); + public void onClick(View v) { + if (onGeofavMarkerInfoWindowClickListener == null) + return; + + if (v.getId() == R.id.action_icon_share) + onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowShareClick(); + + if (v.getId() == R.id.action_icon_nav) + onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowNavClick(); + + if (v.getId() == R.id.action_icon_delete) + onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowDeleteClick(); + + if (v.getId() == R.id.action_icon_edit) + onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowEditClick(); + } + + + public interface OnGeofavMarkerInfoWindowClickListener { + public void onGeofavMarkerInfoWindowEditClick(); + public void onGeofavMarkerInfoWindowShareClick(); + public void onGeofavMarkerInfoWindowNavClick(); + public void onGeofavMarkerInfoWindowDeleteClick(); } } diff --git a/app/src/main/res/layout/infowindow_geofav.xml b/app/src/main/res/layout/infowindow_geofav.xml index f56062a..26e6772 100644 --- a/app/src/main/res/layout/infowindow_geofav.xml +++ b/app/src/main/res/layout/infowindow_geofav.xml @@ -72,6 +72,15 @@ android:src="@drawable/ic_delete_grey" app:tint="@color/defaultBrand"/> + +