Skip to content

Commit 24328fd

Browse files
authored
Merge branch 'release-0.23.0' into dependabot/github_actions/actions/checkout-5
2 parents fb36ea3 + 770c72d commit 24328fd

33 files changed

+1479
-285
lines changed

.github/workflows/flutter_beta.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
working-directory: maplibre_gl_example
1717
steps:
1818
- uses: actions/checkout@v5
19-
- uses: actions/setup-java@v4
19+
- uses: actions/setup-java@v5
2020
with:
2121
java-version: '17'
2222
distribution: 'temurin'

.github/workflows/flutter_ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ jobs:
8686
channel: stable
8787
cache: true
8888
- uses: bluefireteam/melos-action@v3
89-
- uses: actions/setup-java@v4
89+
- uses: actions/setup-java@v5
9090
with:
9191
java-version: '21'
9292
distribution: 'temurin'

maplibre_gl/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## UNRELEASED
2+
3+
### Breaking changes
4+
* `annotation` argument now replaces the previous `id` argument in the onFeatureDrag and onFeatureTapped callbacks. Existing implementations must be updated to use the new annotation parameter.
5+
6+
### Changed
7+
* Added `onFeatureHover` to the controller for listening to hover interactions.
8+
* Fixed: annotationConsumeTapEvents previously had no effect. This has been fixed, and it now properly controls whether tap events on annotations are consumed.
9+
* Fixed: Avoided calling notifyListeners() on a disposed controller.
10+
* Fixed: Internal event listeners wasn't properly removed/off in web.
11+
112
## [0.22.0](https://github.com/maplibre/flutter-maplibre-gl/compare/v0.21.0...v0.22.0)
213

314
### Breaking changes

maplibre_gl/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ constructor. The following formats are supported:
196196
3. Passing the style as a local file. create an JSON file in app directory (e.g.
197197
ApplicationDocumentsDirectory). Set the style string to the absolute path of
198198
this JSON file.
199-
4. Passing the raw JSON of the map style. This is only supported on Android.
199+
4. Passing the raw JSON of the map style.
200200

201201
### Tile sources requiring an API key
202202

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.maplibre.maplibregl;
2+
3+
import org.maplibre.android.module.http.HttpRequestUtil;
4+
import io.flutter.plugin.common.MethodChannel;
5+
import java.util.Map;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.ArrayList;
9+
import java.util.regex.Pattern;
10+
import okhttp3.OkHttpClient;
11+
import okhttp3.Request;
12+
import android.util.Log;
13+
14+
public class MapLibreCustomHttpInterceptor {
15+
private static final String TAG = "MapLibreCustomHttpInterceptor";
16+
public static final HashMap<String, String> CustomHeaders = new HashMap<>();
17+
public static final List<String> Filter = new ArrayList<>();
18+
19+
public static void setCustomHeaders(Map<String, String> headers, List<String> filter, MethodChannel.Result result) {
20+
CustomHeaders.clear();
21+
Filter.clear();
22+
23+
for (Map.Entry<String, String> entry : headers.entrySet()) {
24+
CustomHeaders.put(entry.getKey(), entry.getValue());
25+
Log.d(TAG, "Setting " + entry.getKey() + " to " + entry.getValue());
26+
}
27+
28+
for (String pattern : filter) {
29+
Filter.add(pattern);
30+
}
31+
32+
HttpRequestUtil.setOkHttpClient(getOkHttpClient().build());
33+
result.success(null);
34+
}
35+
36+
private static OkHttpClient.Builder getOkHttpClient() {
37+
try {
38+
return new OkHttpClient.Builder()
39+
.addNetworkInterceptor(
40+
chain -> {
41+
Request.Builder builder = chain.request().newBuilder();
42+
String url = chain.request().url().toString();
43+
44+
// Check if URL matches any filter pattern
45+
boolean shouldApplyHeaders = Filter.isEmpty();
46+
for (String pattern : Filter) {
47+
if (Pattern.matches(pattern, url)) {
48+
shouldApplyHeaders = true;
49+
break;
50+
}
51+
}
52+
53+
if (shouldApplyHeaders) {
54+
for (Map.Entry<String, String> header : CustomHeaders.entrySet()) {
55+
if (header.getKey() == null || header.getKey().trim().isEmpty()) {
56+
continue;
57+
}
58+
if (header.getValue() == null || header.getValue().trim().isEmpty()) {
59+
builder.removeHeader(header.getKey());
60+
} else {
61+
builder.header(header.getKey(), header.getValue());
62+
}
63+
}
64+
}
65+
66+
return chain.proceed(builder.build());
67+
});
68+
} catch (Exception e) {
69+
Log.e(TAG, "Error creating HTTP client: " + e.getMessage());
70+
throw new RuntimeException(e);
71+
}
72+
}
73+
}
74+

maplibre_gl/android/src/main/java/org/maplibre/maplibregl/MapLibreMapController.java

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
import org.maplibre.android.style.sources.VectorSource;
8181
import org.maplibre.geojson.Feature;
8282
import org.maplibre.geojson.FeatureCollection;
83+
import org.maplibre.android.net.ConnectivityReceiver;
8384

8485
import java.io.IOException;
8586
import java.io.InputStream;
@@ -923,6 +924,174 @@ public void onCancel() {
923924
result.success(false);
924925
break;
925926
}
927+
case "map#setMaximumFps":
928+
{
929+
final int fps = call.argument("fps");
930+
if (mapView != null) {
931+
mapView.setMaximumFps(fps);
932+
}
933+
result.success(null);
934+
break;
935+
}
936+
case "map#forceOnlineMode":
937+
{
938+
// Force online mode by setting connectivity to true
939+
if (mapView != null) {
940+
ConnectivityReceiver.instance(mapView.getContext()).setConnected(true);
941+
}
942+
result.success(null);
943+
break;
944+
}
945+
case "camera#ease":
946+
{
947+
final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapLibreMap, density);
948+
final Integer duration = call.argument("duration");
949+
950+
final OnCameraMoveFinishedListener onCameraMoveFinishedListener =
951+
new OnCameraMoveFinishedListener() {
952+
@Override
953+
public void onFinish() {
954+
super.onFinish();
955+
result.success(true);
956+
}
957+
958+
@Override
959+
public void onCancel() {
960+
super.onCancel();
961+
result.success(false);
962+
}
963+
};
964+
965+
if (cameraUpdate != null && duration != null && duration > 0) {
966+
// camera transformation not handled yet
967+
mapLibreMap.easeCamera(cameraUpdate, duration, false, onCameraMoveFinishedListener);
968+
} else if (cameraUpdate != null) {
969+
// camera transformation not handled yet
970+
mapLibreMap.easeCamera(cameraUpdate, onCameraMoveFinishedListener);
971+
} else {
972+
result.success(false);
973+
}
974+
break;
975+
}
976+
case "map#queryCameraPosition":
977+
{
978+
result.success(Convert.toJson(mapLibreMap.getCameraPosition()));
979+
break;
980+
}
981+
case "map#editGeoJsonSource":
982+
{
983+
boolean ret = false;
984+
if (mapLibreMap != null) {
985+
Style style = mapLibreMap.getStyle();
986+
if (style != null) {
987+
try {
988+
GeoJsonSource source = style.getSourceAs(call.argument("id"));
989+
if (source != null) {
990+
source.setGeoJson((String)call.argument("data"));
991+
ret = true;
992+
}
993+
} catch (Exception e) {}
994+
}
995+
}
996+
Map<String, Boolean> reply = new HashMap<>();
997+
reply.put("result", ret);
998+
result.success(reply);
999+
break;
1000+
}
1001+
case "map#editGeoJsonUrl":
1002+
{
1003+
boolean ret = false;
1004+
if (mapLibreMap != null) {
1005+
Style style = mapLibreMap.getStyle();
1006+
if (style != null) {
1007+
try {
1008+
GeoJsonSource source = style.getSourceAs(call.argument("id"));
1009+
if (source != null) {
1010+
source.setUrl((String)call.argument("url"));
1011+
ret = true;
1012+
}
1013+
} catch (Exception e) {}
1014+
}
1015+
}
1016+
Map<String, Boolean> reply = new HashMap<>();
1017+
reply.put("result", ret);
1018+
result.success(reply);
1019+
break;
1020+
}
1021+
case "map#setLayerFilter":
1022+
{
1023+
boolean ret = false;
1024+
if (mapLibreMap != null) {
1025+
Style style = mapLibreMap.getStyle();
1026+
if (style != null) {
1027+
try {
1028+
Layer layer = style.getLayer(call.argument("id"));
1029+
if (layer != null) {
1030+
String filter = call.argument("filter");
1031+
if (filter != null) {
1032+
Expression expression = Expression.raw(filter);
1033+
if (expression != null) {
1034+
if (layer instanceof LineLayer) {
1035+
((LineLayer)layer).setFilter(expression);
1036+
ret = true;
1037+
} else if (layer instanceof FillLayer) {
1038+
((FillLayer)layer).setFilter(expression);
1039+
ret = true;
1040+
} else if (layer instanceof SymbolLayer) {
1041+
((SymbolLayer)layer).setFilter(expression);
1042+
ret = true;
1043+
}
1044+
}
1045+
}
1046+
}
1047+
} catch (Exception e) {
1048+
e.printStackTrace();
1049+
}
1050+
}
1051+
}
1052+
Map<String, Boolean> reply = new HashMap<>();
1053+
reply.put("result", ret);
1054+
result.success(reply);
1055+
break;
1056+
}
1057+
case "map#getStyle":
1058+
{
1059+
Map<String, Object> reply = new HashMap<>();
1060+
boolean ret = false;
1061+
if (mapLibreMap != null) {
1062+
Style style = mapLibreMap.getStyle();
1063+
if (style != null) {
1064+
try {
1065+
String json = style.getJson();
1066+
reply.put("json", json);
1067+
ret = true;
1068+
} catch (Exception e) {}
1069+
}
1070+
}
1071+
reply.put("result", ret);
1072+
result.success(reply);
1073+
break;
1074+
}
1075+
case "map#setCustomHeaders":
1076+
{
1077+
if (mapLibreMap != null) {
1078+
HashMap<String, String> headers = (HashMap<String, String>)call.argument("headers");
1079+
List<String> filter = (List<String>)call.argument("filter");
1080+
MapLibreCustomHttpInterceptor.setCustomHeaders(headers, filter, result);
1081+
} else {
1082+
result.success(null);
1083+
}
1084+
break;
1085+
}
1086+
case "map#getCustomHeaders":
1087+
{
1088+
if (mapLibreMap != null) {
1089+
result.success(MapLibreCustomHttpInterceptor.CustomHeaders);
1090+
} else {
1091+
result.success(null);
1092+
}
1093+
break;
1094+
}
9261095
case "map#invalidateAmbientCache":
9271096
{
9281097
OfflineManager fileSource = OfflineManager.Companion.getInstance(context);

maplibre_gl/ios/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ Icon?
3737

3838
Package.resolved
3939
.swiftpm
40+
.build
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Foundation
2+
import MapLibre
3+
4+
public class MapLibreCustomHeaders {
5+
private static var customHeaders: [String: String] = [:]
6+
private static var filterPatterns: [String] = []
7+
8+
public static func setCustomHeaders(_ headers: [String: String], filter: [String]) {
9+
customHeaders = headers
10+
filterPatterns = filter
11+
12+
let sessionConfig = URLSessionConfiguration.default
13+
sessionConfig.httpAdditionalHeaders = headers
14+
MLNNetworkConfiguration.sharedManager.sessionConfiguration = sessionConfig
15+
}
16+
17+
public static func getCustomHeaders() -> [String: String] {
18+
return customHeaders
19+
}
20+
21+
public static func getFilterPatterns() -> [String] {
22+
return filterPatterns
23+
}
24+
25+
public static func shouldApplyHeaders(to url: String) -> Bool {
26+
if filterPatterns.isEmpty {
27+
return true
28+
}
29+
30+
for pattern in filterPatterns {
31+
if url.range(of: pattern, options: .regularExpression) != nil {
32+
return true
33+
}
34+
}
35+
36+
return false
37+
}
38+
}
39+

0 commit comments

Comments
 (0)