Skip to content

Commit f53e8f8

Browse files
committed
small refactor of coordinate state
1 parent d969b6b commit f53e8f8

2 files changed

Lines changed: 82 additions & 58 deletions

File tree

packages/app/lib/ui/screens/sighting.dart

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,15 @@ class _SightingProfileState extends State<SightingProfile> {
159159
setState(() {});
160160
}
161161

162-
void _updateLocation(
163-
{required double latitude, required double longitude}) async {
164-
if (sighting.latitude == latitude && sighting.longitude == longitude) {
162+
void _updateLocation(Coordinates coordinates) async {
163+
if (sighting.latitude == coordinates.latitude &&
164+
sighting.longitude == coordinates.longitude) {
165165
// Nothing has changed
166166
return;
167167
}
168168

169-
await sighting.update(latitude: latitude, longitude: longitude);
169+
await sighting.update(
170+
latitude: coordinates.latitude, longitude: coordinates.longitude);
170171

171172
setState(() {});
172173
}
@@ -198,8 +199,10 @@ class _SightingProfileState extends State<SightingProfile> {
198199
title: AppLocalizations.of(context)!.noteCardTitle,
199200
onUpdate: _updateComment),
200201
LocationField(
201-
latitude: sighting.latitude,
202-
longitude: sighting.longitude,
202+
// Not the best way to check if a position has not been set, but works for now
203+
coordinates: sighting.latitude == 0 && sighting.longitude == 0
204+
? null
205+
: (latitude: sighting.latitude, longitude: sighting.longitude),
203206
onUpdate: _updateLocation),
204207
]),
205208
);

packages/app/lib/ui/widgets/location_field.dart

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,28 @@ import 'package:flutter/material.dart';
99
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1010
import 'package:maplibre_gl/maplibre_gl.dart';
1111

12-
typedef OnUpdate = void Function(
13-
{required double latitude, required double longitude});
12+
typedef OnUpdate = void Function(Coordinates coordinates);
13+
typedef Coordinates = ({double latitude, double longitude});
1414

1515
class LocationField extends StatefulWidget {
16-
final double latitude;
17-
final double longitude;
16+
final Coordinates? coordinates;
1817

1918
final OnUpdate onUpdate;
2019

2120
const LocationField(
22-
{super.key,
23-
required this.longitude,
24-
required this.latitude,
25-
required this.onUpdate});
21+
{super.key, required this.coordinates, required this.onUpdate});
2622

2723
@override
2824
State<LocationField> createState() => _LocationFieldState();
2925
}
3026

31-
double DEFAULT_ZOOM = 8;
32-
String CURRENT_FEATURE_ID = 'current';
33-
String TARGET_FEATURE_ID = 'target';
27+
const Coordinates BRAZIL_CENTROID_COORDINATES =
28+
(latitude: -14.235004, longitude: -51.92528);
29+
const double DEFAULT_ZOOMED_OUT_LEVEL = 1.5;
30+
const double DEFAULT_ZOOMED_IN_LEVEL = 8;
3431

3532
class _LocationFieldState extends State<LocationField> {
36-
// The latitude value displayed for the marker at the center of the map
37-
late double _lat;
38-
// The longitude value displayed for the marker at the center of the map
39-
late double _lng;
33+
late Coordinates? _coordinates;
4034

4135
bool _isEditMode = false;
4236

@@ -47,8 +41,7 @@ class _LocationFieldState extends State<LocationField> {
4741

4842
@override
4943
void initState() {
50-
_lat = widget.latitude;
51-
_lng = widget.longitude;
44+
_coordinates = widget.coordinates;
5245
super.initState();
5346
}
5447

@@ -71,10 +64,12 @@ class _LocationFieldState extends State<LocationField> {
7164
const SizedBox(
7265
height: 20,
7366
),
74-
Text(t.sightingLocationLongitude(_lng),
75-
style: Theme.of(context).textTheme.bodyLarge),
76-
Text(t.sightingLocationLatitude(_lat),
77-
style: Theme.of(context).textTheme.bodyLarge),
67+
if (_coordinates != null) ...[
68+
Text(t.sightingLocationLongitude(_coordinates!.longitude),
69+
style: Theme.of(context).textTheme.bodyLarge),
70+
Text(t.sightingLocationLatitude(_coordinates!.latitude),
71+
style: Theme.of(context).textTheme.bodyLarge),
72+
],
7873
if (_isEditMode)
7974
Padding(
8075
padding: const EdgeInsets.only(top: 10.0),
@@ -85,13 +80,20 @@ class _LocationFieldState extends State<LocationField> {
8580
}
8681

8782
Widget _renderMap() {
83+
final initialCameraPosition = _coordinates == null
84+
? CameraPosition(
85+
zoom: DEFAULT_ZOOMED_OUT_LEVEL,
86+
target: LatLng(BRAZIL_CENTROID_COORDINATES.latitude,
87+
BRAZIL_CENTROID_COORDINATES.longitude))
88+
: CameraPosition(
89+
target: LatLng(_coordinates!.latitude, _coordinates!.longitude),
90+
zoom: DEFAULT_ZOOMED_IN_LEVEL);
91+
8892
return Container(
8993
alignment: Alignment.center,
9094
height: 200,
9195
child: MaplibreMap(
92-
initialCameraPosition: CameraPosition(
93-
target: LatLng(widget.latitude, widget.longitude),
94-
zoom: DEFAULT_ZOOM),
96+
initialCameraPosition: initialCameraPosition,
9597
scrollGesturesEnabled: _isEditMode,
9698
dragEnabled: _isEditMode,
9799
zoomGesturesEnabled: _isEditMode,
@@ -106,28 +108,33 @@ class _LocationFieldState extends State<LocationField> {
106108
() => EagerGestureRecognizer()),
107109
},
108110
onStyleLoadedCallback: () async {
109-
_existingMapMarker = await _mapController!.addCircle(
110-
createMapCircle(lat: widget.latitude, lng: widget.longitude));
111+
if (_coordinates != null) {
112+
_existingMapMarker = await _mapController!.addCircle(
113+
createMapCircle(
114+
latitude: _coordinates!.latitude,
115+
longitude: _coordinates!.longitude));
116+
}
111117
},
112118
onMapClick: (_, latLng) async {
113119
if (!_isEditMode) return;
114-
if (_existingMapMarker == null) return;
115120

116-
var nextMarker = _mapController!.circles.where((c) {
121+
final nextMarker = _mapController!.circles.where((c) {
117122
return c != _existingMapMarker;
118123
}).firstOrNull;
119124

120125
// Add the "next" marker and update the visuals of the existing marker
121126
if (nextMarker == null) {
122127
await _mapController!.addCircle(createMapCircle(
123-
lat: latLng.latitude, lng: latLng.longitude));
124-
125-
await _mapController!.updateCircle(
126-
_existingMapMarker!,
127-
const CircleOptions(
128-
circleOpacity: 0.5,
129-
circleStrokeOpacity: 0.5,
130-
));
128+
latitude: latLng.latitude, longitude: latLng.longitude));
129+
130+
if (_existingMapMarker != null) {
131+
await _mapController!.updateCircle(
132+
_existingMapMarker!,
133+
const CircleOptions(
134+
circleOpacity: 0.5,
135+
circleStrokeOpacity: 0.5,
136+
));
137+
}
131138
} else {
132139
await _mapController!
133140
.updateCircle(nextMarker, CircleOptions(geometry: latLng));
@@ -136,57 +143,71 @@ class _LocationFieldState extends State<LocationField> {
136143
_mapController!.animateCamera(CameraUpdate.newLatLng(latLng));
137144

138145
setState(() {
139-
_lng = latLng.longitude;
140-
_lat = latLng.latitude;
146+
_coordinates =
147+
(latitude: latLng.latitude, longitude: latLng.longitude);
141148
});
142149
}));
143150
}
144151

145152
void _handleSave() async {
146153
// Do nothing if coordinates have not changed at all
147-
if (_lat == widget.latitude && _lng == widget.longitude) {
154+
if (_coordinates == widget.coordinates) {
148155
_handleCancel();
149156
return;
150157
}
151158

152159
setState(() {
153160
_isEditMode = false;
154-
widget.onUpdate(latitude: _lat, longitude: _lng);
161+
if (_coordinates != null) {
162+
widget.onUpdate(_coordinates!);
163+
}
155164
});
156165

157-
_resetMap(LatLng(_lat, _lng));
166+
_resetMap(coordinates: _coordinates!, zoomLevel: DEFAULT_ZOOMED_IN_LEVEL);
158167
}
159168

160169
void _handleCancel() async {
161-
await _resetMap(LatLng(widget.latitude, widget.longitude));
170+
if (widget.coordinates == null || _coordinates == null) {
171+
await _resetMap(
172+
coordinates: BRAZIL_CENTROID_COORDINATES,
173+
zoomLevel: DEFAULT_ZOOMED_OUT_LEVEL);
174+
} else {
175+
await _resetMap(
176+
coordinates: widget.coordinates!, zoomLevel: DEFAULT_ZOOMED_IN_LEVEL);
177+
}
162178

163179
setState(() {
164180
_isEditMode = false;
165-
_lat = widget.latitude;
166-
_lng = widget.longitude;
181+
_coordinates = widget.coordinates;
167182
});
168183
}
169184

170-
Future<void> _resetMap(LatLng latLng) async {
171-
await _mapController!.updateCircle(
172-
_existingMapMarker!,
173-
CircleOptions(
174-
geometry: latLng, circleOpacity: 1.0, circleStrokeOpacity: 1.0));
185+
Future<void> _resetMap(
186+
{required Coordinates coordinates, required double zoomLevel}) async {
187+
final latLng = LatLng(coordinates.latitude, coordinates.longitude);
188+
189+
if (_existingMapMarker != null) {
190+
await _mapController!.updateCircle(
191+
_existingMapMarker!,
192+
CircleOptions(
193+
geometry: latLng, circleOpacity: 1.0, circleStrokeOpacity: 1.0));
194+
}
175195

176196
await _mapController!.removeCircles(_mapController!.circles.where((c) {
177197
return c != _existingMapMarker;
178198
}));
179199

180200
_mapController!
181-
.animateCamera(CameraUpdate.newLatLngZoom(latLng, DEFAULT_ZOOM));
201+
.animateCamera(CameraUpdate.newLatLngZoom(latLng, zoomLevel));
182202
}
183203
}
184204

185-
CircleOptions createMapCircle({required double lat, required double lng}) {
205+
CircleOptions createMapCircle(
206+
{required double latitude, required double longitude}) {
186207
return CircleOptions(
187208
circleRadius: 8,
188209
circleColor: MeliColors.magnolia.toHexStringRGB(),
189210
circleStrokeColor: MeliColors.black.toHexStringRGB(),
190211
circleStrokeWidth: 2.0,
191-
geometry: LatLng(lat, lng));
212+
geometry: LatLng(latitude, longitude));
192213
}

0 commit comments

Comments
 (0)