108 lines
3.3 KiB
Dart
108 lines
3.3 KiB
Dart
import 'package:aves/model/entry/entry.dart';
|
|
import 'package:aves/model/entry/extensions/location.dart';
|
|
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
|
import 'package:aves/model/settings/settings.dart';
|
|
import 'package:aves/services/common/services.dart';
|
|
import 'package:aves/services/geocoding_service.dart';
|
|
import 'package:aves/theme/icons.dart';
|
|
import 'package:aves/theme/text.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'info_row.dart';
|
|
|
|
class MapAddressRow extends StatefulWidget {
|
|
final AvesEntry? entry;
|
|
|
|
const MapAddressRow({
|
|
super.key,
|
|
required this.entry,
|
|
});
|
|
|
|
@override
|
|
State<MapAddressRow> createState() => _MapAddressRowState();
|
|
}
|
|
|
|
class _MapAddressRowState extends State<MapAddressRow> {
|
|
final ValueNotifier<String?> _addressLineNotifier = ValueNotifier(null);
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_updateAddress();
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(covariant MapAddressRow oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
if (oldWidget.entry != widget.entry) {
|
|
_updateAddress();
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_addressLineNotifier.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final textScaler = MediaQuery.textScalerOf(context);
|
|
return Container(
|
|
alignment: AlignmentDirectional.centerStart,
|
|
// addresses can include non-latin scripts with inconsistent line height,
|
|
// which is especially an issue for relayout/painting of heavy Google map,
|
|
// so we give extra height to give breathing room to the text and stabilize layout
|
|
height: textScaler.scale(Theme.of(context).textTheme.bodyMedium!.fontSize!) * 2,
|
|
child: ValueListenableBuilder<String?>(
|
|
valueListenable: _addressLineNotifier,
|
|
builder: (context, addressLine, child) {
|
|
final entry = widget.entry;
|
|
final location = addressLine ??
|
|
(entry == null
|
|
? AText.valueNotAvailable
|
|
: entry.hasAddress
|
|
? entry.shortAddress
|
|
: settings.coordinateFormat.format(context, entry.latLng!));
|
|
return Text.rich(
|
|
TextSpan(
|
|
children: [
|
|
WidgetSpan(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: MapInfoRow.iconPadding),
|
|
child: Icon(AIcons.location, size: MapInfoRow.getIconSize(context)),
|
|
),
|
|
alignment: PlaceholderAlignment.middle,
|
|
),
|
|
TextSpan(text: location),
|
|
],
|
|
),
|
|
softWrap: false,
|
|
overflow: TextOverflow.fade,
|
|
maxLines: 1,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _updateAddress() async {
|
|
final entry = widget.entry;
|
|
final addressLine = await _getAddressLine(entry);
|
|
if (!mounted) return;
|
|
if (entry == widget.entry) {
|
|
_addressLineNotifier.value = addressLine;
|
|
}
|
|
}
|
|
|
|
Future<String?> _getAddressLine(AvesEntry? entry) async {
|
|
if (entry != null && await availability.canLocatePlaces) {
|
|
final addresses = await GeocodingService.getAddress(entry.latLng!, settings.appliedLocale);
|
|
if (addresses.isNotEmpty) {
|
|
final address = addresses.first;
|
|
return address.addressLine;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|