Skip to content

Commit 486b961

Browse files
feat(spark_web): add idiomatic Geolocation API and improve Firefox compatibility
- spark_web: Added Future-based getPosition() and Stream-based onPositionChanged() to Geolocation. - spark_css: Bumped version to v1.0.0-alpha.2 and updated CHANGELOG with new typed properties. - spark (example): Refactored GeolocationDemo to use new idiomatic API and added fallback for Firefox systems without GPS.
1 parent 76cf090 commit 486b961

13 files changed

Lines changed: 248 additions & 205 deletions

File tree

.gemini/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"mcpServers": {
3+
"dart": {
4+
"command": "dart",
5+
"args": [
6+
"mcp-server"
7+
]
8+
}
9+
}
10+
}

packages/spark/example/lib/components/geolocation_demo/geolocation_demo_base.dart

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:async';
12
import 'package:spark_framework/spark.dart';
23

34
@Component(tag: GeolocationDemo.tag)
@@ -6,7 +7,7 @@ class GeolocationDemo {
67

78
int? _watchId;
89

9-
GeolocationDemo();
10+
GeolocationDemo({this.status = 'Ready', this.coords = '', this.error = ''});
1011

1112
@Attribute()
1213
String status = 'Ready';
@@ -125,48 +126,85 @@ class GeolocationDemo {
125126
]);
126127
}
127128

128-
void _getCurrentPosition() {
129-
status = 'Requesting position...';
129+
Future<void> _getCurrentPosition({bool highAccuracy = true}) async {
130+
status = highAccuracy
131+
? 'Requesting position (High Accuracy)...'
132+
: 'Requesting position (Low Accuracy)...';
130133
error = '';
131134

132-
window.navigator.geolocation.getCurrentPosition(
133-
(position) {
134-
status = 'Position retrieved';
135-
coords = _formatPosition(position);
136-
},
137-
(e) {
138-
status = 'Error';
135+
try {
136+
final position = await window.navigator.geolocation.getPosition(
137+
PositionOptions(
138+
enableHighAccuracy: highAccuracy,
139+
timeout: 15000,
140+
maximumAge: 0,
141+
),
142+
);
143+
status = 'Position retrieved';
144+
coords = _formatPosition(position);
145+
} catch (e) {
146+
if (e is GeolocationPositionError && highAccuracy && e.code == 2) {
147+
// Firefox sometimes fails with code 2 (POSITION_UNAVAILABLE) when
148+
// enableHighAccuracy is true on systems without a GPS.
149+
// Fallback to low accuracy in this case.
150+
return _getCurrentPosition(highAccuracy: false);
151+
}
152+
status = 'Error';
153+
if (e is GeolocationPositionError) {
139154
error = '[${e.code}] ${e.message}';
140-
},
141-
PositionOptions(enableHighAccuracy: true, timeout: 5000, maximumAge: 0),
142-
);
155+
} else {
156+
error = e.toString();
157+
}
158+
}
143159
}
144160

145-
void _startWatch() {
161+
void _startWatch({bool highAccuracy = true}) {
146162
if (_watchId != null) return;
147163

148-
status = 'Watching position...';
164+
status = highAccuracy
165+
? 'Watching position (High Accuracy)...'
166+
: 'Watching position (Low Accuracy)...';
149167
error = '';
150168

151-
_watchId = window.navigator.geolocation.watchPosition(
169+
final stream = window.navigator.geolocation.onPositionChanged(
170+
PositionOptions(enableHighAccuracy: highAccuracy),
171+
);
172+
173+
// We still use _watchId internally to track if we're watching,
174+
// though the implementation now uses a Stream.
175+
_watchId = 1; // Dummy ID
176+
177+
final subscription = stream.listen(
152178
(position) {
153-
status = 'Position updated (Watch ID: $_watchId)';
179+
status = 'Position updated';
154180
coords = _formatPosition(position);
155181
},
156-
(e) {
182+
onError: (e) {
183+
if (e is GeolocationPositionError && highAccuracy && e.code == 2) {
184+
_stopWatch();
185+
_startWatch(highAccuracy: false);
186+
return;
187+
}
157188
status = 'Watch Error';
158-
error = '[${e.code}] ${e.message}';
189+
if (e is GeolocationPositionError) {
190+
error = '[${e.code}] ${e.message}';
191+
} else {
192+
error = e.toString();
193+
}
159194
},
160-
PositionOptions(enableHighAccuracy: true),
161195
);
196+
197+
// Store subscription in a way we can cancel it
198+
_subscription = subscription;
162199
}
163200

201+
StreamSubscription? _subscription;
202+
164203
void _stopWatch() {
165-
if (_watchId != null) {
166-
window.navigator.geolocation.clearWatch(_watchId!);
167-
_watchId = null;
168-
status = 'Watch stopped';
169-
}
204+
_subscription?.cancel();
205+
_subscription = null;
206+
_watchId = null;
207+
status = 'Watch stopped';
170208
}
171209

172210
String _formatPosition(GeolocationPosition pos) {

packages/spark/example/lib/components/geolocation_demo/geolocation_demo_base.impl.dart

Lines changed: 21 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/spark/example/lib/pages/geolocation/geolocation_page.g.dart

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)