|
|
|
|
@ -37,6 +37,8 @@ class _PickLocationPageState extends State<PickLocationPage> {
|
|
|
|
|
late LatLng currentPosition;
|
|
|
|
|
Completer<GoogleMapController> mapController = Completer();
|
|
|
|
|
final ValueNotifier<String> _counter = ValueNotifier<String>("");
|
|
|
|
|
final ValueNotifier<bool> _isLoadingAddress = ValueNotifier<bool>(false);
|
|
|
|
|
String actualAddress = ""; // Store the actual address to return
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
@ -74,7 +76,7 @@ class _PickLocationPageState extends State<PickLocationPage> {
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Stack(
|
|
|
|
|
children: [
|
|
|
|
|
if (appMap != null) appMap,
|
|
|
|
|
appMap,
|
|
|
|
|
ValueListenableBuilder<String>(
|
|
|
|
|
builder: (BuildContext context, String value, Widget? child) {
|
|
|
|
|
// This builder will only get called when the _counter
|
|
|
|
|
@ -86,13 +88,42 @@ class _PickLocationPageState extends State<PickLocationPage> {
|
|
|
|
|
child: Card(
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.all(12.0),
|
|
|
|
|
child: Text(value ?? ""),
|
|
|
|
|
child: Text(value),
|
|
|
|
|
)),
|
|
|
|
|
)
|
|
|
|
|
: Container();
|
|
|
|
|
},
|
|
|
|
|
valueListenable: _counter,
|
|
|
|
|
),
|
|
|
|
|
ValueListenableBuilder<bool>(
|
|
|
|
|
builder: (BuildContext context, bool isLoading, Widget? child) {
|
|
|
|
|
return isLoading
|
|
|
|
|
? Container(
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
margin: const EdgeInsets.only(top: 70),
|
|
|
|
|
alignment: Alignment.topCenter,
|
|
|
|
|
child: const Card(
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: EdgeInsets.all(12.0),
|
|
|
|
|
child: Row(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: 20,
|
|
|
|
|
height: 20,
|
|
|
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
|
|
|
),
|
|
|
|
|
SizedBox(width: 12),
|
|
|
|
|
Text('Loading address...'),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
: const SizedBox.shrink();
|
|
|
|
|
},
|
|
|
|
|
valueListenable: _isLoadingAddress,
|
|
|
|
|
),
|
|
|
|
|
const Align(
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
child: Icon(
|
|
|
|
|
@ -108,12 +139,20 @@ class _PickLocationPageState extends State<PickLocationPage> {
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.all(12.0),
|
|
|
|
|
child: ShowFillButton(
|
|
|
|
|
maxHeight: 55,
|
|
|
|
|
title: LocaleKeys.pickAddress.tr(),
|
|
|
|
|
onPressed: () {
|
|
|
|
|
widget.onPickAddress(latitude, longitude, _counter.value);
|
|
|
|
|
pop(context);
|
|
|
|
|
child: ValueListenableBuilder<bool>(
|
|
|
|
|
valueListenable: _isLoadingAddress,
|
|
|
|
|
builder: (context, isLoading, child) {
|
|
|
|
|
return ShowFillButton(
|
|
|
|
|
maxHeight: 55,
|
|
|
|
|
title: isLoading ? 'Loading Address...' : LocaleKeys.pickAddress.tr(),
|
|
|
|
|
isDisabled: isLoading || _counter.value.isEmpty,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
if (!isLoading && _counter.value.isNotEmpty) {
|
|
|
|
|
widget.onPickAddress(latitude, longitude, actualAddress);
|
|
|
|
|
pop(context);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
@ -157,8 +196,33 @@ class _PickLocationPageState extends State<PickLocationPage> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateAddress(double latitude, double longitude) async {
|
|
|
|
|
List<Placemark> placemarks = await placemarkFromCoordinates(latitude, longitude);
|
|
|
|
|
_counter.value = '${placemarks.first.street}, ${placemarks.first.subLocality}, ${placemarks.first.locality}, ${placemarks.first.postalCode}, ${placemarks.first.country}';
|
|
|
|
|
_isLoadingAddress.value = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
List<Placemark> placemarks = await placemarkFromCoordinates(latitude, longitude).timeout(
|
|
|
|
|
const Duration(seconds: 5),
|
|
|
|
|
onTimeout: () {
|
|
|
|
|
throw TimeoutException('Geocoding request timed out');
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (placemarks.isNotEmpty) {
|
|
|
|
|
final placemark = placemarks.first;
|
|
|
|
|
// Restore original format - building address string from individual fields
|
|
|
|
|
actualAddress = '${placemark.street}, ${placemark.subLocality}, ${placemark.locality}, ${placemark.postalCode}, ${placemark.country}';
|
|
|
|
|
_counter.value = actualAddress;
|
|
|
|
|
} else {
|
|
|
|
|
actualAddress = "";
|
|
|
|
|
_counter.value = "";
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log('Error getting address: $e');
|
|
|
|
|
// On error, leave address empty - user can try again by moving the map
|
|
|
|
|
actualAddress = "";
|
|
|
|
|
_counter.value = "";
|
|
|
|
|
} finally {
|
|
|
|
|
_isLoadingAddress.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setMap() {
|
|
|
|
|
|