Repository: Baseflow/flutter-geolocator

Issue:
[Bug]: NoSuchMethodError (NoSuchMethodError: The method 'toInt' was called on null. Receiver: null Tried calling: toInt())
### Please check the following before submitting a new issue.

- [X] I have searched the [existing issues](https://github.com/baseflow/flutter-geolocator/issues).
- [X] I have carefully [read the documentation](https://github.com/Baseflow/flutter-geolocator/blob/main/geolocator/README.md) and verified I have added the required platform specific configuration.

### Please select affected platform(s)

- [X] Android
- [x] iOS
- [ ] Linux
- [ ] macOS
- [ ] Web
- [ ] Windows

### Steps to reproduce

1. Open my apps
2. Go to the page that uses Postion.map function
3. Program Crash showing NoSuchMethodError

### Expected results

It should be load the page properly, without showing the debug error. When I used the plugins there was no issue, it occurs after some time of implementation

### Actual results
It should the error shown below, causing whole program the crash probably due to the variable being empty and converted toInt. Not sure why it worked before.

### Code sample

<details><summary>Code sample</summary>

When I use Position.fromMap function, it will crash on the library geolocator_platform_interface_4.2.0. I do not have this problem before, it happens recently when I try to open the apps. I have checked and allowed my gps location already. But this problem seems to be because the timestamp is null. I might be wrong, please help me.
```
    OutletList(
        imagePath: 'smtg here',
        titleTxt: 'smtg here',
        subTxt: 'smtg here',
        address:
            Position.fromMap({'latitude': 5.613820, 'longitude': 100.482940}),
        dist: 2.0,
),
```
The error occur on the position.dart on  geolocator_platform_interface_4.2.0. Refer code below for details.

Error Details:
`NoSuchMethodError (NoSuchMethodError: The method 'toInt' was called on null.
Receiver: null
Tried calling: toInt())`

Error Code Line: position.dart
`    final timestamp = DateTime.fromMillisecondsSinceEpoch(
        positionMap['timestamp'].toInt(),
        isUtc: true);`


</details>


### Screenshots or video

<details>
<summary>Screenshots or video demonstration</summary>

[![image](https://github.com/Baseflow/flutter-geolocator/assets/73678149/5a4ad64d-f5c0-429a-940e-0ba9ef90354b)](https://imgur.com/a/pqJWZWW)

</details>


### Version

10.1.0

### Flutter Doctor output

<details><summary>Doctor output</summary>

```console
[√] Flutter (Channel stable, 3.13.6, on Microsoft Windows [Version 10.0.19045.3693], locale en-US)
    • Flutter version 3.13.6 on channel stable at C:\dev\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ead455963c (10 weeks ago), 2023-09-26 18:28:17 -0700
    • Engine revision a794cf2681
    • Dart version 3.1.3
    • DevTools version 2.25.0

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at C:\Users\swchuah96118\AppData\Local\Android\Sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = C:\Users\swchuah96118\AppData\Local\Android\Sdk
    • Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[X] Visual Studio - develop Windows apps
    X Visual Studio not installed; this is necessary to develop Windows apps.
      Download at https://visualstudio.microsoft.com/downloads/.
      Please install the "Desktop development with C++" workload, including all of its default components

[√] Android Studio (version 2022.3)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231)

[√] VS Code (version 1.84.2)
    • VS Code at C:\Users\swchuah96118\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.78.0

[√] Connected device (4 available)
    • REA NX9 (mobile)  • AF2SVB3905001108 • android-arm64  • Android 13 (API 33)
    • Windows (desktop) • windows          • windows-x64    • Microsoft Windows [Version 10.0.19045.3693]
    • Chrome (web)      • chrome           • web-javascript • Google Chrome 119.0.6045.200
    • Edge (web)        • edge             • web-javascript • Microsoft Edge 119.0.2151.97

[√] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.
```

</details>



Discussion: **NOTE: as a temporary solution, I completely remove the timestamp variables from the library and it seems to work fine.**
> **NOTE: as a temporary solution, I completely remove the timestamp variables from the library and it seems to work fine.**

This would be a heavy breaking change.

Another option would be to adapt the `timestamp` of `Position` to be nullable and adapt the code within `fromMap` to accept that the 'timestamp' might be null (or non-existent).
However, this also might be a breaking change.

Ideally, what could happen is for the `fromMap` method to check if the `timestamp` exists, and if it does not exist, assume that the timestamp is "now".

Meanwhile, you can update your code to create a fake timestamp:
```dart
Position.fromMap({
  'latitude': yourLatitude,
  'longitude': yourLongitude,
  'timestamp': DateTime.now().millisecondsSinceEpoch,
});
```

Fix patch:
diff --git a/geolocator_platform_interface/lib/src/models/position.dart b/geolocator_platform_interface/lib/src/models/position.dart
index d6a491416..543586c1c 100644
--- a/geolocator_platform_interface/lib/src/models/position.dart
+++ b/geolocator_platform_interface/lib/src/models/position.dart
@@ -141,9 +141,14 @@ class Position {
           'The supplied map doesn\'t contain the mandatory key `longitude`.');
     }
 
-    final timestamp = DateTime.fromMillisecondsSinceEpoch(
-        positionMap['timestamp'].toInt(),
-        isUtc: true);
+    // Assume that the timestamp is null if the map does not contain one
+    dynamic timestampInMap = positionMap['timestamp'];
+    final timestamp = timestampInMap == null
+        ? DateTime.now()
+        : DateTime.fromMillisecondsSinceEpoch(
+            timestampInMap.toInt(),
+            isUtc: true,
+          );
 
     return Position(
       latitude: positionMap['latitude'],
diff --git a/geolocator_platform_interface/pubspec.yaml b/geolocator_platform_interface/pubspec.yaml
index efb3104c4..73ac32c48 100644
--- a/geolocator_platform_interface/pubspec.yaml
+++ b/geolocator_platform_interface/pubspec.yaml
@@ -3,7 +3,7 @@ description: A common platform interface for the geolocator plugin.
 repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 4.2.0
+version: 4.2.1
 
 dependencies:
   flutter:


Test patch:
diff --git a/geolocator_platform_interface/test/geolocator_platform_interface_test.dart b/geolocator_platform_interface/test/geolocator_platform_interface_test.dart
index 64afcd11a..587a87631 100644
--- a/geolocator_platform_interface/test/geolocator_platform_interface_test.dart
+++ b/geolocator_platform_interface/test/geolocator_platform_interface_test.dart
@@ -324,6 +324,15 @@ void main() {
 
       expect(bearing, -90.0);
     });
+
+    test('generate Position object from map without timestamp', () async {
+      final Position position = Position.fromMap({
+        'latitude': 0.0,
+        'longitude': 0.0,
+      });
+
+      expect(position, isNotNull);
+    });
   });
 }