diff --git a/CHANGELOG.md b/CHANGELOG.md index f793020f..705ba361 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,147 +1,153 @@ # Changelog +## 1.5.0 + +- Swift Package Manager support (requires Flutter 3.44+); CocoaPods podspec kept in sync + ## 1.4.0 -* Flutter 3.27.1 compatibility, replace `ui.hash*` with `Object.hash* +- Flutter 3.27.1 compatibility, replace `ui.hash*` with `Object.hash\* ## 1.3.0 -* Animate marker position changes instead of removing and re-adding -* Fix Fatal error: Attempted to read an unowned reference but the object was already deallocated -* Fixed an issue where onCameraMove was not invoked by double-tapping -* Added insetsLayoutMarginsFromSafeArea +- Animate marker position changes instead of removing and re-adding +- Fix Fatal error: Attempted to read an unowned reference but the object was already deallocated +- Fixed an issue where onCameraMove was not invoked by double-tapping +- Added insetsLayoutMarginsFromSafeArea ## 1.2.0 -* Added a `markerAnnotationWithHue()` and `pinAnnotationWithHue()` method to allow custom marker/pin colors +- Added a `markerAnnotationWithHue()` and `pinAnnotationWithHue()` method to allow custom marker/pin colors ## 1.1.0 -* Added Annotation zIndex -* Added posibility to take snapshots of the map +- Added Annotation zIndex +- Added posibility to take snapshots of the map ## 1.0.3 -* Fixes an issue where mapController.moveCamera would animate the camera transition -* To animate a camera movement, mapController.animateCamera should be used instead +- Fixes an issue where mapController.moveCamera would animate the camera transition +- To animate a camera movement, mapController.animateCamera should be used instead ## 1.0.2 -* Removed Android folder to fix build failures +- Removed Android folder to fix build failures ## 1.0.1 -* Fixes memory leak -* Adds ability to take snapshots of the map +- Fixes memory leak +- Adds ability to take snapshots of the map + ## 1.0.0 Thanks to @jonbhanson -* Adds null safety. -* Refreshes the example app. -* Updates .gitignore and removes files that should not be tracked. + +- Adds null safety. +- Refreshes the example app. +- Updates .gitignore and removes files that should not be tracked. ## 0.1.4 -* Animate to bounds was added. (Thanks to @nghiashiyi) -* Fixed an issue where the user location was only displayed in `authorizationInUse` status. (Thanks to @zgosalvez) +- Animate to bounds was added. (Thanks to @nghiashiyi) +- Fixed an issue where the user location was only displayed in `authorizationInUse` status. (Thanks to @zgosalvez) -* minor fixes +- minor fixes ## 0.1.3 -* Thanks to @maxiundtesa the getter for the current zoomLevel was added -* iOS build failure for Flutter modules was fixed +- Thanks to @maxiundtesa the getter for the current zoomLevel was added +- iOS build failure for Flutter modules was fixed ## 0.1.2+5 -* Fixed build failure -* Added anchor param to Annotation -* Added missing comparison of Overlay coordinates, which caused +- Fixed build failure +- Added anchor param to Annotation +- Added missing comparison of Overlay coordinates, which caused Circles, Annotations, Polylines and Ploygons to not update correctly on coordinate changes. ## 0.1.2+4 -* Added configurable Anchor for infoWindows +- Added configurable Anchor for infoWindows ## 0.1.2+3 -* Fixed the offset of custom markers +- Fixed the offset of custom markers ## 0.1.2+2 -* Fixed the onTap event for Annotation Callouts +- Fixed the onTap event for Annotation Callouts ## 0.1.2+1 -* Added custom annotation icons from byte data -* Fixed scaling of icons from assets => see: https://flutter.dev/docs/development/ui/assets-and-images#declaring-resolution-aware-image-assets +- Added custom annotation icons from byte data +- Fixed scaling of icons from assets => see: https://flutter.dev/docs/development/ui/assets-and-images#declaring-resolution-aware-image-assets ## 0.1.2 -* Annotation rework: - * onTap for InfoWindow added - * Multiline InfoWindow subtitle support - * Overall Annotation handling refactored - * Correct UserTracking Button added +- Annotation rework: + - onTap for InfoWindow added + - Multiline InfoWindow subtitle support + - Overall Annotation handling refactored + - Correct UserTracking Button added ## 0.1.1+2 -* Fixed map freezing when setState is being called +- Fixed map freezing when setState is being called ## 0.1.1+1 -* Fixed Polygon and Circle Tap events. +- Fixed Polygon and Circle Tap events. ## 0.1.1 -* Added markerAnnotation as selectable annotation type. +- Added markerAnnotation as selectable annotation type. ## 0.1.0 -* Added ability to place circles on the map. +- Added ability to place circles on the map. ## 0.0.7 -* Added ability to place polygons on the map. +- Added ability to place polygons on the map. ## 0.0.6+4 -* Fixed build issues +- Fixed build issues ## 0.0.6+3 -* Fixes issue #6, location permission is only requested if it's actually used. +- Fixes issue #6, location permission is only requested if it's actually used. ## 0.0.6+2 -* Converted iOS code to swift 5. +- Converted iOS code to swift 5. ## 0.0.6+1 -* Changed annotation initialisation, fixes custom annotation icons not showing up on the map. +- Changed annotation initialisation, fixes custom annotation icons not showing up on the map. ## 0.0.6 -* Added ability to add padding to the map +- Added ability to add padding to the map ## 0.0.5 -* Added ability to place polylines. +- Added ability to place polylines. ## 0.0.4 -* Fixed error when updating Annotations on map. +- Fixed error when updating Annotations on map. ## 0.0.3 -* Added getter for visible map region. +- Added getter for visible map region. ## 0.0.2 -* Added zoomBy functionality. -* Added setter for min and max zoom levels. +- Added zoomBy functionality. +- Added setter for min and max zoom levels. ## 0.0.1 -* Initial release. +- Initial release. diff --git a/example/android/.project b/example/android/.project index f1817044..994fbc43 100644 --- a/example/android/.project +++ b/example/android/.project @@ -16,12 +16,12 @@ - 1601924530843 + 1792504847059 30 org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 8d4492f9..391a902b 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 9.0 diff --git a/ios/Assets/.gitkeep b/example/ios/Flutter/ephemeral/.swift_pm.lock similarity index 100% rename from ios/Assets/.gitkeep rename to example/ios/Flutter/ephemeral/.swift_pm.lock diff --git a/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift b/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift new file mode 100644 index 00000000..ef4bd1b5 --- /dev/null +++ b/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. +// +// Generated file. Do not edit. +// + +import PackageDescription + +let package = Package( + name: "FlutterGeneratedPluginSwiftPackage", + platforms: [ + .iOS("15.0") + ], + products: [ + .library(name: "FlutterGeneratedPluginSwiftPackage", type: .static, targets: ["FlutterGeneratedPluginSwiftPackage"]) + ], + dependencies: [ + + ], + targets: [ + .target( + name: "FlutterGeneratedPluginSwiftPackage" + ) + ] +) diff --git a/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift b/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift new file mode 100644 index 00000000..a30d95a8 --- /dev/null +++ b/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift @@ -0,0 +1,3 @@ +// +// Generated file. Do not edit. +// diff --git a/example/ios/Flutter/ephemeral/flutter_lldb_helper.py b/example/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 00000000..a88caf99 --- /dev/null +++ b/example/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/example/ios/Flutter/ephemeral/flutter_lldbinit b/example/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 00000000..e3ba6fbe --- /dev/null +++ b/example/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/example/ios/Flutter/ephemeral/flutter_native_integration.env b/example/ios/Flutter/ephemeral/flutter_native_integration.env new file mode 100644 index 00000000..03d45f83 --- /dev/null +++ b/example/ios/Flutter/ephemeral/flutter_native_integration.env @@ -0,0 +1,13 @@ +FLUTTER_ROOT=/Users/admin/Development/flutter +FLUTTER_APPLICATION_PATH=/Users/admin/Projects/apple_maps_flutter/example +FLUTTER_FRAMEWORK_SWIFT_PACKAGE_PATH=/Users/admin/Projects/apple_maps_flutter/example/ios/Flutter/ephemeral/Packages/.packages/FlutterFramework +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib/main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +DART_DEFINES=RkxVVFRFUl9CVUlMRF9OQU1FPTEuMC4w,RkxVVFRFUl9CVUlMRF9OVU1CRVI9MQ==,RkxVVFRFUl9WRVJTSU9OPTMuNDcuNw==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049YWJhZjljNTIzNw==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049ZGViMjg3NDgxZQ==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My4xMy41 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=false +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=/Users/admin/Projects/apple_maps_flutter/example/.dart_tool/package_config.json diff --git a/example/ios/Podfile b/example/ios/Podfile index 1e8c3c90..17ed9861 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '15.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index eff76023..d62e9312 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,22 +1,16 @@ PODS: - - apple_maps_flutter (0.0.1): - - Flutter - Flutter (1.0.0) DEPENDENCIES: - - apple_maps_flutter (from `.symlinks/plugins/apple_maps_flutter/ios`) - Flutter (from `Flutter`) EXTERNAL SOURCES: - apple_maps_flutter: - :path: ".symlinks/plugins/apple_maps_flutter/ios" Flutter: :path: Flutter SPEC CHECKSUMS: - apple_maps_flutter: c59725efea39e13e703cde52a1d2b14866ad68a8 - Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + Flutter: 71a624a5bc0c04062bf19101d501e466baf2fb47 -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c +PODFILE CHECKSUM: a938cb79d452854fa9f13c14ded5e356e38f0fc7 -COCOAPODS: 1.11.3 +COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index b74440f9..1125509a 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,13 +3,14 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 7E3ED54974DCE25524E09722 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5AB21804E11E2CF6CAB18B54 /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -36,6 +37,9 @@ 5AB21804E11E2CF6CAB18B54 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; + 78DABEA22ED26510000E7860 /* apple_maps_flutter */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = apple_maps_flutter; path = ../../ios/apple_maps_flutter; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -54,6 +58,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 7E3ED54974DCE25524E09722 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -75,6 +80,9 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78DABEA22ED26510000E7860 /* apple_maps_flutter */, + 784666492D4C4C64000A1A5F /* FlutterFramework */, + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -139,13 +147,15 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - A76139E19E24CB98ED0622B3 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -156,7 +166,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -174,6 +184,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -200,10 +213,12 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -236,6 +251,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -248,23 +264,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - A76139E19E24CB98ED0622B3 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -340,7 +339,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -358,7 +357,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -414,7 +416,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -463,7 +465,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -482,7 +484,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -501,7 +506,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -534,6 +542,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3db53b6e..0bd6d422 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,10 +1,28 @@ + + + + + + + + + + @@ -45,11 +64,13 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 70693e4a..c30b367e 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,13 +1,16 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 6f300aae..7d9e6577 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -24,6 +26,29 @@ NSLocationWhenInUseUsageDescription This App needs permission to access your location in order to show it on the map. + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + FlutterSceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -43,7 +68,5 @@ UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone - diff --git a/example/lib/map_click.dart b/example/lib/map_click.dart index 49510d4f..6ff8eacc 100644 --- a/example/lib/map_click.dart +++ b/example/lib/map_click.dart @@ -4,7 +4,6 @@ import 'package:apple_maps_flutter/apple_maps_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'page.dart'; @@ -30,11 +29,11 @@ class _MapClickBody extends StatefulWidget { } class _MapClickBodyState extends State<_MapClickBody> { - _MapClickBodyState(); - AppleMapController? mapController; + LatLng? _lastTap; LatLng? _lastLongPress; + _MapClickBodyState(); @override Widget build(BuildContext context) { diff --git a/example/lib/map_coordinates.dart b/example/lib/map_coordinates.dart index de28d54d..5d63b778 100644 --- a/example/lib/map_coordinates.dart +++ b/example/lib/map_coordinates.dart @@ -4,7 +4,6 @@ import 'package:apple_maps_flutter/apple_maps_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'page.dart'; @@ -30,13 +29,13 @@ class _MapCoordinatesBody extends StatefulWidget { } class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { - _MapCoordinatesBodyState(); - AppleMapController? mapController; + LatLngBounds _visibleRegion = LatLngBounds( southwest: const LatLng(0, 0), northeast: const LatLng(0, 0), ); + _MapCoordinatesBodyState(); @override Widget build(BuildContext context) { diff --git a/example/lib/place_annotation.dart b/example/lib/place_annotation.dart index 3a3e28b6..af615c71 100644 --- a/example/lib/place_annotation.dart +++ b/example/lib/place_annotation.dart @@ -4,8 +4,6 @@ import 'dart:async'; import 'dart:math'; -import 'dart:typed_data'; -import 'dart:ui'; import 'dart:ui' as ui; import 'package:apple_maps_flutter/apple_maps_flutter.dart'; @@ -14,14 +12,7 @@ import 'package:flutter/services.dart'; import 'page.dart'; -class PlaceAnnotationPage extends ExamplePage { - PlaceAnnotationPage() : super(const Icon(Icons.place), 'Place annotation'); - - @override - Widget build(BuildContext context) { - return const PlaceAnnotationBody(); - } -} +typedef Annotation AnnotationUpdateAction(Annotation annotation); class PlaceAnnotationBody extends StatefulWidget { const PlaceAnnotationBody(); @@ -30,13 +21,10 @@ class PlaceAnnotationBody extends StatefulWidget { State createState() => PlaceAnnotationBodyState(); } -typedef Annotation AnnotationUpdateAction(Annotation annotation); - class PlaceAnnotationBodyState extends State { - PlaceAnnotationBodyState(); static final LatLng center = const LatLng(-33.86711, 151.1947171); - late AppleMapController controller; + Uint8List? _imageBytes; Map annotations = {}; late AnnotationId selectedAnnotationId; @@ -44,9 +32,115 @@ class PlaceAnnotationBodyState extends State { BitmapDescriptor? _annotationIcon; late BitmapDescriptor _iconFromBytes; double _devicePixelRatio = 3.0; + PlaceAnnotationBodyState(); - void _onMapCreated(AppleMapController controller) { - this.controller = controller; + @override + Widget build(BuildContext context) { + _createAnnotationImageFromAsset(context, _devicePixelRatio); + _getBytesFromAsset('assets/creator.png', 160); + return SafeArea( + child: Column( + children: [ + Expanded( + child: AppleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11, + ), + annotations: Set.of(annotations.values), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + child: const Text('add defaultAnnotation'), + onPressed: () => _add('pin'), + ), + TextButton( + child: const Text('add defaultWithHue'), + onPressed: () => _add('defaultAnnotationWithColor'), + ), + TextButton( + child: const Text('add markerAnnotation'), + onPressed: () => _add('marker'), + ), + TextButton( + child: const Text('add markerWithHue'), + onPressed: () => _add('markerAnnotationWithHue'), + ), + TextButton( + child: const Text('add customAnnotation'), + onPressed: () => _add('customAnnotation'), + ), + TextButton( + child: const Text('customAnnotation from bytes'), + onPressed: () => _add('customAnnotationFromBytes'), + ), + TextButton( + child: const Text('remove'), + onPressed: _remove, + ), + TextButton( + child: const Text('change info'), + onPressed: _changeInfo, + ), + TextButton( + child: const Text('infoWindow is shown?s'), + onPressed: _isInfoWindowShown, + ), + TextButton( + child: const Text('change alpha'), + onPressed: _changeAlpha, + ), + TextButton( + child: const Text('toggle draggable'), + onPressed: _toggleDraggable, + ), + TextButton( + child: const Text('change position'), + onPressed: _changePosition, + ), + TextButton( + child: const Text('toggle visible'), + onPressed: _toggleVisible, + ), + TextButton( + child: const Text('show infoWindow'), + onPressed: _showInfoWindow, + ), + TextButton( + child: const Text('hide infoWindow'), + onPressed: _hideInfoWindow, + ), + TextButton( + child: const Text('change zIndex'), + onPressed: () => _changeZIndex(selectedAnnotationId), + ), + TextButton( + child: Text('Take a snapshot'), + onPressed: () async { + final imageBytes = await this.controller.takeSnapshot(); + setState(() { + _imageBytes = imageBytes; + }); + }, + ), + Container( + decoration: BoxDecoration(color: Colors.blueGrey[50]), + height: 180, + child: + _imageBytes != null ? Image.memory(_imageBytes!) : null, + ), + ], + ), + ) + ], + ), + ); } @override @@ -54,20 +148,6 @@ class PlaceAnnotationBodyState extends State { super.dispose(); } - void _onAnnotationTapped(AnnotationId annotationId) { - final Annotation? tappedAnnotation = annotations[annotationId]; - if (tappedAnnotation != null) { - setState(() { - if (annotations.containsKey(tappedAnnotation)) { - final Annotation resetOld = - annotations[selectedAnnotationId]!.copyWith(); - annotations[selectedAnnotationId] = resetOld; - } - selectedAnnotationId = annotationId; - }); - } - } - void _add(String iconType) { final int annotationCount = annotations.length; @@ -124,36 +204,12 @@ class PlaceAnnotationBodyState extends State { }); } - void _remove() { - setState(() { - if (annotations.containsKey(selectedAnnotationId)) { - annotations.remove(selectedAnnotationId); - } - }); - } - - void _changePosition() { - final Annotation annotation = annotations[selectedAnnotationId]!; - final LatLng current = annotation.position; - final Offset offset = Offset( - center.latitude - current.latitude, - center.longitude - current.longitude, - ); - setState(() { - annotations[selectedAnnotationId] = annotation.copyWith( - positionParam: LatLng( - center.latitude + offset.dy, - center.longitude + offset.dx, - ), - ); - }); - } - - Future _toggleDraggable() async { + Future _changeAlpha() async { final Annotation annotation = annotations[selectedAnnotationId]!; + final double current = annotation.alpha; setState(() { annotations[selectedAnnotationId] = annotation.copyWith( - draggableParam: !annotation.draggable, + alphaParam: current < 0.1 ? 1.0 : current * 0.75, ); }); } @@ -171,21 +227,29 @@ class PlaceAnnotationBodyState extends State { }); } - Future _changeAlpha() async { + void _changePosition() { final Annotation annotation = annotations[selectedAnnotationId]!; - final double current = annotation.alpha; + final LatLng current = annotation.position; + final Offset offset = Offset( + center.latitude - current.latitude, + center.longitude - current.longitude, + ); setState(() { annotations[selectedAnnotationId] = annotation.copyWith( - alphaParam: current < 0.1 ? 1.0 : current * 0.75, + positionParam: LatLng( + center.latitude + offset.dy, + center.longitude + offset.dx, + ), ); }); } - Future _toggleVisible() async { - final Annotation annotation = annotations[selectedAnnotationId]!; + Future _changeZIndex(AnnotationId annotationId) async { + final Annotation annotation = annotations[annotationId]!; + final double current = annotation.zIndex; setState(() { - annotations[selectedAnnotationId] = annotation.copyWith( - visibleParam: !annotation.visible, + annotations[annotationId] = annotation.copyWith( + zIndexParam: current >= 12.0 ? 0.0 : current + 1.0, ); }); } @@ -201,15 +265,15 @@ class PlaceAnnotationBodyState extends State { } } - void _updateBitmap(BitmapDescriptor bitmap) { - setState(() { - _annotationIcon = bitmap; - }); - } - - Future _showInfoWindow() async { - final Annotation annotation = annotations[selectedAnnotationId]!; - await this.controller.showMarkerInfoWindow(annotation.annotationId); + Future _getBytesFromAsset(String path, int width) async { + ByteData data = await rootBundle.load(path); + ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), + targetWidth: width); + ui.FrameInfo fi = await codec.getNextFrame(); + _iconFromBytes = BitmapDescriptor.fromBytes( + (await fi.image.toByteData(format: ui.ImageByteFormat.png))! + .buffer + .asUint8List()); } Future _hideInfoWindow() async { @@ -226,133 +290,67 @@ class PlaceAnnotationBodyState extends State { .isMarkerInfoWindowShown(annotation.annotationId))!; } - Future _getBytesFromAsset(String path, int width) async { - ByteData data = await rootBundle.load(path); - ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), - targetWidth: width); - ui.FrameInfo fi = await codec.getNextFrame(); - _iconFromBytes = BitmapDescriptor.fromBytes( - (await fi.image.toByteData(format: ui.ImageByteFormat.png))! - .buffer - .asUint8List()); + void _onAnnotationTapped(AnnotationId annotationId) { + final Annotation? tappedAnnotation = annotations[annotationId]; + if (tappedAnnotation != null) { + setState(() { + if (annotations.containsKey(tappedAnnotation)) { + final Annotation resetOld = + annotations[selectedAnnotationId]!.copyWith(); + annotations[selectedAnnotationId] = resetOld; + } + selectedAnnotationId = annotationId; + }); + } } - Future _changeZIndex(AnnotationId annotationId) async { - final Annotation annotation = annotations[annotationId]!; - final double current = annotation.zIndex; + void _onMapCreated(AppleMapController controller) { + this.controller = controller; + } + + void _remove() { setState(() { - annotations[annotationId] = annotation.copyWith( - zIndexParam: current >= 12.0 ? 0.0 : current + 1.0, + if (annotations.containsKey(selectedAnnotationId)) { + annotations.remove(selectedAnnotationId); + } + }); + } + + Future _showInfoWindow() async { + final Annotation annotation = annotations[selectedAnnotationId]!; + await this.controller.showMarkerInfoWindow(annotation.annotationId); + } + + Future _toggleDraggable() async { + final Annotation annotation = annotations[selectedAnnotationId]!; + setState(() { + annotations[selectedAnnotationId] = annotation.copyWith( + draggableParam: !annotation.draggable, ); }); } + Future _toggleVisible() async { + final Annotation annotation = annotations[selectedAnnotationId]!; + setState(() { + annotations[selectedAnnotationId] = annotation.copyWith( + visibleParam: !annotation.visible, + ); + }); + } + + void _updateBitmap(BitmapDescriptor bitmap) { + setState(() { + _annotationIcon = bitmap; + }); + } +} + +class PlaceAnnotationPage extends ExamplePage { + PlaceAnnotationPage() : super(const Icon(Icons.place), 'Place annotation'); + @override Widget build(BuildContext context) { - _createAnnotationImageFromAsset(context, _devicePixelRatio); - _getBytesFromAsset('assets/creator.png', 160); - return SafeArea( - child: Column( - children: [ - Expanded( - child: AppleMap( - onMapCreated: _onMapCreated, - initialCameraPosition: const CameraPosition( - target: LatLng(-33.852, 151.211), - zoom: 11, - ), - annotations: Set.of(annotations.values), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - alignment: WrapAlignment.spaceEvenly, - children: [ - TextButton( - child: const Text('add defaultAnnotation'), - onPressed: () => _add('pin'), - ), - TextButton( - child: const Text('add defaultWithHue'), - onPressed: () => _add('defaultAnnotationWithColor'), - ), - TextButton( - child: const Text('add markerAnnotation'), - onPressed: () => _add('marker'), - ), - TextButton( - child: const Text('add markerWithHue'), - onPressed: () => _add('markerAnnotationWithHue'), - ), - TextButton( - child: const Text('add customAnnotation'), - onPressed: () => _add('customAnnotation'), - ), - TextButton( - child: const Text('customAnnotation from bytes'), - onPressed: () => _add('customAnnotationFromBytes'), - ), - TextButton( - child: const Text('remove'), - onPressed: _remove, - ), - TextButton( - child: const Text('change info'), - onPressed: _changeInfo, - ), - TextButton( - child: const Text('infoWindow is shown?s'), - onPressed: _isInfoWindowShown, - ), - TextButton( - child: const Text('change alpha'), - onPressed: _changeAlpha, - ), - TextButton( - child: const Text('toggle draggable'), - onPressed: _toggleDraggable, - ), - TextButton( - child: const Text('change position'), - onPressed: _changePosition, - ), - TextButton( - child: const Text('toggle visible'), - onPressed: _toggleVisible, - ), - TextButton( - child: const Text('show infoWindow'), - onPressed: _showInfoWindow, - ), - TextButton( - child: const Text('hide infoWindow'), - onPressed: _hideInfoWindow, - ), - TextButton( - child: const Text('change zIndex'), - onPressed: () => _changeZIndex(selectedAnnotationId), - ), - TextButton( - child: Text('Take a snapshot'), - onPressed: () async { - final imageBytes = await this.controller.takeSnapshot(); - setState(() { - _imageBytes = imageBytes; - }); - }, - ), - Container( - decoration: BoxDecoration(color: Colors.blueGrey[50]), - height: 180, - child: - _imageBytes != null ? Image.memory(_imageBytes!) : null, - ), - ], - ), - ) - ], - ), - ); + return const PlaceAnnotationBody(); } } diff --git a/example/lib/scrolling_map.dart b/example/lib/scrolling_map.dart index 4b6143ac..3e043c7e 100644 --- a/example/lib/scrolling_map.dart +++ b/example/lib/scrolling_map.dart @@ -8,24 +8,14 @@ import 'package:apple_maps_flutter/apple_maps_flutter.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'page.dart'; -class ScrollingMapPage extends ExamplePage { - ScrollingMapPage() : super(const Icon(Icons.map), 'Scrolling map'); - - @override - Widget build(BuildContext context) { - return const ScrollingMapBody(); - } -} - class ScrollingMapBody extends StatelessWidget { - const ScrollingMapBody(); - final LatLng center = const LatLng(32.080664, 34.9563837); + const ScrollingMapBody(); + @override Widget build(BuildContext context) { return SafeArea( @@ -113,3 +103,12 @@ class ScrollingMapBody extends StatelessWidget { ); } } + +class ScrollingMapPage extends ExamplePage { + ScrollingMapPage() : super(const Icon(Icons.map), 'Scrolling map'); + + @override + Widget build(BuildContext context) { + return const ScrollingMapBody(); + } +} diff --git a/example/test_driver/test_widgets.dart b/example/test_driver/test_widgets.dart index d2c27fd9..5656c9f5 100644 --- a/example/test_driver/test_widgets.dart +++ b/example/test_driver/test_widgets.dart @@ -8,5 +8,5 @@ import 'package:flutter/widgets.dart'; Future pumpWidget(Widget widget) { runApp(widget); - return WidgetsBinding.instance!.endOfFrame; + return WidgetsBinding.instance.endOfFrame; } diff --git a/ios/.gitignore b/ios/.gitignore index 710ec6cf..e4f8f29c 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -9,6 +9,8 @@ profile DerivedData/ build/ +.build/ +.swiftpm/ GeneratedPluginRegistrant.h GeneratedPluginRegistrant.m diff --git a/ios/Classes/AppleMapsFlutterPlugin.h b/ios/Classes/AppleMapsFlutterPlugin.h deleted file mode 100644 index 7ca9bfbc..00000000 --- a/ios/Classes/AppleMapsFlutterPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface AppleMapsFlutterPlugin : NSObject -@end diff --git a/ios/Classes/AppleMapsFlutterPlugin.m b/ios/Classes/AppleMapsFlutterPlugin.m deleted file mode 100644 index 13164091..00000000 --- a/ios/Classes/AppleMapsFlutterPlugin.m +++ /dev/null @@ -1,8 +0,0 @@ -#import "AppleMapsFlutterPlugin.h" -#import - -@implementation AppleMapsFlutterPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - [SwiftAppleMapsFlutterPlugin registerWithRegistrar:registrar]; -} -@end diff --git a/ios/apple_maps_flutter.podspec b/ios/apple_maps_flutter.podspec index 1bad1794..2eb73877 100644 --- a/ios/apple_maps_flutter.podspec +++ b/ios/apple_maps_flutter.podspec @@ -12,10 +12,9 @@ A new flutter plugin project. s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' + s.source_files = 'apple_maps_flutter/Sources/apple_maps_flutter/**/*.swift' s.dependency 'Flutter' - s.ios.deployment_target = '9.0' + s.ios.deployment_target = '13.0' s.swift_version = '5.0' end diff --git a/ios/apple_maps_flutter/Package.swift b/ios/apple_maps_flutter/Package.swift new file mode 100644 index 00000000..6b154d03 --- /dev/null +++ b/ios/apple_maps_flutter/Package.swift @@ -0,0 +1,24 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "apple_maps_flutter", + platforms: [ + .iOS("13.0") + ], + products: [ + .library(name: "apple-maps-flutter", targets: ["apple_maps_flutter"]) + ], + dependencies: [ + .package(name: "FlutterFramework", path: "../FlutterFramework") + ], + targets: [ + .target( + name: "apple_maps_flutter", + dependencies: [ + .product(name: "FlutterFramework", package: "FlutterFramework") + ] + ) + ] +) diff --git a/ios/Classes/Annotations/AnnotationController.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationController.swift similarity index 99% rename from ios/Classes/Annotations/AnnotationController.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationController.swift index 09bf6b27..9aadb753 100644 --- a/ios/Classes/Annotations/AnnotationController.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationController.swift @@ -1,3 +1,4 @@ +import Flutter // // AnnotationController.swift // apple_maps_flutter diff --git a/ios/Classes/Annotations/AnnotationDelegate.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationDelegate.swift similarity index 97% rename from ios/Classes/Annotations/AnnotationDelegate.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationDelegate.swift index 83f6798f..37fc23e2 100644 --- a/ios/Classes/Annotations/AnnotationDelegate.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationDelegate.swift @@ -1,3 +1,4 @@ +import Flutter // // AnnotationDelegate.swift // apple_maps_flutter diff --git a/ios/Classes/Annotations/AnnotationIcon.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationIcon.swift similarity index 99% rename from ios/Classes/Annotations/AnnotationIcon.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationIcon.swift index 85b04f7c..91f6c1a4 100644 --- a/ios/Classes/Annotations/AnnotationIcon.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/AnnotationIcon.swift @@ -1,3 +1,4 @@ +import Flutter // // AnnotationIcon.swift // apple_maps_flutter diff --git a/ios/Classes/Annotations/FlutterAnnotation.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/FlutterAnnotation.swift similarity index 99% rename from ios/Classes/Annotations/FlutterAnnotation.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/FlutterAnnotation.swift index 5e29e799..db25ac5e 100644 --- a/ios/Classes/Annotations/FlutterAnnotation.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/FlutterAnnotation.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterAnnotation.swift // apple_maps_flutter diff --git a/ios/Classes/Annotations/FlutterAnnotationView.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/FlutterAnnotationView.swift similarity index 99% rename from ios/Classes/Annotations/FlutterAnnotationView.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/FlutterAnnotationView.swift index 70e4b26c..d8fcb8c9 100644 --- a/ios/Classes/Annotations/FlutterAnnotationView.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Annotations/FlutterAnnotationView.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterAnnotationView.swift // apple_maps_flutter diff --git a/ios/Classes/MapView/AppleMapController.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/AppleMapController.swift similarity index 97% rename from ios/Classes/MapView/AppleMapController.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/AppleMapController.swift index 85e7a981..e8ca2f3e 100644 --- a/ios/Classes/MapView/AppleMapController.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/AppleMapController.swift @@ -1,3 +1,4 @@ +import Flutter // // AppleMapController.swift // apple_maps_flutter @@ -59,7 +60,13 @@ public class AppleMapController: NSObject, FlutterPlatformView { } private func setMethodCallHandlers() { - channel.setMethodCallHandler({ [unowned self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + // `weak`, not `unowned`: Dart can still send calls (pending widget + // updates, camera moves) after the platform view was disposed. + channel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + guard let self = self else { + result(nil) + return + } if let args: Dictionary = call.arguments as? Dictionary { switch(call.method) { case "annotations#update": diff --git a/ios/Classes/MapView/AppleMapsViewFactory.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/AppleMapsViewFactory.swift similarity index 98% rename from ios/Classes/MapView/AppleMapsViewFactory.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/AppleMapsViewFactory.swift index 2d01ad6e..97ee0fae 100644 --- a/ios/Classes/MapView/AppleMapsViewFactory.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/AppleMapsViewFactory.swift @@ -1,3 +1,4 @@ +import Flutter // // AppleMapsViewFactory.swift // apple_maps_flutter diff --git a/ios/Classes/MapView/FlutterMapView.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/FlutterMapView.swift similarity index 99% rename from ios/Classes/MapView/FlutterMapView.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/FlutterMapView.swift index 1e733edc..93ffc1cd 100644 --- a/ios/Classes/MapView/FlutterMapView.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/FlutterMapView.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterAppleMap.swift // apple_maps_flutter diff --git a/ios/Classes/MapView/MapViewExtension.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/MapViewExtension.swift similarity index 100% rename from ios/Classes/MapView/MapViewExtension.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/MapView/MapViewExtension.swift diff --git a/ios/Classes/Overlays/FlutterOverlay.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/FlutterOverlay.swift similarity index 94% rename from ios/Classes/Overlays/FlutterOverlay.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/FlutterOverlay.swift index 1258b3db..c2789e8e 100644 --- a/ios/Classes/Overlays/FlutterOverlay.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/FlutterOverlay.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterOverlay.swift // apple_maps_flutter diff --git a/ios/Classes/Overlays/Polygons/FlutterPolygon.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/FlutterPolygon.swift similarity index 99% rename from ios/Classes/Overlays/Polygons/FlutterPolygon.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/FlutterPolygon.swift index 190b080b..a346fc63 100644 --- a/ios/Classes/Overlays/Polygons/FlutterPolygon.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/FlutterPolygon.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterPolygon.swift // apple_maps_flutter diff --git a/ios/Classes/Overlays/Polygons/PolygonController.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/PolygonController.swift similarity index 99% rename from ios/Classes/Overlays/Polygons/PolygonController.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/PolygonController.swift index 87c51132..08b0b29e 100644 --- a/ios/Classes/Overlays/Polygons/PolygonController.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/PolygonController.swift @@ -1,3 +1,4 @@ +import Flutter // // PolygonController.swift // apple_maps_flutter diff --git a/ios/Classes/Overlays/Polygons/PolygonDelegate.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/PolygonDelegate.swift similarity index 100% rename from ios/Classes/Overlays/Polygons/PolygonDelegate.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polygons/PolygonDelegate.swift diff --git a/ios/Classes/Overlays/Polylines/FlutterPolyline.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/FlutterPolyline.swift similarity index 99% rename from ios/Classes/Overlays/Polylines/FlutterPolyline.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/FlutterPolyline.swift index 8b583dbc..79c24547 100644 --- a/ios/Classes/Overlays/Polylines/FlutterPolyline.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/FlutterPolyline.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterPolyline.swift // apple_maps_flutter diff --git a/ios/Classes/Overlays/Polylines/PolylineController.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/PolylineController.swift similarity index 99% rename from ios/Classes/Overlays/Polylines/PolylineController.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/PolylineController.swift index 8e297576..9412ac2a 100644 --- a/ios/Classes/Overlays/Polylines/PolylineController.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/PolylineController.swift @@ -1,3 +1,4 @@ +import Flutter // // PolylineController.swift // apple_maps_flutter diff --git a/ios/Classes/Overlays/Polylines/PolylineDelegate.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/PolylineDelegate.swift similarity index 100% rename from ios/Classes/Overlays/Polylines/PolylineDelegate.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/Polylines/PolylineDelegate.swift diff --git a/ios/Classes/Overlays/circles/CircleController.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/CircleController.swift similarity index 99% rename from ios/Classes/Overlays/circles/CircleController.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/CircleController.swift index bf897713..37ab71a0 100644 --- a/ios/Classes/Overlays/circles/CircleController.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/CircleController.swift @@ -1,3 +1,4 @@ +import Flutter // // CircleController.swift // apple_maps_flutter diff --git a/ios/Classes/Overlays/circles/CircleDelegate.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/CircleDelegate.swift similarity index 100% rename from ios/Classes/Overlays/circles/CircleDelegate.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/CircleDelegate.swift diff --git a/ios/Classes/Overlays/circles/FlutterCircle.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/FlutterCircle.swift similarity index 99% rename from ios/Classes/Overlays/circles/FlutterCircle.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/FlutterCircle.swift index 7371b32b..07dd98c2 100644 --- a/ios/Classes/Overlays/circles/FlutterCircle.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Overlays/circles/FlutterCircle.swift @@ -1,3 +1,4 @@ +import Flutter // // FlutterCircle.swift // apple_maps_flutter diff --git a/ios/Classes/SwiftAppleMapsFlutterPlugin.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/SwiftAppleMapsFlutterPlugin.swift similarity index 100% rename from ios/Classes/SwiftAppleMapsFlutterPlugin.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/SwiftAppleMapsFlutterPlugin.swift diff --git a/ios/Classes/Utils/JsonConversion.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/JsonConversion.swift similarity index 100% rename from ios/Classes/Utils/JsonConversion.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/JsonConversion.swift diff --git a/ios/Classes/Utils/TouchHandler.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/TouchHandler.swift similarity index 99% rename from ios/Classes/Utils/TouchHandler.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/TouchHandler.swift index e14644f8..82413773 100644 --- a/ios/Classes/Utils/TouchHandler.swift +++ b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/TouchHandler.swift @@ -1,3 +1,4 @@ +import Flutter // // TouchHandler.swift // apple_maps_flutter diff --git a/ios/Classes/Utils/Utils.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/Utils.swift similarity index 100% rename from ios/Classes/Utils/Utils.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/Utils/Utils.swift diff --git a/ios/Classes/models/SnapshotOptions.swift b/ios/apple_maps_flutter/Sources/apple_maps_flutter/models/SnapshotOptions.swift similarity index 100% rename from ios/Classes/models/SnapshotOptions.swift rename to ios/apple_maps_flutter/Sources/apple_maps_flutter/models/SnapshotOptions.swift diff --git a/lib/apple_maps_flutter.dart b/lib/apple_maps_flutter.dart index dccdfc81..84aff660 100644 --- a/lib/apple_maps_flutter.dart +++ b/lib/apple_maps_flutter.dart @@ -5,31 +5,28 @@ library apple_maps_flutter; import 'dart:async'; -import 'dart:typed_data'; -import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; part 'src/annotation.dart'; part 'src/annotation_updates.dart'; part 'src/apple_map.dart'; part 'src/bitmap.dart'; -part 'src/cap.dart'; part 'src/callbacks.dart'; part 'src/camera.dart'; +part 'src/cap.dart'; part 'src/circle.dart'; part 'src/circle_updates.dart'; part 'src/controller.dart'; part 'src/joint_type.dart'; part 'src/location.dart'; part 'src/pattern_item.dart'; -part 'src/polyline.dart'; -part 'src/polyline_updates.dart'; part 'src/polygon.dart'; part 'src/polygon_updates.dart'; -part 'src/ui.dart'; +part 'src/polyline.dart'; +part 'src/polyline_updates.dart'; part 'src/snapshot_options.dart'; +part 'src/ui.dart'; diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart index 71b6b12d..5f2e48ce 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation.dart @@ -4,6 +4,16 @@ part of apple_maps_flutter; +Map _keyByAnnotationId( + Iterable? annotations) { + if (annotations == null) { + return {}; + } + return Map.fromEntries(annotations.map( + (Annotation annotation) => MapEntry( + annotation.annotationId, annotation))); +} + dynamic _offsetToJson(Offset? offset) { if (offset == null) { return null; @@ -11,117 +21,14 @@ dynamic _offsetToJson(Offset? offset) { return [offset.dx, offset.dy]; } -/// Text labels for a [Annotation] info window. -class InfoWindow { - const InfoWindow({ - this.title, - this.snippet, - this.anchor = const Offset(0.5, 0.0), - this.onTap, - }); - - /// Text labels specifying that no text is to be displayed. - static const InfoWindow noText = InfoWindow(); - - /// Text displayed in an info window when the user taps the annotation. - /// - /// A null value means no title. - final String? title; - - /// Additional text displayed below the [title]. - /// - /// A null value means no additional text. - final String? snippet; - - /// The icon image point that will be the anchor of the info window when - /// displayed. - /// - /// The image point is specified in normalized coordinates: An anchor of - /// (0.0, 0.0) means the top left corner of the image. An anchor - /// of (1.0, 1.0) means the bottom right corner of the image. - final Offset anchor; - - /// onTap callback for this [InfoWindow]. - final VoidCallback? onTap; - - /// Creates a new [InfoWindow] object whose values are the same as this instance, - /// unless overwritten by the specified parameters. - InfoWindow copyWith({ - String? titleParam, - String? snippetParam, - Offset? anchorParam, - VoidCallback? onTapParam, - }) { - return InfoWindow( - title: titleParam ?? title, - snippet: snippetParam ?? snippet, - anchor: anchorParam ?? anchor, - onTap: onTapParam ?? onTap, - ); - } - - dynamic _toJson() { - final Map json = {}; - - void addIfPresent(String fieldName, dynamic value) { - if (value != null) { - json[fieldName] = value; - } - } - - addIfPresent('title', title); - addIfPresent('snippet', snippet); - addIfPresent('anchor', _offsetToJson(anchor)); - addIfPresent('consumesTapEvents', onTap != null); - - return json; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! InfoWindow) return false; - final InfoWindow typedOther = other; - return title == typedOther.title && - snippet == typedOther.snippet && - anchor == typedOther.anchor && - onTap == typedOther.onTap; - } - - @override - int get hashCode => Object.hash(title.hashCode, snippet, anchor); - - @override - String toString() { - return 'InfoWindow{title: $title, snippet: $snippet, anchor: $anchor, consumesTapEvents: ${onTap != null}}'; - } -} - -/// Uniquely identifies a [Annotation] among [AppleMap] annotations. -/// -/// This does not have to be globally unique, only unique among the list. -@immutable -class AnnotationId { - AnnotationId(this.value); - - /// value of the [AnnotationId]. - final String value; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! AnnotationId) return false; - final AnnotationId typedOther = other; - return value == typedOther.value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() { - return 'AnnotationId{value: $value}'; +List>? _serializeAnnotationSet( + Set? annotations) { + if (annotations == null) { + return null; } + return annotations + .map>((Annotation m) => m._toJson()) + .toList(); } /// Marks a geographical location on the map. @@ -131,32 +38,6 @@ class AnnotationId { /// due to map rotations, tilting, or zooming. @immutable class Annotation { - /// Creates a set of annotation configuration options. - /// - /// Default annotation options. - /// - /// Specifies a annotation that - /// * is fully opaque; [alpha] is 1.0 - /// * has default tap handling; [consumeTapEvents] is false - /// * is stationary; [draggable] is false - /// * has a default icon; [icon] is default Pin Annotation - /// * has no info window text; [infoWindowText] is `InfoWindowText.noText` - /// * is positioned at 0, 0; [position] is `LatLng(0.0, 0.0)` - /// * is visible; [visible] is true - Annotation({ - required this.annotationId, - this.alpha = 1.0, - this.anchor = const Offset(0.5, 1.0), - this.draggable = false, - this.icon = BitmapDescriptor.defaultAnnotation, - this.infoWindow = InfoWindow.noText, - this.position = const LatLng(0.0, 0.0), - this.onTap, - this.visible = true, - this.zIndex = -1, - this.onDragEnd, - }) : assert(0.0 <= alpha && alpha <= 1.0); - /// Uniquely identifies a [Annotation]. final AnnotationId annotationId; @@ -201,6 +82,51 @@ class Annotation { /// earlier, and thus appearing to be closer to the surface of the Earth. double zIndex; + /// Creates a set of annotation configuration options. + /// + /// Default annotation options. + /// + /// Specifies a annotation that + /// * is fully opaque; [alpha] is 1.0 + /// * has default tap handling; [consumeTapEvents] is false + /// * is stationary; [draggable] is false + /// * has a default icon; [icon] is default Pin Annotation + /// * has no info window text; [infoWindowText] is `InfoWindowText.noText` + /// * is positioned at 0, 0; [position] is `LatLng(0.0, 0.0)` + /// * is visible; [visible] is true + Annotation({ + required this.annotationId, + this.alpha = 1.0, + this.anchor = const Offset(0.5, 1.0), + this.draggable = false, + this.icon = BitmapDescriptor.defaultAnnotation, + this.infoWindow = InfoWindow.noText, + this.position = const LatLng(0.0, 0.0), + this.onTap, + this.visible = true, + this.zIndex = -1, + this.onDragEnd, + }) : assert(0.0 <= alpha && alpha <= 1.0); + + @override + int get hashCode => annotationId.hashCode; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! Annotation) return false; + final Annotation typedOther = other; + return annotationId == typedOther.annotationId && + alpha == typedOther.alpha && + anchor == typedOther.anchor && + draggable == typedOther.draggable && + icon == typedOther.icon && + infoWindow == typedOther.infoWindow && + position == typedOther.position && + visible == typedOther.visible && + zIndex == typedOther.zIndex; + } + /// Creates a new [Annotation] object whose values are the same as this instance, /// unless overwritten by the specified parameters. Annotation copyWith({ @@ -231,6 +157,13 @@ class Annotation { ); } + @override + String toString() { + return 'Annotation{annotationId: $annotationId, alpha: $alpha, draggable: $draggable, ' + 'icon: $icon, infoWindow: $infoWindow, position: $position ,visible: $visible, ' + 'onTap: $onTap}, zIndex: $zIndex, onTap: $onTap}'; + } + Map _toJson() { final Map json = {}; @@ -251,50 +184,117 @@ class Annotation { addIfPresent('zIndex', zIndex); return json; } +} + +/// Uniquely identifies a [Annotation] among [AppleMap] annotations. +/// +/// This does not have to be globally unique, only unique among the list. +@immutable +class AnnotationId { + /// value of the [AnnotationId]. + final String value; + + AnnotationId(this.value); + + @override + int get hashCode => value.hashCode; @override bool operator ==(Object other) { if (identical(this, other)) return true; - if (other is! Annotation) return false; - final Annotation typedOther = other; - return annotationId == typedOther.annotationId && - alpha == typedOther.alpha && - anchor == typedOther.anchor && - draggable == typedOther.draggable && - icon == typedOther.icon && - infoWindow == typedOther.infoWindow && - position == typedOther.position && - visible == typedOther.visible && - zIndex == typedOther.zIndex; + if (other is! AnnotationId) return false; + final AnnotationId typedOther = other; + return value == typedOther.value; } - @override - int get hashCode => annotationId.hashCode; - @override String toString() { - return 'Annotation{annotationId: $annotationId, alpha: $alpha, draggable: $draggable, ' - 'icon: $icon, infoWindow: $infoWindow, position: $position ,visible: $visible, ' - 'onTap: $onTap}, zIndex: $zIndex, onTap: $onTap}'; + return 'AnnotationId{value: $value}'; } } -Map _keyByAnnotationId( - Iterable? annotations) { - if (annotations == null) { - return {}; +/// Text labels for a [Annotation] info window. +class InfoWindow { + /// Text labels specifying that no text is to be displayed. + static const InfoWindow noText = InfoWindow(); + + /// Text displayed in an info window when the user taps the annotation. + /// + /// A null value means no title. + final String? title; + + /// Additional text displayed below the [title]. + /// + /// A null value means no additional text. + final String? snippet; + + /// The icon image point that will be the anchor of the info window when + /// displayed. + /// + /// The image point is specified in normalized coordinates: An anchor of + /// (0.0, 0.0) means the top left corner of the image. An anchor + /// of (1.0, 1.0) means the bottom right corner of the image. + final Offset anchor; + + /// onTap callback for this [InfoWindow]. + final VoidCallback? onTap; + + const InfoWindow({ + this.title, + this.snippet, + this.anchor = const Offset(0.5, 0.0), + this.onTap, + }); + + @override + int get hashCode => Object.hash(title.hashCode, snippet, anchor); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! InfoWindow) return false; + final InfoWindow typedOther = other; + return title == typedOther.title && + snippet == typedOther.snippet && + anchor == typedOther.anchor && + onTap == typedOther.onTap; } - return Map.fromEntries(annotations.map( - (Annotation annotation) => MapEntry( - annotation.annotationId, annotation))); -} -List>? _serializeAnnotationSet( - Set? annotations) { - if (annotations == null) { - return null; + /// Creates a new [InfoWindow] object whose values are the same as this instance, + /// unless overwritten by the specified parameters. + InfoWindow copyWith({ + String? titleParam, + String? snippetParam, + Offset? anchorParam, + VoidCallback? onTapParam, + }) { + return InfoWindow( + title: titleParam ?? title, + snippet: snippetParam ?? snippet, + anchor: anchorParam ?? anchor, + onTap: onTapParam ?? onTap, + ); + } + + @override + String toString() { + return 'InfoWindow{title: $title, snippet: $snippet, anchor: $anchor, consumesTapEvents: ${onTap != null}}'; + } + + dynamic _toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('title', title); + addIfPresent('snippet', snippet); + addIfPresent('anchor', _offsetToJson(anchor)); + addIfPresent('consumesTapEvents', onTap != null); + + return json; } - return annotations - .map>((Annotation m) => m._toJson()) - .toList(); } diff --git a/lib/src/annotation_updates.dart b/lib/src/annotation_updates.dart index 55b62e73..6f3eec9e 100644 --- a/lib/src/annotation_updates.dart +++ b/lib/src/annotation_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _AnnotationUpdates { + late Set annotationsToAdd; + + late Set annotationIdsToRemove; + late Set annotationsToChange; + /// Computes [_AnnotationUpdates] given previous and current [Annotation]s. _AnnotationUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -50,9 +55,26 @@ class _AnnotationUpdates { annotationsToChange = _annotationsToChange; } - late Set annotationsToAdd; - late Set annotationIdsToRemove; - late Set annotationsToChange; + @override + int get hashCode => + Object.hash(annotationsToAdd, annotationIdsToRemove, annotationsToChange); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! _AnnotationUpdates) return false; + final _AnnotationUpdates typedOther = other; + return setEquals(annotationsToAdd, typedOther.annotationsToAdd) && + setEquals(annotationIdsToRemove, typedOther.annotationIdsToRemove) && + setEquals(annotationsToChange, typedOther.annotationsToChange); + } + + @override + String toString() { + return '_AnnotationUpdates{annotationsToAdd: $annotationsToAdd, ' + 'annotationIdsToRemove: $annotationIdsToRemove, ' + 'annotationsToChange: $annotationsToChange}'; + } Map _toMap() { final Map updateMap = {}; @@ -74,25 +96,4 @@ class _AnnotationUpdates { return updateMap; } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! _AnnotationUpdates) return false; - final _AnnotationUpdates typedOther = other; - return setEquals(annotationsToAdd, typedOther.annotationsToAdd) && - setEquals(annotationIdsToRemove, typedOther.annotationIdsToRemove) && - setEquals(annotationsToChange, typedOther.annotationsToChange); - } - - @override - int get hashCode => - Object.hash(annotationsToAdd, annotationIdsToRemove, annotationsToChange); - - @override - String toString() { - return '_AnnotationUpdates{annotationsToAdd: $annotationsToAdd, ' - 'annotationIdsToRemove: $annotationIdsToRemove, ' - 'annotationsToChange: $annotationsToChange}'; - } } diff --git a/lib/src/apple_map.dart b/lib/src/apple_map.dart index 793a269e..4d6a1a9f 100644 --- a/lib/src/apple_map.dart +++ b/lib/src/apple_map.dart @@ -235,12 +235,14 @@ class _AppleMapState extends State { return; } final AppleMapController controller = await _controller.future; + if (!mounted) return; controller._updateMapOptions(updates); _appleMapOptions = newOptions; } void _updateAnnotations() async { final AppleMapController controller = await _controller.future; + if (!mounted) return; controller._updateAnnotations(_AnnotationUpdates.from( _annotations.values.toSet(), widget.annotations)); _annotations = _keyByAnnotationId(widget.annotations); @@ -248,6 +250,7 @@ class _AppleMapState extends State { void _updatePolylines() async { final AppleMapController controller = await _controller.future; + if (!mounted) return; controller._updatePolylines( _PolylineUpdates.from(_polylines.values.toSet(), widget.polylines)); _polylines = _keyByPolylineId(widget.polylines); @@ -255,6 +258,7 @@ class _AppleMapState extends State { void _updatePolygons() async { final AppleMapController controller = await _controller.future; + if (!mounted) return; // ignore: unawaited_futures controller._updatePolygons( _PolygonUpdates.from(_polygons.values.toSet(), widget.polygons)); @@ -263,6 +267,7 @@ class _AppleMapState extends State { void _updateCircles() async { final AppleMapController controller = await _controller.future; + if (!mounted) return; // ignore: unawaited_futures controller._updateCircles( _CircleUpdates.from(_circles.values.toSet(), widget.circles)); @@ -275,6 +280,7 @@ class _AppleMapState extends State { widget.initialCameraPosition, this, ); + if (!mounted) return; _controller.complete(controller); widget.onMapCreated?.call(controller); } diff --git a/lib/src/camera.dart b/lib/src/camera.dart index fb842af1..8dd827ed 100644 --- a/lib/src/camera.dart +++ b/lib/src/camera.dart @@ -8,13 +8,6 @@ part of apple_maps_flutter; /// shown in the map view. Aggregates the camera's [target] geographical /// location, its [zoom] level, [pitch] angle, and [heading]. class CameraPosition { - const CameraPosition({ - required this.target, - this.heading = 0.0, - this.pitch = 0.0, - this.zoom = 0, - }); - /// The camera's bearing in degrees, measured clockwise from north. /// /// A bearing of 0.0, the default, means the camera points north. @@ -41,6 +34,31 @@ class CameraPosition { /// will be silently clamped to the supported range. final double zoom; + const CameraPosition({ + required this.target, + this.heading = 0.0, + this.pitch = 0.0, + this.zoom = 0, + }); + + @override + int get hashCode => Object.hash(heading, target, pitch, zoom); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) return true; + if (runtimeType != other.runtimeType) return false; + final CameraPosition typedOther = other; + return heading == typedOther.heading && + target == typedOther.target && + pitch == typedOther.pitch && + zoom == typedOther.zoom; + } + + @override + String toString() => + 'CameraPosition(bearing: $heading, target: $target, tilt: $pitch, zoom: $zoom)'; + dynamic _toMap() => { 'target': target._toJson(), 'heading': heading, @@ -60,31 +78,17 @@ class CameraPosition { zoom: json['zoom'], ); } - - @override - bool operator ==(dynamic other) { - if (identical(this, other)) return true; - if (runtimeType != other.runtimeType) return false; - final CameraPosition typedOther = other; - return heading == typedOther.heading && - target == typedOther.target && - pitch == typedOther.pitch && - zoom == typedOther.zoom; - } - - @override - int get hashCode => Object.hash(heading, target, pitch, zoom); - - @override - String toString() => - 'CameraPosition(bearing: $heading, target: $target, tilt: $pitch, zoom: $zoom)'; } /// Defines a camera move, supporting absolute moves as well as moves relative /// the current position. class CameraUpdate { + final dynamic _json; + CameraUpdate._(this._json); + dynamic _toJson() => _json; + /// Returns a camera update that moves the camera to the specified position. static CameraUpdate newCameraPosition(CameraPosition cameraPosition) { return CameraUpdate._( @@ -98,14 +102,6 @@ class CameraUpdate { return CameraUpdate._(['newLatLng', latLng._toJson()]); } - /// Returns a camera update that moves the camera target to the specified - /// geographical location and zoom level. - static CameraUpdate newLatLngZoom(LatLng latLng, double zoom) { - return CameraUpdate._( - ['newLatLngZoom', latLng._toJson(), zoom], - ); - } - /// Returns a camera update that transforms the camera so that the specified /// geographical bounding box is centered in the map view at the greatest /// possible zoom level. A non-zero [padding] insets the bounding box from the @@ -118,6 +114,14 @@ class CameraUpdate { ]); } + /// Returns a camera update that moves the camera target to the specified + /// geographical location and zoom level. + static CameraUpdate newLatLngZoom(LatLng latLng, double zoom) { + return CameraUpdate._( + ['newLatLngZoom', latLng._toJson(), zoom], + ); + } + /// Returns a camera update that modifies the camera zoom level by the /// specified amount. The optional [focus] is a screen point whose underlying /// geographical location should be invariant, if possible, by the movement. @@ -153,8 +157,4 @@ class CameraUpdate { static CameraUpdate zoomTo(double zoom) { return CameraUpdate._(['zoomTo', zoom]); } - - final dynamic _json; - - dynamic _toJson() => _json; } diff --git a/lib/src/circle_updates.dart b/lib/src/circle_updates.dart index 2788e489..4e00a9cd 100644 --- a/lib/src/circle_updates.dart +++ b/lib/src/circle_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _CircleUpdates { + late Set circlesToAdd; + + late Set circleIdsToRemove; + late Set circlesToChange; + /// Computes [_CircleUpdates] given previous and current [Circle]s. _CircleUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -54,26 +59,9 @@ class _CircleUpdates { circlesToChange = _circlesToChange; } - late Set circlesToAdd; - late Set circleIdsToRemove; - late Set circlesToChange; - - Map _toMap() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('circlesToAdd', _serializeCircleSet(circlesToAdd)); - addIfNonNull('circlesToChange', _serializeCircleSet(circlesToChange)); - addIfNonNull('circleIdsToRemove', - circleIdsToRemove.map((CircleId m) => m.value).toList()); - - return updateMap; - } + @override + int get hashCode => + Object.hash(circlesToAdd, circleIdsToRemove, circlesToChange); @override bool operator ==(Object other) { @@ -85,14 +73,27 @@ class _CircleUpdates { setEquals(circlesToChange, typedOther.circlesToChange); } - @override - int get hashCode => - Object.hash(circlesToAdd, circleIdsToRemove, circlesToChange); - @override String toString() { return '_CircleUpdates{circlesToAdd: $circlesToAdd, ' 'circleIdsToRemove: $circleIdsToRemove, ' 'circlesToChange: $circlesToChange}'; } + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('circlesToAdd', _serializeCircleSet(circlesToAdd)); + addIfNonNull('circlesToChange', _serializeCircleSet(circlesToChange)); + addIfNonNull('circleIdsToRemove', + circleIdsToRemove.map((CircleId m) => m.value).toList()); + + return updateMap; + } } diff --git a/lib/src/location.dart b/lib/src/location.dart index b004f5ca..2e25c0f0 100644 --- a/lib/src/location.dart +++ b/lib/src/location.dart @@ -6,6 +6,12 @@ part of apple_maps_flutter; /// A pair of latitude and longitude coordinates, stored as degrees. class LatLng { + /// The latitude in degrees between -90.0 and 90.0, both inclusive. + final double latitude; + + /// The longitude in degrees between -180.0 (inclusive) and 180.0 (exclusive). + final double longitude; + /// Creates a geographical location specified in degrees [latitude] and /// [longitude]. /// @@ -18,11 +24,16 @@ class LatLng { (latitude < -90.0 ? -90.0 : (90.0 < latitude ? 90.0 : latitude)), longitude = (longitude + 180.0) % 360.0 - 180.0; - /// The latitude in degrees between -90.0 and 90.0, both inclusive. - final double latitude; + @override + int get hashCode => Object.hash(latitude, longitude); - /// The longitude in degrees between -180.0 (inclusive) and 180.0 (exclusive). - final double longitude; + @override + bool operator ==(Object o) { + return o is LatLng && o.latitude == latitude && o.longitude == longitude; + } + + @override + String toString() => '$runtimeType($latitude, $longitude)'; dynamic _toJson() { return [latitude, longitude]; @@ -34,17 +45,6 @@ class LatLng { } return LatLng(json[0], json[1]); } - - @override - String toString() => '$runtimeType($latitude, $longitude)'; - - @override - bool operator ==(Object o) { - return o is LatLng && o.latitude == latitude && o.longitude == longitude; - } - - @override - int get hashCode => Object.hash(latitude, longitude); } /// A latitude/longitude aligned rectangle. @@ -56,6 +56,12 @@ class LatLng { /// * lng ∈ [-180, `northeast.longitude`] ∪ [`southwest.longitude`, 180[, /// if `northeast.longitude` < `southwest.longitude` class LatLngBounds { + /// The southwest corner of the rectangle. + final LatLng southwest; + + /// The northeast corner of the rectangle. + final LatLng northeast; + /// Creates geographical bounding box with the specified corners. /// /// The latitude of the southwest corner cannot be larger than the @@ -63,11 +69,15 @@ class LatLngBounds { LatLngBounds({required this.southwest, required this.northeast}) : assert(southwest.latitude <= northeast.latitude); - /// The southwest corner of the rectangle. - final LatLng southwest; + @override + int get hashCode => Object.hash(southwest, northeast); - /// The northeast corner of the rectangle. - final LatLng northeast; + @override + bool operator ==(Object o) { + return o is LatLngBounds && + o.southwest == southwest && + o.northeast == northeast; + } /// Returns whether this rectangle contains the given [LatLng]. bool contains(LatLng point) { @@ -75,6 +85,11 @@ class LatLngBounds { _containsLongitude(point.longitude); } + @override + String toString() { + return '$runtimeType($southwest, $northeast)'; + } + bool _containsLatitude(double lat) { return (southwest.latitude <= lat) && (lat <= northeast.latitude); } @@ -87,6 +102,11 @@ class LatLngBounds { } } + /// Converts this object to something serializable in JSON. + dynamic _toJson() { + return [southwest._toJson(), northeast._toJson()]; + } + @visibleForTesting static LatLngBounds? fromList(dynamic json) { if (json == null) { @@ -97,24 +117,4 @@ class LatLngBounds { northeast: LatLng._fromJson(json[1])!, ); } - - @override - String toString() { - return '$runtimeType($southwest, $northeast)'; - } - - @override - bool operator ==(Object o) { - return o is LatLngBounds && - o.southwest == southwest && - o.northeast == northeast; - } - - /// Converts this object to something serializable in JSON. - dynamic _toJson() { - return [southwest._toJson(), northeast._toJson()]; - } - - @override - int get hashCode => Object.hash(southwest, northeast); } diff --git a/lib/src/polygon_updates.dart b/lib/src/polygon_updates.dart index 9f81494a..3c4b9856 100644 --- a/lib/src/polygon_updates.dart +++ b/lib/src/polygon_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _PolygonUpdates { + late Set polygonsToAdd; + + late Set polygonIdsToRemove; + late Set polygonsToChange; + /// Computes [_PolygonUpdates] given previous and current [Polygon]s. _PolygonUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -54,26 +59,9 @@ class _PolygonUpdates { polygonsToChange = _polygonsToChange; } - late Set polygonsToAdd; - late Set polygonIdsToRemove; - late Set polygonsToChange; - - Map _toMap() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('polygonsToAdd', _serializePolygonSet(polygonsToAdd)); - addIfNonNull('polygonsToChange', _serializePolygonSet(polygonsToChange)); - addIfNonNull('polygonIdsToRemove', - polygonIdsToRemove.map((PolygonId m) => m.value).toList()); - - return updateMap; - } + @override + int get hashCode => + Object.hash(polygonsToAdd, polygonIdsToRemove, polygonsToChange); @override bool operator ==(Object other) { @@ -85,14 +73,27 @@ class _PolygonUpdates { setEquals(polygonsToChange, typedOther.polygonsToChange); } - @override - int get hashCode => - Object.hash(polygonsToAdd, polygonIdsToRemove, polygonsToChange); - @override String toString() { return '_PolygonUpdates{polygonsToAdd: $polygonsToAdd, ' 'polygonIdsToRemove: $polygonIdsToRemove, ' 'polygonsToChange: $polygonsToChange}'; } + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('polygonsToAdd', _serializePolygonSet(polygonsToAdd)); + addIfNonNull('polygonsToChange', _serializePolygonSet(polygonsToChange)); + addIfNonNull('polygonIdsToRemove', + polygonIdsToRemove.map((PolygonId m) => m.value).toList()); + + return updateMap; + } } diff --git a/lib/src/polyline_updates.dart b/lib/src/polyline_updates.dart index 89cc2cbc..baf813a2 100644 --- a/lib/src/polyline_updates.dart +++ b/lib/src/polyline_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _PolylineUpdates { + late Set polylinesToAdd; + + late Set polylineIdsToRemove; + late Set polylinesToChange; + /// Computes [_PolylineUpdates] given previous and current [Polyline]s. _PolylineUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -48,26 +53,9 @@ class _PolylineUpdates { polylinesToChange = _polylinesToChange; } - late Set polylinesToAdd; - late Set polylineIdsToRemove; - late Set polylinesToChange; - - Map _toMap() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('polylinesToAdd', _serializePolylineSet(polylinesToAdd)); - addIfNonNull('polylinesToChange', _serializePolylineSet(polylinesToChange)); - addIfNonNull('polylineIdsToRemove', - polylineIdsToRemove.map((PolylineId m) => m.value).toList()); - - return updateMap; - } + @override + int get hashCode => + Object.hash(polylinesToAdd, polylineIdsToRemove, polylinesToChange); @override bool operator ==(Object other) { @@ -79,14 +67,27 @@ class _PolylineUpdates { setEquals(polylinesToChange, typedOther.polylinesToChange); } - @override - int get hashCode => - Object.hash(polylinesToAdd, polylineIdsToRemove, polylinesToChange); - @override String toString() { return '_PolylineUpdates{polylinesToAdd: $polylinesToAdd, ' 'polylineIdsToRemove: $polylineIdsToRemove, ' 'polylinesToChange: $polylinesToChange}'; } + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('polylinesToAdd', _serializePolylineSet(polylinesToAdd)); + addIfNonNull('polylinesToChange', _serializePolylineSet(polylinesToChange)); + addIfNonNull('polylineIdsToRemove', + polylineIdsToRemove.map((PolylineId m) => m.value).toList()); + + return updateMap; + } } diff --git a/lib/src/snapshot_options.dart b/lib/src/snapshot_options.dart index dbfa8547..b7a8eb43 100644 --- a/lib/src/snapshot_options.dart +++ b/lib/src/snapshot_options.dart @@ -1,6 +1,11 @@ part of apple_maps_flutter; class SnapshotOptions { + final bool showBuildings; + + final bool showPointsOfInterest; + final bool showAnnotations; + final bool showOverlays; const SnapshotOptions({ this.showBuildings = true, this.showPointsOfInterest = true, @@ -8,10 +13,23 @@ class SnapshotOptions { this.showOverlays = true, }); - final bool showBuildings; - final bool showPointsOfInterest; - final bool showAnnotations; - final bool showOverlays; + @override + int get hashCode => Object.hash(showBuildings, showPointsOfInterest); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) return true; + if (runtimeType != other.runtimeType) return false; + final SnapshotOptions typedOther = other; + return showBuildings == typedOther.showBuildings && + showPointsOfInterest == typedOther.showPointsOfInterest && + showAnnotations == typedOther.showAnnotations && + showOverlays == typedOther.showOverlays; + } + + @override + String toString() => + 'SnapshotOptions(showBuildings: $showBuildings, showPointsOfInterest: $showPointsOfInterest, showAnnotations: $showAnnotations, showOverlays: $showOverlays)'; dynamic _toMap() => { 'showBuildings': showBuildings, @@ -32,22 +50,4 @@ class SnapshotOptions { showOverlays: json['showOverlays'], ); } - - @override - bool operator ==(dynamic other) { - if (identical(this, other)) return true; - if (runtimeType != other.runtimeType) return false; - final SnapshotOptions typedOther = other; - return showBuildings == typedOther.showBuildings && - showPointsOfInterest == typedOther.showPointsOfInterest && - showAnnotations == typedOther.showAnnotations && - showOverlays == typedOther.showOverlays; - } - - @override - int get hashCode => Object.hash(showBuildings, showPointsOfInterest); - - @override - String toString() => - 'SnapshotOptions(showBuildings: $showBuildings, showPointsOfInterest: $showPointsOfInterest, showAnnotations: $showAnnotations, showOverlays: $showOverlays)'; } diff --git a/lib/src/ui.dart b/lib/src/ui.dart index 71c00a5f..1dc577ff 100644 --- a/lib/src/ui.dart +++ b/lib/src/ui.dart @@ -4,45 +4,25 @@ part of apple_maps_flutter; -/// Type of map tiles to display. -enum MapType { - /// Normal tiles (traffic and labels, subtle terrain information). - standard, - - /// Satellite imaging tiles (aerial photos) - satellite, - - /// Hybrid tiles (satellite images with some labels/overlays) - hybrid, -} - -enum TrackingMode { - // the user's location is not followed - none, - - // the map follows the user's location - follow, - - // the map follows the user's location and heading - followWithHeading, -} - /// Bounds for the map camera target. // Used with [AppleMapOptions] to wrap a [LatLngBounds] value. This allows // distinguishing between specifying an unbounded target (null `LatLngBounds`) // from not specifying anything (null `CameraTargetBounds`). class CameraTargetBounds { - /// Creates a camera target bounds with the specified bounding box, or null - /// to indicate that the camera target is not bounded. - const CameraTargetBounds(this.bounds); + /// Unbounded camera target. + static const CameraTargetBounds unbounded = CameraTargetBounds(null); /// The geographical bounding box for the map camera target. /// /// A null value means the camera target is unbounded. final LatLngBounds? bounds; - /// Unbounded camera target. - static const CameraTargetBounds unbounded = CameraTargetBounds(null); + /// Creates a camera target bounds with the specified bounding box, or null + /// to indicate that the camera target is not bounded. + const CameraTargetBounds(this.bounds); + + @override + int get hashCode => bounds.hashCode; @override bool operator ==(dynamic other) { @@ -52,18 +32,28 @@ class CameraTargetBounds { return bounds == typedOther.bounds; } - @override - int get hashCode => bounds.hashCode; - @override String toString() { return 'CameraTargetBounds(bounds: $bounds)'; } } +/// Type of map tiles to display. +enum MapType { + /// Normal tiles (traffic and labels, subtle terrain information). + standard, + + /// Satellite imaging tiles (aerial photos) + satellite, + + /// Hybrid tiles (satellite images with some labels/overlays) + hybrid, +} + class MinMaxZoomPreference { - const MinMaxZoomPreference(this.minZoom, this.maxZoom) - : assert(minZoom == null || maxZoom == null || minZoom <= maxZoom); + /// Unbounded zooming. + static const MinMaxZoomPreference unbounded = + MinMaxZoomPreference(null, null); /// The preferred minimum zoom level or null, if unbounded from below. final double? minZoom; @@ -71,11 +61,11 @@ class MinMaxZoomPreference { /// The preferred maximum zoom level or null, if unbounded from above. final double? maxZoom; - /// Unbounded zooming. - static const MinMaxZoomPreference unbounded = - MinMaxZoomPreference(null, null); + const MinMaxZoomPreference(this.minZoom, this.maxZoom) + : assert(minZoom == null || maxZoom == null || minZoom <= maxZoom); - dynamic _toJson() => [minZoom, maxZoom]; + @override + int get hashCode => Object.hash(minZoom, maxZoom); @override bool operator ==(dynamic other) { @@ -85,11 +75,21 @@ class MinMaxZoomPreference { return minZoom == typedOther.minZoom && maxZoom == typedOther.maxZoom; } - @override - int get hashCode => Object.hash(minZoom, maxZoom); - @override String toString() { return 'MinMaxZoomPreference(minZoom: $minZoom, maxZoom: $maxZoom)'; } + + dynamic _toJson() => [minZoom, maxZoom]; +} + +enum TrackingMode { + // the user's location is not followed + none, + + // the map follows the user's location + follow, + + // the map follows the user's location and heading + followWithHeading, } diff --git a/pubspec.yaml b/pubspec.yaml index 8fb876c6..27f2232b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,13 +1,13 @@ name: apple_maps_flutter description: This plugin uses the Flutter platform view to display an Apple Maps widget. -version: 1.4.0 +version: 1.5.0 homepage: https://luisthein.de repository: https://github.com/LuisThein/apple_maps_flutter issue_tracker: https://github.com/LuisThein/apple_maps_flutter/issues environment: - sdk: ">=2.14.0 <3.0.0" - flutter: ">=1.17.0" + sdk: ">=3.0.0 <4.0.0" + flutter: ">=3.44.0" dependencies: flutter: @@ -29,7 +29,7 @@ flutter: plugin: platforms: ios: - pluginClass: AppleMapsFlutterPlugin + pluginClass: SwiftAppleMapsFlutterPlugin # To add assets to your plugin package, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg