Line data Source code
1 : import 'package:meta/meta.dart';
2 :
3 : /// Contains detailed location information.
4 : @immutable
5 : class Position {
6 : /// Constructs an instance with the given values for testing. [Position]
7 : /// instances constructed this way won't actually reflect any real information
8 : /// from the platform, just whatever was passed in at construction time.
9 2 : Position({
10 : required this.longitude,
11 : required this.latitude,
12 : required this.timestamp,
13 : required this.accuracy,
14 : required this.altitude,
15 : required this.heading,
16 : required this.speed,
17 : required this.speedAccuracy,
18 : this.floor,
19 : this.isMocked = false,
20 : });
21 :
22 : /// The latitude of this position in degrees normalized to the interval -90.0
23 : /// to +90.0 (both inclusive).
24 : final double latitude;
25 :
26 : /// The longitude of the position in degrees normalized to the interval -180
27 : /// (exclusive) to +180 (inclusive).
28 : final double longitude;
29 :
30 : /// The time at which this position was determined.
31 : final DateTime? timestamp;
32 :
33 : /// The altitude of the device in meters.
34 : ///
35 : /// The altitude is not available on all devices. In these cases the returned
36 : /// value is 0.0.
37 : final double altitude;
38 :
39 : /// The estimated horizontal accuracy of the position in meters.
40 : ///
41 : /// The accuracy is not available on all devices. In these cases the value is
42 : /// 0.0.
43 : final double accuracy;
44 :
45 : /// The heading in which the device is traveling in degrees.
46 : ///
47 : /// The heading is not available on all devices. In these cases the value is
48 : /// 0.0.
49 : final double heading;
50 :
51 : /// The floor specifies the floor of the building on which the device is
52 : /// located.
53 : ///
54 : /// The floor property is only available on iOS and only when the information
55 : /// is available. In all other cases this value will be null.
56 : final int? floor;
57 :
58 : /// The speed at which the devices is traveling in meters per second over
59 : /// ground.
60 : ///
61 : /// The speed is not available on all devices. In these cases the value is
62 : /// 0.0.
63 : final double speed;
64 :
65 : /// The estimated speed accuracy of this position, in meters per second.
66 : ///
67 : /// The speedAccuracy is not available on all devices. In these cases the
68 : /// value is 0.0.
69 : final double speedAccuracy;
70 :
71 : /// Will be true on Android (starting from API lvl 18) when the location came
72 : /// from the mocked provider.
73 : ///
74 : /// On iOS this value will always be false.
75 : final bool isMocked;
76 :
77 1 : @override
78 : bool operator ==(Object o) {
79 1 : var areEqual = o is Position &&
80 3 : o.accuracy == accuracy &&
81 3 : o.altitude == altitude &&
82 3 : o.heading == heading &&
83 3 : o.latitude == latitude &&
84 3 : o.longitude == longitude &&
85 3 : o.floor == o.floor &&
86 3 : o.speed == speed &&
87 3 : o.speedAccuracy == speedAccuracy &&
88 3 : o.timestamp == timestamp &&
89 3 : o.isMocked == isMocked;
90 :
91 : return areEqual;
92 : }
93 :
94 1 : @override
95 : int get hashCode =>
96 3 : accuracy.hashCode ^
97 3 : altitude.hashCode ^
98 3 : heading.hashCode ^
99 3 : latitude.hashCode ^
100 3 : longitude.hashCode ^
101 3 : floor.hashCode ^
102 3 : speed.hashCode ^
103 3 : speedAccuracy.hashCode ^
104 3 : timestamp.hashCode ^
105 2 : isMocked.hashCode;
106 :
107 1 : @override
108 : String toString() {
109 3 : return 'Latitude: $latitude, Longitude: $longitude';
110 : }
111 :
112 : /// Converts the supplied [Map] to an instance of the [Position] class.
113 2 : static Position fromMap(dynamic message) {
114 : final Map<dynamic, dynamic> positionMap = message;
115 :
116 2 : if (!positionMap.containsKey('latitude')) {
117 1 : throw ArgumentError.value(positionMap, 'positionMap',
118 : 'The supplied map doesn\'t contain the mandatory key `latitude`.');
119 : }
120 :
121 2 : if (!positionMap.containsKey('longitude')) {
122 1 : throw ArgumentError.value(positionMap, 'positionMap',
123 : 'The supplied map doesn\'t contain the mandatory key `longitude`.');
124 : }
125 :
126 1 : final timestamp = positionMap['timestamp'] != null
127 3 : ? DateTime.fromMillisecondsSinceEpoch(positionMap['timestamp'].toInt(),
128 : isUtc: true)
129 : : null;
130 :
131 1 : return Position(
132 1 : latitude: positionMap['latitude'],
133 1 : longitude: positionMap['longitude'],
134 : timestamp: timestamp,
135 1 : altitude: positionMap['altitude'] ?? 0.0,
136 1 : accuracy: positionMap['accuracy'] ?? 0.0,
137 1 : heading: positionMap['heading'] ?? 0.0,
138 1 : floor: positionMap['floor'],
139 1 : speed: positionMap['speed'] ?? 0.0,
140 1 : speedAccuracy: positionMap['speed_accuracy'] ?? 0.0,
141 1 : isMocked: positionMap['is_mocked'] ?? false,
142 : );
143 : }
144 :
145 : /// Converts the [Position] instance into a [Map] instance that can be
146 : /// serialized to JSON.
147 2 : Map<String, dynamic> toJson() => {
148 1 : 'longitude': longitude,
149 1 : 'latitude': latitude,
150 2 : 'timestamp': timestamp?.millisecondsSinceEpoch,
151 1 : 'accuracy': accuracy,
152 1 : 'altitude': altitude,
153 1 : 'floor': floor,
154 1 : 'heading': heading,
155 1 : 'speed': speed,
156 1 : 'speed_accuracy': speedAccuracy,
157 1 : 'is_mocked': isMocked,
158 : };
159 : }
|