From abc2c02d945f98d06b088168c03a2cc2b5b429e8 Mon Sep 17 00:00:00 2001 From: liodali <16631886+liodali@users.noreply.github.com> Date: Sun, 24 Nov 2024 11:48:50 +0100 Subject: [PATCH] * fix follow location for vector map #544 * fix some gradle issue --- android/build.gradle | 73 ++--- android/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.properties | 5 - .../location/CustomLocation.kt | 16 +- .../location/OSMLocationManager.kt | 25 +- .../location/VectorLocationManager.kt | 259 +++++++++++------- .../map/FlutterMapLibreView.kt | 128 ++++----- .../flutter_osm_plugin/map/FlutterOsmView.kt | 4 +- .../dali/flutter_osm_plugin/map/OSMBase.kt | 2 - example/.metadata | 24 +- example/android/app/build.gradle | 63 ++--- .../android/app/src/debug/AndroidManifest.xml | 3 +- .../android/app/src/main/AndroidManifest.xml | 34 ++- .../MainActivity.java | 13 - .../kotlin/hamza/dali/example/MainActivity.kt | 5 + .../res/drawable-night/launch_background.xml | 11 + .../main/res/drawable/launch_background.xml | 2 +- .../app/src/main/res/values-night/styles.xml | 14 + .../app/src/profile/AndroidManifest.xml | 3 +- example/android/build.gradle | 19 +- example/android/gradle.properties | 18 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- example/android/settings.gradle | 6 +- 23 files changed, 404 insertions(+), 330 deletions(-) delete mode 100644 android/gradle.properties delete mode 100644 android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 example/android/app/src/main/java/hamza/dali/flutter_osm_plugin_example/MainActivity.java create mode 100644 example/android/app/src/main/kotlin/hamza/dali/example/MainActivity.kt create mode 100644 example/android/app/src/main/res/drawable-night/launch_background.xml create mode 100644 example/android/app/src/main/res/values-night/styles.xml diff --git a/android/build.gradle b/android/build.gradle index fb5c1006..c8b912f4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,73 +1,80 @@ -group 'hamza.dali.flutter_osm_plugin' -version '1.0' +group = "hamza.dali.flutter_osm_plugin" +version = "1.0-SNAPSHOT" buildscript { - ext.kotlin_version = '1.9.23' + ext.kotlin_version = "1.9.24" repositories { google() mavenCentral() - maven { url "https://jitpack.io" } } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.android.tools.build:gradle:7.1.3' + classpath("com.android.tools.build:gradle:8.1.4") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") } } -rootProject.allprojects { +allprojects { repositories { google() mavenCentral() - maven { url "https://jitpack.io" } } } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -//apply plugin: 'kotlin-kapt' +apply plugin: "com.android.library" +apply plugin: "kotlin-android" android { - compileSdk 34 - namespace "hamza.dali.flutter_osm_plugin" + if (project.android.hasProperty("namespace")) { + namespace = "hamza.dali.flutter_osm_plugin" + } + + compileSdk = 34 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } sourceSets { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { - minSdkVersion 20 - multiDexEnabled true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - lintOptions { - // disable 'InvalidPackage' + minSdk = 23 } buildFeatures { viewBinding true } - compileOptions { - coreLibraryDesugaringEnabled true - // Sets Java compatibility to Java 8 - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - } packagingOptions { pickFirst 'lib/x86/libc++_shared.so' pickFirst 'lib/x86_64/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' pickFirst 'lib/arm64-v8a/libc++_shared.so' } + + testOptions { + unitTests.all { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed", "standardOut", "standardError" + outputs.upToDateWhen {false} + showStandardStreams = true + } + } + } } dependencies { - def coroutines_version ="1.9.0" implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + + //implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Retrofit and relevant converters implementation 'com.squareup.retrofit2:retrofit:2.9.0' @@ -91,9 +98,5 @@ dependencies { implementation 'org.maplibre.gl:android-sdk:11.5.2' implementation 'org.maplibre.gl:android-plugin-annotation-v9:3.0.1' - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2' - - implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.29' - + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.3' } - diff --git a/android/gradle.properties b/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 01a286e9..00000000 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/CustomLocation.kt b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/CustomLocation.kt index 90451e85..a7b7ddd4 100644 --- a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/CustomLocation.kt +++ b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/CustomLocation.kt @@ -42,22 +42,30 @@ import java.util.LinkedList import kotlin.lazy typealias OnChangedLocation = (userLocation: GeoPoint, heading: Double) -> Unit +enum class LocationMode { + LocationOnly, + UserPositionOnly, + GPSOnly, + GPSBearing, + NONE, +} +fun Enum.isFollowing()= this == LocationMode.GPSBearing || this == LocationMode.GPSOnly interface CustomLocationManager : IMyLocationConsumer { val context: Context val provider: GpsMyLocationProvider var currentLocation: Location? var mGeoPoint: GeoPoint? - var mIsFollowing: Boolean - var controlMapFromOutSide: Boolean var enableAutoStop: Boolean var mIsLocationEnabled: Boolean - fun setMarkerIcon(personIcon: Bitmap?, directionIcon: Bitmap?) + var useDirectionMarker: Boolean + fun startLocationUpdating() fun stopLocationUpdating() fun enableMyLocation() fun onStopLocation() - fun toggleFollow(enableStop: Boolean) + fun configurationFollow(enableStop: Boolean?,useDirectionIcon: Boolean? ) + fun toggleFollow() fun disableFollowLocation() fun sendLocation() } diff --git a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/OSMLocationManager.kt b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/OSMLocationManager.kt index 4f7f49ae..d7ab1d5e 100644 --- a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/OSMLocationManager.kt +++ b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/OSMLocationManager.kt @@ -37,6 +37,8 @@ abstract class CustomOSMLocationManager( ) : Overlay(), Snappable, CustomLocationManager { + abstract var mIsFollowing: Boolean + abstract var controlMapFromOutSide: Boolean abstract val onMove: (IGeoPoint) -> Unit abstract val onUpdate: () -> Unit override val provider: GpsMyLocationProvider by lazy { @@ -70,14 +72,14 @@ class OSMLocationManager( private var mDirectionArrowCenterX = 0f private var mDirectionArrowCenterY = 0f - var disableRotateDirection = false + var disableRotateDirection = false override var enableAutoStop = true override var mIsFollowing: Boolean = false override var mIsLocationEnabled: Boolean = false - var useDirectionMarker = false + override var useDirectionMarker = false override var currentLocation: Location? = null override var mGeoPoint: GeoPoint? = GeoPoint(0.0, 0.0) @@ -165,6 +167,8 @@ class OSMLocationManager( mHandler.removeCallbacksAndMessages(mHandlerToken) } + + private fun disableMyLocation() { mIsLocationEnabled = false stopLocationProvider() @@ -251,9 +255,18 @@ class OSMLocationManager( }, mHandlerToken, 0) } } - - override fun toggleFollow(enableStop: Boolean) { - enableAutoStop = enableStop + override fun configurationFollow( + enableStop: Boolean?, + useDirectionIcon: Boolean? + ) { + if(enableStop!= null){ + this.enableAutoStop = enableStop + } + if(useDirectionIcon!= null){ + this.useDirectionMarker = useDirectionIcon + } + } + override fun toggleFollow() { enableFollowLocation() } @@ -312,7 +325,7 @@ class OSMLocationManager( } } - override fun setMarkerIcon(personIcon: Bitmap?, directionIcon: Bitmap?) { + fun setMarkerIcon(personIcon: Bitmap?, directionIcon: Bitmap?) { when { personIcon != null && directionIcon != null -> { diff --git a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/VectorLocationManager.kt b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/VectorLocationManager.kt index d785a62f..3ad6f6f8 100644 --- a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/VectorLocationManager.kt +++ b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/location/VectorLocationManager.kt @@ -1,26 +1,32 @@ package hamza.dali.flutter_osm_plugin.location +import android.Manifest import android.content.Context +import android.content.pm.PackageManager import android.graphics.Bitmap -import android.graphics.Color import android.location.Location import android.util.Log +import androidx.core.app.ActivityCompat import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.toDrawable import hamza.dali.flutter_osm_plugin.R +import hamza.dali.flutter_osm_plugin.map.MarkerConfiguration +import hamza.dali.flutter_osm_plugin.models.toLngLat import hamza.dali.flutter_osm_plugin.utilities.toGeoPoint import hamza.dali.flutter_osm_plugin.utilities.toHashMap import io.flutter.plugin.common.MethodChannel +import org.maplibre.android.camera.CameraPosition +import org.maplibre.android.camera.CameraUpdate +import org.maplibre.android.geometry.LatLng import org.maplibre.android.location.LocationComponentActivationOptions import org.maplibre.android.location.LocationComponentOptions -import org.maplibre.android.location.engine.AndroidLocationEngineImpl import org.maplibre.android.location.engine.LocationEngineCallback -import org.maplibre.android.location.engine.LocationEngineProxy -import org.maplibre.android.location.engine.LocationEngineRequest import org.maplibre.android.location.engine.LocationEngineResult import org.maplibre.android.location.modes.CameraMode -import org.maplibre.android.location.modes.RenderMode import org.maplibre.android.maps.MapLibreMap +import org.maplibre.android.plugins.annotation.Symbol +import org.maplibre.android.plugins.annotation.SymbolManager +import org.maplibre.android.plugins.annotation.SymbolOptions import org.osmdroid.util.GeoPoint import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider import org.osmdroid.views.overlay.mylocation.IMyLocationProvider @@ -28,76 +34,73 @@ import java.lang.Exception class OSMVectorLocationManager( override val context: Context, - private val mapView: MapLibreMap, + private val mapLibre: MapLibreMap, + private val locationMarkerManager: SymbolManager, private val methodChannel: MethodChannel, private val methodName: String, ) : CustomLocationManager { - private val listenerLocation = object : LocationEngineCallback { - override fun onSuccess(result: LocationEngineResult?) { - setLocation(result?.lastLocation) - sendLocation() - } - - override fun onFailure(e: Exception) { - Log.e("listenerLocation", e.stackTraceToString()) - } - } + private var locationMarker: Symbol? = null + private var personIconSymbolOption: SymbolOptions? = null + private var directionIconSymbolOption: Pair? = null override val provider: GpsMyLocationProvider by lazy { - GpsMyLocationProvider(context) - } - val locationProxy by lazy { - val andEnginImpl = AndroidLocationEngineImpl(context) - andEnginImpl.createListener(listenerLocation) - LocationEngineProxy(andEnginImpl) + val gps = GpsMyLocationProvider(context) + gps.locationUpdateMinTime = 2000L + gps.locationUpdateMinDistance = 10f + gps } -// init { -// mapView.locationComponent.isLocationComponentEnabled = false -// } + override var currentLocation: Location? = null override var mGeoPoint: GeoPoint? = null - override var mIsFollowing: Boolean = false - override var controlMapFromOutSide: Boolean = false override var enableAutoStop: Boolean = false + override var useDirectionMarker: Boolean = true + private var locationMode: LocationMode = LocationMode.NONE + private var locationModeCache: LocationMode? = null override var mIsLocationEnabled: Boolean = false - fun onStart() { - mapView.locationComponent.onStart() - if (mIsFollowing) { + if (locationModeCache != null && locationModeCache!!.isFollowing()) { + mIsLocationEnabled = provider.startLocationProvider(this) enableFollowLocation() + locationModeCache = null } } fun onStop() { - if (mIsFollowing) { + locationModeCache = locationMode + if (isFollowing()) { disableFollowLocation() } - mapView.locationComponent.onStop() + provider.stopLocationProvider() } fun onDestroy() { disableFollowLocation() - mapView.locationComponent.onDestroy() + locationModeCache = null + mapLibre.locationComponent.onDestroy() } - override fun setMarkerIcon( - personIcon: Bitmap?, directionIcon: Bitmap? + fun setMarkerIcon( + personIcon: MarkerConfiguration?, directionIcon: Pair? ) { - mapView.style?.removeImage("personIcon") - mapView.style?.removeImage("directionIcon") - mapView.style?.addImage( - "personIcon", personIcon?.toDrawable(context.resources) ?: ResourcesCompat.getDrawable( + mapLibre.style?.removeImage("personIcon") + mapLibre.style?.removeImage("directionIcon") + mapLibre.style?.addImage( + "personIcon", personIcon?.markerIcon?.toDrawable(context.resources) ?: ResourcesCompat.getDrawable( context.resources, R.drawable.ic_location_on_red_24dp, context.theme )!! ) - mapView.style?.addImage( + mapLibre.style?.addImage( "directionIcon", - directionIcon?.toDrawable(context.resources) ?: ResourcesCompat.getDrawable( + directionIcon?.first?.toDrawable(context.resources) ?: ResourcesCompat.getDrawable( context.resources, R.drawable.baseline_navigation_24, context.theme )!! ) + personIconSymbolOption = SymbolOptions().withIconImage("personIcon") + .withIconSize(personIcon?.factorSize?.toFloat() ?:1f) + + directionIconSymbolOption = directionIcon } @@ -105,99 +108,86 @@ class OSMVectorLocationManager( override fun startLocationUpdating() { enableMyLocation() - controlMapFromOutSide = true + locationMode = LocationMode.LocationOnly } override fun stopLocationUpdating() { - controlMapFromOutSide = false + locationMode = LocationMode.NONE onStopLocation() } override fun enableMyLocation() { - mIsLocationEnabled = provider.startLocationProvider(this) - - // set initial location when enabled - if (mIsLocationEnabled) { - provider.lastKnownLocation?.let { location -> - setLocation(location) + if(!mIsLocationEnabled){ + mIsLocationEnabled = provider.startLocationProvider(this) + + // set initial location when enabled + if (mIsLocationEnabled) { + provider.lastKnownLocation?.let { location -> + setLocation(location) + } } } + } override fun onStopLocation() { provider.stopLocationProvider() } - override fun toggleFollow(enableStop: Boolean) { - if (enableStop == false) { + override fun toggleFollow() { + if (!enableAutoStop ) { resetCameraToFollow() + enableAutoStop = !enableAutoStop + locationMode = LocationMode.GPSBearing + } + + if(!isFollowing() && !mIsLocationEnabled) { + enableFollowLocation() } - enableAutoStop = enableStop - enableFollowLocation() } override fun disableFollowLocation() { - mIsFollowing = false - mapView.locationComponent.cameraMode = CameraMode.NONE - mapView.locationComponent.isLocationComponentEnabled = false - mapView.locationComponent.locationEngine = null - mapView.locationComponent.cancelZoomWhileTrackingAnimation() - mapView.cancelTransitions() - mapView.locationComponent.activateLocationComponent( - LocationComponentActivationOptions - .builder(context, mapView.style!!) - .useDefaultLocationEngine(false) - .locationComponentOptions( - LocationComponentOptions.builder(context).build() - ) - .build() - ) - mapView.resetNorth() - mapView.triggerRepaint() + provider.stopLocationProvider() + locationMode = LocationMode.NONE + locationMarkerManager.deleteAll() + locationMarker = null + mIsLocationEnabled = false + + mapLibre.resetNorth() } fun resetCameraToFollow() { - mapView.locationComponent.cameraMode = CameraMode.TRACKING - mapView.locationComponent.forceLocationUpdate(currentLocation) - } + if(currentLocation != null){ + locationMarker?.latLng = currentLocation!!.toGeoPoint().toLngLat() + animateCamera() + } + } + private fun animateCamera(){ + mapLibre.animateCamera(object:CameraUpdate { + override fun getCameraPosition(maplibreMap: MapLibreMap): CameraPosition? { + return CameraPosition.Builder().target(locationMarker?.latLng) + .zoom(maplibreMap.cameraPosition.zoom) + .build() + } + }) + } fun stopCamera() { - mapView.locationComponent.cameraMode = CameraMode.NONE + locationModeNone() } private fun enableFollowLocation() { - mapView.resetNorth() - mIsFollowing = true - - mapView.locationComponent.locationEngine = locationProxy - mapView.locationComponent.activateLocationComponent( - LocationComponentActivationOptions - .builder(context, mapView.style!!) - .useDefaultLocationEngine(true) - .locationEngineRequest( - LocationEngineRequest.Builder(1250) - .setFastestInterval(1250) - .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) - .build() - ) - .locationComponentOptions( - LocationComponentOptions.builder(context) - .elevation(0f) - .bearingName("directionIcon") - .backgroundName("personIcon") - .foregroundName("personIcon").build() - ) - .build() - ) - mapView.locationComponent.isLocationComponentEnabled = mIsFollowing - mapView.locationComponent.cameraMode = CameraMode.TRACKING - mapView.locationComponent.renderMode = RenderMode.NORMAL + if(!mIsLocationEnabled){ + mIsLocationEnabled = provider.startLocationProvider(this) + } + setFollowing() // set initial location when enabled if (mIsLocationEnabled && provider.lastKnownLocation != null) { val location: Location = provider.lastKnownLocation setLocation(location) + mapLibre.resetNorth() } } @@ -217,8 +207,25 @@ class OSMVectorLocationManager( if (location != null) { setLocation(location) sendLocation() + if (isFollowing()) { + if(locationMarker == null){ + createMarker(location.toGeoPoint().toLngLat()) + } + locationMarker?.latLng = location.toGeoPoint().toLngLat() + if(location.hasBearing() && location.bearing != 0f){ + locationMarker?.iconRotate = location.bearing + locationMarker?.iconImage = "directionIcon" + locationMarker?.iconSize = directionIconSymbolOption?.second ?:1f + }else if( locationMarker?.iconImage != "personIcon") { + locationMarker?.iconImage = "personIcon" + locationMarker?.iconRotate = 0f + locationMarker?.iconSize = personIconSymbolOption?.iconSize ?:1f + } + animateCamera() + } } + } private fun setLocation(location: Location?) { @@ -233,18 +240,22 @@ class OSMVectorLocationManager( onUserLocationReady: (GeoPoint?) -> Unit, onUserLocationFailed: () -> Unit ) { - mapView.locationComponent.activateLocationComponent( + mapLibre.locationComponent.onStart() + mapLibre.locationComponent.activateLocationComponent( LocationComponentActivationOptions - .builder(context, mapView.style!!) + .builder(context, mapLibre.style!!) .useDefaultLocationEngine(true) .build() ) - mapView.locationComponent.isLocationComponentEnabled = true - mapView.locationComponent.cameraMode = CameraMode.NONE - mapView.locationComponent.locationEngine?.getLastLocation(object : + checkPermission() + mapLibre.locationComponent.isLocationComponentEnabled = true + mapLibre.locationComponent.cameraMode = CameraMode.NONE + mapLibre.locationComponent.locationEngine?.getLastLocation(object : LocationEngineCallback { override fun onSuccess(p0: LocationEngineResult?) { - mapView.locationComponent.isLocationComponentEnabled = false + checkPermission() + mapLibre.locationComponent.isLocationComponentEnabled = false + mapLibre.locationComponent.onStop() onUserLocationReady(p0?.lastLocation?.toGeoPoint()) } @@ -255,4 +266,40 @@ class OSMVectorLocationManager( }) } + override fun configurationFollow(enableStop: Boolean?,useDirectionIcon: Boolean? ) { + if(enableStop!= null){ + this.enableAutoStop = enableStop + } + if(useDirectionIcon!= null){ + this.useDirectionMarker = useDirectionIcon + } + } + private fun createMarker(latLng: LatLng){ + locationMarker = locationMarkerManager.create(personIconSymbolOption?.withLatLng(latLng)) + + } + private fun checkPermission() { + if (ActivityCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_FINE_LOCATION + ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_COARSE_LOCATION + ) != PackageManager.PERMISSION_GRANTED + ) { + return + } + } + private fun locationModeNone(){ + locationMode = LocationMode.NONE + } + private fun setFollowing() { + locationMode = when { + useDirectionMarker -> LocationMode.GPSBearing + else -> LocationMode.GPSOnly + } + + } + fun isFollowing() = locationMode == LocationMode.GPSBearing || locationMode == LocationMode.GPSOnly + } \ No newline at end of file diff --git a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterMapLibreView.kt b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterMapLibreView.kt index f434616e..5a1daa62 100644 --- a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterMapLibreView.kt +++ b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterMapLibreView.kt @@ -72,7 +72,6 @@ class FlutterMapLibreView( private var mapView: MapView? = null private var mapLibre: MapLibreMap? = null private var markerManager: SymbolManager? = null - private var markerStaticManager: SymbolManager? = null private var shapeManager: FillManager? = null private var lineManager: LineManager? = null @@ -133,6 +132,10 @@ class FlutterMapLibreView( mapView?.onResume() } + override fun onPause(owner: LifecycleOwner) { + super.onPause(owner) + mapView?.onPause() + } override fun onStop(owner: LifecycleOwner) { super.onStop(owner) locationManager?.onStop() @@ -179,16 +182,6 @@ class FlutterMapLibreView( result.success(200) } - MapMethodChannelCall.LocationMarkers -> { - val args = call.arguments!! as HashMap<*, *> - // update user marker and direction marker - val personIcon = (args["personIcon"] as ByteArray) - val arrowIcon = (args["arrowDirectionIcon"] as ByteArray) - customPersonMarkerIcon = personIcon.toBitmap() - customArrowMarkerIcon = arrowIcon.toBitmap() - locationManager?.setMarkerIcon(customPersonMarkerIcon, customArrowMarkerIcon) - result.success(200) - } MapMethodChannelCall.AddMarker -> { val args = call.arguments as HashMap<*, *> @@ -396,15 +389,6 @@ class FlutterMapLibreView( result.success(200) } - MapMethodChannelCall.StartLocationUpdating -> { - locationManager?.startLocationUpdating() - result.success(200) - } - - MapMethodChannelCall.StopLocationUpdating -> { - locationManager?.stopLocationUpdating() - result.success(200) - } MapMethodChannelCall.StaticPosition -> { val args = call.arguments as HashMap<*, *> @@ -447,6 +431,31 @@ class FlutterMapLibreView( MapMethodChannelCall.ToggleLayers -> { result.success(200) } + MapMethodChannelCall.LocationMarkers -> { + val args = call.arguments!! as HashMap<*, *> + // update user marker and direction marker + val personIcon = (args["personIcon"] as ByteArray) + val arrowIcon = (args["arrowDirectionIcon"] as ByteArray) + val factorPerson = args["personIconFactorSize"] as Double? ?:1.0 + val factorArrow = args["arrowDirectionIconFactorSize"] as Double? ?:1.0 + customPersonMarkerIcon = MarkerConfiguration( + markerIcon = personIcon.toBitmap(), + markerRotate = 0.0, + markerAnchor = Anchor(0.5f, 0.5f), + factorSize = factorPerson + ) + locationManager?.setMarkerIcon(customPersonMarkerIcon, Pair(arrowIcon.toBitmap(),factorArrow.toFloat())) + result.success(200) + } + MapMethodChannelCall.StartLocationUpdating -> { + locationManager?.startLocationUpdating() + result.success(200) + } + + MapMethodChannelCall.StopLocationUpdating -> { + locationManager?.stopLocationUpdating() + result.success(200) + } MapMethodChannelCall.TrackMe -> { val args = call.arguments as List<*> @@ -456,7 +465,8 @@ class FlutterMapLibreView( mapView?.getMapAsync { map -> map.uiSettings.isRotateGesturesEnabled = disableRotation } - locationManager?.toggleFollow(enableStopFollow) + locationManager?.configurationFollow(enableStopFollow,useDirectionMarker) + locationManager?.toggleFollow() result.success(200) } @@ -470,8 +480,11 @@ class FlutterMapLibreView( } MapMethodChannelCall.CurrentLocation -> { - locationManager?.currentUserPosition({ gp -> - result.success(gp?.toHashMap()) + locationManager?.currentUserPosition({ geoPoint -> + if(geoPoint != null){ + moveTo(geoPoint,mapLibre?.cameraPosition?.zoom,true) + } + result.success(200) }, { result.error("userLocationFailed", "userLocationFailed", "userLocationFailed") }) @@ -529,10 +542,8 @@ class FlutterMapLibreView( override var customMarkerIcon: Bitmap? = null - override var customPersonMarkerIcon: Bitmap? = null - - - override var customArrowMarkerIcon: Bitmap? = null + var customPersonMarkerIcon: MarkerConfiguration? = null + var customArrowMarkerIcon: MarkerConfiguration? = null override var staticMarkerIcon: HashMap = HashMap() override val staticPoints: HashMap> = HashMap>() @@ -553,19 +564,19 @@ class FlutterMapLibreView( } val style = Style.Builder().fromUri(styleURL) map.setStyle(style) { styleLoaded -> - markerManager = SymbolManager(mapView!!, mapLibre!!, map.style!!) + markerManager = SymbolManager(mapView!!, mapLibre!!, styleLoaded) lineManager = LineManager( mapView!!, mapLibre!!, - map.style!!, + styleLoaded, markerManager?.layerId, null, ) markerStaticManager = SymbolManager( mapView!!, mapLibre!!, - mapLibre!!.style!!, + styleLoaded, null, lineManager?.layerId ) @@ -574,10 +585,22 @@ class FlutterMapLibreView( mapView!!, mapLibre!!, mapLibre!!.style!!, lineManager?.layerId, null, ) - + locationManager = + OSMVectorLocationManager( + context, + mapLibre!!, + SymbolManager( + mapView!!, + mapLibre!!, + styleLoaded, + null, + markerManager?.layerId + ), + methodChannel, + "receiveUserLocation" + ) } - locationManager = - OSMVectorLocationManager(context, map, methodChannel, "receiveUserLocation") + map.cameraPosition = CameraPosition.Builder().target(configuration.point.toLngLat()) .zoom(configuration.initZoom).build() map.addOnMapClickListener { lng -> @@ -601,37 +624,14 @@ class FlutterMapLibreView( methodChannel.invokeMethod("receiveRegionIsChanging", hashMap) } - map.setGesturesManager( - AndroidGesturesManager(context).apply { - this.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener { - override fun onMoveBegin(p0: MoveGestureDetector): Boolean { - return true - } - - override fun onMove( - gesture: MoveGestureDetector, - p1: Float, - p2: Float - ): Boolean { - Log.d("onMove", gesture.toString()) - if (locationManager != null && locationManager!!.mIsFollowing && locationManager!!.enableAutoStop) { - locationManager?.stopCamera() - map.cancelTransitions() - } - return true - } - - override fun onMoveEnd( - p0: MoveGestureDetector, - p1: Float, - p2: Float - ) { - } - }) - }, - true, - true - ) + map.addOnCameraMoveStartedListener { reason -> + if (reason == MapLibreMap.OnCameraMoveStartedListener.REASON_API_GESTURE){ + if (locationManager != null && locationManager!!.isFollowing() && locationManager!!.enableAutoStop) { + locationManager?.stopCamera() + map.cancelTransitions() + } + } + } } diff --git a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterOsmView.kt b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterOsmView.kt index bf7f2443..ef8e2d9e 100644 --- a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterOsmView.kt +++ b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/FlutterOsmView.kt @@ -972,8 +972,8 @@ class FlutterOsmView( locationNewOverlay.enableMyLocation() } - locationNewOverlay.useDirectionMarker = useDirectionMarker - locationNewOverlay.toggleFollow(enableStopFollow) + locationNewOverlay.configurationFollow(enableStopFollow,useDirectionMarker) + locationNewOverlay.toggleFollow() when { locationNewOverlay.mIsFollowing -> { isTracking = true diff --git a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/OSMBase.kt b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/OSMBase.kt index 0b4359dc..e1fc0e20 100644 --- a/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/OSMBase.kt +++ b/android/src/main/kotlin/hamza/dali/flutter_osm_plugin/map/OSMBase.kt @@ -183,8 +183,6 @@ data class OSMLineConfiguration( interface OSMBase : OSM { var customMarkerIcon: Bitmap? - var customPersonMarkerIcon: Bitmap? - var customArrowMarkerIcon: Bitmap? var staticMarkerIcon: HashMap val staticPoints: HashMap> fun init(configuration: OSMInitConfiguration) diff --git a/example/.metadata b/example/.metadata index 01d2dcb9..fb51cb0b 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: 0b8abb4724aa590dd0f429683339b1e045a1594d - channel: stable + revision: "dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 + base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 + - platform: android + create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 + base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 3ee42985..16ee59cb 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,9 +1,8 @@ -//apply plugin: 'com.android.application' -//apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" plugins { - id "com.android.application" - //id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" //version "1.0.0" apply false + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" } def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') @@ -37,23 +36,28 @@ if (keystorePropertiesFile.exists()) { } def exist = keystorePropertiesFile.exists() android { - compileSdk 34 - namespace "hamza.dali.example" + namespace = "hamza.dali.example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion - lintOptions { - disable 'InvalidPackage' + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "hamza.dali.flutter_osm_plugin_example" - minSdkVersion 21 - targetSdkVersion 34 - - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - multiDexEnabled true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + applicationId = "hamza.dali.example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = 23 + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } if(exist) { signingConfigs { @@ -66,30 +70,19 @@ android { } } buildTypes { - if(exist){ - release { - signingConfig signingConfigs.release - } - }else{ - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug } - } - namespace 'hamza.dali.flutter_osm_plugin_example' } flutter { - source '../..' + source = "../.." } - dependencies { - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' def multidex_version = "2.0.1" implementation "androidx.multidex:multidex:$multidex_version" -} + +} \ No newline at end of file diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index f880684a..399f6981 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,6 @@ - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index a611a236..23a1d57d 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,24 +1,27 @@ - + + calls FlutterMain.startInitialization(this); in its onCreate method. + In most cases you can leave this as-is, but you if you want to provide + additional functionality it is fine to subclass or reimplement + FlutterApplication and put your custom class here. --> - + + android:icon="@mipmap/ic_launcher"> + + + + + + + diff --git a/example/android/app/src/main/java/hamza/dali/flutter_osm_plugin_example/MainActivity.java b/example/android/app/src/main/java/hamza/dali/flutter_osm_plugin_example/MainActivity.java deleted file mode 100644 index 179de7f8..00000000 --- a/example/android/app/src/main/java/hamza/dali/flutter_osm_plugin_example/MainActivity.java +++ /dev/null @@ -1,13 +0,0 @@ -package hamza.dali.flutter_osm_plugin_example; - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.engine.FlutterEngine; -import io.flutter.plugins.GeneratedPluginRegistrant; - -public class MainActivity extends FlutterActivity { - @Override - public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/example/android/app/src/main/kotlin/hamza/dali/example/MainActivity.kt b/example/android/app/src/main/kotlin/hamza/dali/example/MainActivity.kt new file mode 100644 index 00000000..a3aef2a1 --- /dev/null +++ b/example/android/app/src/main/kotlin/hamza/dali/example/MainActivity.kt @@ -0,0 +1,5 @@ +package hamza.dali.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/example/android/app/src/main/res/drawable-night/launch_background.xml b/example/android/app/src/main/res/drawable-night/launch_background.xml new file mode 100644 index 00000000..9d4bf4d7 --- /dev/null +++ b/example/android/app/src/main/res/drawable-night/launch_background.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml index c5176ba6..17c4f3cd 100644 --- a/example/android/app/src/main/res/drawable/launch_background.xml +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -9,4 +9,4 @@ android:gravity="center" android:src="@mipmap/ic_launcher" /> --> - + \ No newline at end of file diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..99f742a5 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index f880684a..399f6981 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,6 @@ - diff --git a/example/android/build.gradle b/example/android/build.gradle index 0ae09bd0..6b73e568 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,18 +1,3 @@ -buildscript { - - repositories { - google() - mavenCentral() - maven { url "https://jitpack.io" } - } - /* - dependencies { - classpath 'com.android.tools.build:gradle:8.1.3' - } - - */ -} - allprojects { repositories { google() @@ -21,12 +6,12 @@ allprojects { } } -rootProject.buildDir = '../build' +rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } tasks.register("clean", Delete) { diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 72a2514a..25971708 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,19 +1,3 @@ -## For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx1024m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -# -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -#Thu Nov 17 20:27:24 CET 2022 -org.gradle.jvmargs=-Xmx1024M -Dkotlin.daemon.jvm.options\="-Xmx1536M" +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true -android.defaults.buildfeatures.buildconfig=true -android.nonTransitiveRClass=false -android.nonFinalResIds=false diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 6eba597c..348c409e 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sat Dec 05 16:50:44 CET 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 7c2bd3a0..d9070533 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,11 +18,11 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.4" apply false + id "com.android.application" version '8.7.2' apply false id "org.jetbrains.kotlin.android" version "1.9.22" apply false } -include ':app' +include ":app" def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() @@ -36,4 +36,4 @@ plugins.each { name, path -> def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() include ":$name" project(":$name").projectDir = pluginDirectory -} +} \ No newline at end of file