diff --git a/app/build.gradle b/app/build.gradle index 9d72e98..f9cfa9d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,4 +54,8 @@ dependencies { implementation 'com.github.MKergall:osmbonuspack:6.9.0' implementation 'androidx.multidex:multidex:2.0.1' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.squareup.okhttp3:okhttp:4.7.2' + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1db3331..f32b8de 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,7 +4,6 @@ - ): String { + fun toString(places: List): String { return Gson().toJson(places) } @TypeConverter - fun toPlaces(value: String): List { - val listType = object : TypeToken>() {}.type + fun toPlaces(value: String): List { + val listType = object : TypeToken>() {}.type return Gson().fromJson(value, listType) } diff --git a/app/src/main/java/uca/baptistearthur/geocaching/data/Stub.kt b/app/src/main/java/uca/baptistearthur/geocaching/data/Stub.kt index 8cbdffe..3cf4b06 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/data/Stub.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/data/Stub.kt @@ -1,5 +1,6 @@ package uca.baptistearthur.geocaching.data +import org.osmdroid.util.GeoPoint import uca.baptistearthur.geocaching.model.Place import uca.baptistearthur.geocaching.model.RoadTripEntity import java.util.Date @@ -11,25 +12,25 @@ class Stub { 1, "France", Date(), - listOf(Place(49.3, 49.3)).toMutableList() + listOf(GeoPoint(49.3, 49.3)).toMutableList() ), RoadTripEntity( 2, "Italie", Date(), - listOf(Place(48.866667, 2.34533), Place(98.866667, 2.333333)).toMutableList() + listOf(GeoPoint(48.866667, 2.34533), GeoPoint(98.866667, 2.333333)).toMutableList() ), RoadTripEntity( 3, "Danemark", Date(), - listOf(Place(48.866667, 2.333333), Place(48.866667, 2.333333)).toMutableList() + listOf(GeoPoint(48.866667, 2.333333), GeoPoint(48.866667, 2.333333)).toMutableList() ), RoadTripEntity( 4, "Islande", Date(), - listOf(Place(48.866667, 2.333333), Place(48.866667, 2.333333), Place(48.866667, 2.333333)).toMutableList() + listOf(GeoPoint(48.866667, 2.333333), GeoPoint(48.866667, 2.333333), GeoPoint(48.866667, 2.333333)).toMutableList() ), ) return list.toMutableList() diff --git a/app/src/main/java/uca/baptistearthur/geocaching/model/RoadTripEntity.kt b/app/src/main/java/uca/baptistearthur/geocaching/model/RoadTripEntity.kt index 847a6a2..009d5e3 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/model/RoadTripEntity.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/model/RoadTripEntity.kt @@ -4,6 +4,7 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import com.google.gson.Gson +import org.osmdroid.util.GeoPoint import java.util.Date @Entity(tableName = "Roadtrip") @@ -11,11 +12,10 @@ class RoadTripEntity( @PrimaryKey(autoGenerate = true) val id: Int, @ColumnInfo(name="name") val name: String, @ColumnInfo(name="date") val date: Date, - @ColumnInfo(name="places") val places: MutableList + @ColumnInfo(name="places") val places: MutableList ){ - - fun addPlaceToRoadTripList(place: Place) = places.add(place) - fun addPlaceToRoadTripList(latitude: Double, longitude: Double) = places.add(Place(latitude, longitude)) + fun addPlaceToRoadTripList(place: GeoPoint) = places.add(place) + fun addPlaceToRoadTripList(latitude: Double, longitude: Double) = places.add(GeoPoint(latitude, longitude)) fun toJSON(): String = Gson().toJson(this) } \ No newline at end of file diff --git a/app/src/main/java/uca/baptistearthur/geocaching/recyclerview/PlacesAdapter.kt b/app/src/main/java/uca/baptistearthur/geocaching/recyclerview/PlacesAdapter.kt index 2e3c2f8..de3570f 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/recyclerview/PlacesAdapter.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/recyclerview/PlacesAdapter.kt @@ -4,11 +4,12 @@ import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import org.osmdroid.util.GeoPoint import uca.baptistearthur.geocaching.R import uca.baptistearthur.geocaching.model.Place -class PlacesAdapter (val places: List) : RecyclerView.Adapter(){ +class PlacesAdapter (val places: List) : RecyclerView.Adapter(){ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlacesViewHolder { return PlacesViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.cell_place, parent, false)) diff --git a/app/src/main/java/uca/baptistearthur/geocaching/ui/activity/MainWindow.kt b/app/src/main/java/uca/baptistearthur/geocaching/ui/activity/MainWindow.kt index 320821d..ed7df80 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/ui/activity/MainWindow.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/ui/activity/MainWindow.kt @@ -2,18 +2,13 @@ package uca.baptistearthur.geocaching.ui.activity import android.annotation.SuppressLint import android.os.Bundle -import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.navigation.findNavController import androidx.navigation.ui.NavigationUI import androidx.navigation.ui.setupWithNavController import com.google.android.material.bottomnavigation.BottomNavigationView import uca.baptistearthur.geocaching.R -import uca.baptistearthur.geocaching.application.RTApplication -import uca.baptistearthur.geocaching.ui.fragment.Map -import uca.baptistearthur.geocaching.viewModels.RoadTripViewModel -import uca.baptistearthur.geocaching.viewModels.RoadTripViewModelFactory class MainWindow: AppCompatActivity() { diff --git a/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/Map.kt b/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/Map.kt index efe44e3..e03a433 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/Map.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/Map.kt @@ -30,72 +30,48 @@ import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay import uca.baptistearthur.geocaching.R +import uca.baptistearthur.geocaching.model.Place import uca.baptistearthur.geocaching.ui.overlay.AddMarkerOverlay import uca.baptistearthur.geocaching.ui.overlay.RecenterOverlay -class Map : Fragment() { - private lateinit var map : MapView - private lateinit var spinner: ProgressBar - private lateinit var locationManager: LocationManager - private val userAgent = "RoadTrip" - - val defaultPoint = GeoPoint(48.8583, 2.2944) - var isMapCentered = false; - val locationListener = object : LocationListener { - override fun onLocationChanged(location: Location) { - val geoPoint = GeoPoint(location.latitude, location.longitude) - if(!isMapCentered){ - map.controller.setCenter(geoPoint) - spinner.visibility=View.GONE; - isMapCentered=true; - } - map.invalidate() - } +open class Map : Fragment() { + protected lateinit var map : MapView + companion object{ + private val minimumZoomLevel = 4.0 + private val defaultZoomLevel = 21.0 + private val userAgent = "RoadTrip" + private val defaultPoint = GeoPoint(48.8583, 2.2944) } - - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Configuration.getInstance().userAgentValue = userAgent; - } - - val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) - { map.controller.setCenter(defaultPoint) } - - private fun configureMap(view: View){ - Log.d("GeoMap", "MAP CONFIGURE") - map = view.findViewById(R.id.mapView) - map.setTileSource(TileSourceFactory.MAPNIK); - spinner = view.findViewById(R.id.mapLoading); - spinner.visibility=View.VISIBLE; - map.minZoomLevel = 4.0 - map.controller.setZoom(21.0); - if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - requestPermissionLauncher.launch(ACCESS_FINE_LOCATION) + protected fun configureMap() = map.apply { + setTileSource(TileSourceFactory.MAPNIK) + minZoomLevel = minimumZoomLevel + controller.apply { + setCenter(defaultPoint) + setZoom(defaultZoomLevel) + } + addMapOverlays(mapView = this) } - map.controller.setCenter(defaultPoint) + open fun addMapOverlays(mapView: MapView){ + // Compass Overlay val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), map); compassOverlay.enableCompass(); - map.getOverlays().add(compassOverlay); + map.overlays.add(compassOverlay); + // Scale Bar Overlay val scaleBarOverlay = ScaleBarOverlay(map) scaleBarOverlay.setAlignRight(true) map.overlays.add(scaleBarOverlay) - val myLocation = MyLocationNewOverlay(GpsMyLocationProvider(context), map) - myLocation.enableMyLocation() - map.overlays.add(myLocation) - - val recenter = RecenterOverlay(GpsMyLocationProvider(context), map) - recenter.enableMyLocation() - map.overlays.add(recenter); - + // Add Marker Overlay val addMarker = AddMarkerOverlay(OSRMRoadManager(context, userAgent)) map.overlays.add(addMarker); - + addMarker.addPlaces(listOf(GeoPoint(50.5, 10.1), GeoPoint(52.5, 33.33), GeoPoint(66.0, 33.35)), map) } override fun onCreateView( @@ -103,30 +79,19 @@ class Map : Fragment() { savedInstanceState: Bundle? ): View? { Log.d("GeoMap", "MAP ON CREATE VIEW") - // Inflate the layout for this fragment val view = inflater.inflate(R.layout.fragment_map, container, false) - configureMap(view) + map = view.findViewById(R.id.mapView) + configureMap() return view } override fun onResume() { super.onResume() - Log.d("GeoMap", "MAP RESUME") - if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { - locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, locationListener) - } map.onResume() //needed for compass, my location overlays, v6.0.0 and up } override fun onPause() { super.onPause() - Log.d("GeoMap", "MAP PAUSE") - if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { - locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager - locationManager.removeUpdates(locationListener) - isMapCentered=false; - } map.onPause() //needed for compass, my location overlays, v6.0.0 and up } } \ No newline at end of file diff --git a/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/MyLocationMap.kt b/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/MyLocationMap.kt new file mode 100644 index 0000000..ba98c03 --- /dev/null +++ b/app/src/main/java/uca/baptistearthur/geocaching/ui/fragment/MyLocationMap.kt @@ -0,0 +1,99 @@ +package uca.baptistearthur.geocaching.ui.fragment + +import android.content.Context +import android.content.pm.PackageManager +import android.location.LocationManager +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import org.osmdroid.config.Configuration +import org.osmdroid.util.GeoPoint +import org.osmdroid.views.MapView +import org.osmdroid.views.overlay.ScaleBarOverlay +import android.Manifest.permission.ACCESS_FINE_LOCATION +import android.location.Location +import android.location.LocationListener +import android.util.Log +import android.widget.ProgressBar +import androidx.activity.result.contract.ActivityResultContracts +import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider +import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay +import uca.baptistearthur.geocaching.R +import uca.baptistearthur.geocaching.ui.overlay.RecenterOverlay + +class MyLocationMap : Map() { + + private lateinit var spinner: ProgressBar + private lateinit var locationManager: LocationManager + private var isMapCentered = false; + + private val locationListener = LocationListener { location -> + val geoPoint = GeoPoint(location.latitude, location.longitude) + if(!isMapCentered){ + map.controller.setCenter(geoPoint) + spinner.visibility=View.GONE; + isMapCentered=true; + } + map.invalidate() + } + + private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){} + + private fun displaySpinner(view: View){ + spinner = view.findViewById(R.id.mapLoading) + spinner.visibility=View.VISIBLE + if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + requestPermissionLauncher.launch(ACCESS_FINE_LOCATION) + } + } + + override fun addMapOverlays(mapView: MapView){ + super.addMapOverlays(mapView) + Log.d("GeoMap", "MyLocationOverlay") + + // Recenter Overlay + val recenter = RecenterOverlay(GpsMyLocationProvider(context), map) + recenter.enableMyLocation() + map.overlays.add(recenter); + + // My Location Overlay + val myLocation = MyLocationNewOverlay(GpsMyLocationProvider(context), map) + myLocation.enableMyLocation() + + map.overlays.add(myLocation) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + Log.d("GeoMap", "MAP ON CREATE VIEW") + val view = inflater.inflate(R.layout.fragment_map, container, false) + map = view.findViewById(R.id.mapView) + configureMap() + displaySpinner(view) + return view + } + + override fun onResume() { + super.onResume() + Log.d("GeoMap", "MAP RESUME") + if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, locationListener) + } + } + + override fun onPause() { + super.onPause() + Log.d("GeoMap", "MAP PAUSE") + if (ContextCompat.checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager + locationManager.removeUpdates(locationListener) + isMapCentered=false; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/AddMarkerOverlay.kt b/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/AddMarkerOverlay.kt index 4f8112f..63ca18e 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/AddMarkerOverlay.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/AddMarkerOverlay.kt @@ -14,6 +14,7 @@ import org.osmdroid.views.MapView import org.osmdroid.views.overlay.Overlay import org.osmdroid.views.overlay.Polyline import uca.baptistearthur.geocaching.R +import uca.baptistearthur.geocaching.model.Place class AddMarkerOverlay(val roadManager: RoadManager) : Overlay() { @@ -21,27 +22,35 @@ class AddMarkerOverlay(val roadManager: RoadManager) : Overlay() { private var locations: MutableSet = mutableSetOf() private lateinit var roadOverlay: Polyline private var newRoadtripOverlayVisible = false; + + fun addPlaces(geoPoints: Collection, mapView: MapView)= + geoPoints.forEach { addMarkerAtGeopoint(it, mapView)} + + private fun addMarkerAtGeopoint(geoPoint: GeoPoint, mapView: MapView){ + val marker = PlaceMarker(mapView, this) + marker.position = geoPoint + if(locations.isNotEmpty()) locations.last().setDefaultIcon() + locations.add(marker) + locations.forEach{ it.closeInfoWindow()} + computeIcons(mapView.context) + mapView.overlays.add(marker) + computeRoad(mapView) + computeNewRoadtripOverlay(mapView); + mapView.invalidate() + } + override fun onDoubleTap(e: MotionEvent?, mapView: MapView?): Boolean { - Log.d("GeoMap", "Longpress") + val proj = mapView?.projection; if(proj!=null){ - val loc = proj.fromPixels(e?.x?.toInt()!!, e.y.toInt() ) as GeoPoint - val marker = PlaceMarker(mapView, this) - marker.position = loc - if(locations.isNotEmpty()) locations.last().setDefaultIcon() - locations.add(marker) - locations.forEach{ it.closeInfoWindow()} - computeIcons(mapView.context) - mapView.overlays.add(marker) - computeRoad(mapView) - computeNewRoadtripOverlay(mapView); - mapView.invalidate() + val geoPoint = proj.fromPixels(e?.x?.toInt()!!, e.y.toInt() ) as GeoPoint + addMarkerAtGeopoint(geoPoint, mapView) } return true; } - fun computeIcons(context: Context){ - if(locations.isNotEmpty()) { + fun computeIcons(context: Context) { + if (locations.isNotEmpty()) { val flagIcon = ContextCompat.getDrawable(context, R.drawable.roadtrip_marker)!! locations.last().icon = flagIcon locations.first().icon = flagIcon @@ -52,7 +61,7 @@ class AddMarkerOverlay(val roadManager: RoadManager) : Overlay() { mapView.overlays.remove(mapView.overlays.find { it is Polyline}) if (locations.size > 1) { CoroutineScope(Dispatchers.IO).launch { - val road = roadManager.getRoad(ArrayList(locations.map{it -> it.position})) + val road = roadManager.getRoad(ArrayList(locations.map{it.position})) withContext(Dispatchers.Main) { roadOverlay = RoadManager.buildRoadOverlay(road) mapView.overlays.add(roadOverlay) diff --git a/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/NewRoadtripOverlay.kt b/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/NewRoadtripOverlay.kt index aba5aca..131134c 100644 --- a/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/NewRoadtripOverlay.kt +++ b/app/src/main/java/uca/baptistearthur/geocaching/ui/overlay/NewRoadtripOverlay.kt @@ -12,6 +12,7 @@ import android.view.MotionEvent import android.widget.EditText import android.widget.Toast import androidx.core.content.ContextCompat +import org.osmdroid.util.GeoPoint import org.osmdroid.views.MapView import org.osmdroid.views.overlay.Overlay @@ -75,7 +76,7 @@ class NewRoadtripOverlay(val points: Collection) : Overlay() { .setPositiveButton(R.string.confirm) { _, _ -> val userInput = input.text.toString() if (userInput.isNotBlank()) { - val places: MutableList = points.map { Place(it.position.latitude, it.position.longitude) }.toMutableList() + val places: MutableList = points.map { GeoPoint(it.position.latitude, it.position.longitude) }.toMutableList() val newRoadTrip = RoadTripEntity( id = 0, // auto-generated ID name = input.text.toString(), diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml index c6879a7..3def7bd 100644 --- a/app/src/main/res/layout/fragment_map.xml +++ b/app/src/main/res/layout/fragment_map.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.fragment.Map"> + tools:context=".ui.fragment.MyLocationMap"> \ No newline at end of file