1import 'package:easy_localization/easy_localization.dart';
2import 'package:flutter/material.dart';
3import 'package:flutter_screenutil/flutter_screenutil.dart';
4import 'package:fluentui_system_icons/fluentui_system_icons.dart';
5import 'package:google_maps_flutter/google_maps_flutter.dart';
6import 'package:geocoding/geocoding.dart';
9import '../../../../../../core/ui/theme/color_palette.dart';
10import '../models/search_result.dart';
20 required this.controller,
21 required this.onLocationSelected,
22 this.isVisible =
true,
27 State<LocationSearchBar>
createState() => _LocationSearchBarState();
30class _LocationSearchBarState
extends State<LocationSearchBar> {
65 List<Location> locations = await locationFromAddress(query);
67 List<SearchResult> results = [];
70 for (
int i = 0; i < locations.length && i < 5; i++) {
75 List<Placemark> placemarks = await placemarkFromCoordinates(
80 if (placemarks.isNotEmpty) {
81 final placemark = placemarks.first;
87 if (placemark.name != null && placemark.name!.isNotEmpty) {
88 name = placemark.name!;
89 }
else if (placemark.thoroughfare != null && placemark.thoroughfare!.isNotEmpty) {
90 name = placemark.thoroughfare!;
103 address:
'${location.latitude.toStringAsFixed(4)}, ${location.longitude.toStringAsFixed(4)}',
128 List<String> addressParts = [];
130 if (placemark.thoroughfare != null && placemark.thoroughfare!.isNotEmpty) {
131 addressParts.add(placemark.thoroughfare!);
133 if (placemark.locality != null && placemark.locality!.isNotEmpty) {
134 addressParts.add(placemark.locality!);
136 if (placemark.administrativeArea != null && placemark.administrativeArea!.isNotEmpty) {
137 addressParts.add(placemark.administrativeArea!);
139 if (placemark.country != null && placemark.country!.isNotEmpty) {
140 addressParts.add(placemark.country!);
143 return addressParts.isNotEmpty ? addressParts.join(
', ') :
'Location';
147 widget.controller.text = result.
name;
148 widget.onLocationSelected(result.
latLng);
157 widget.controller.clear();
167 if (widget.onClose != null) {
173 Widget
build(BuildContext context) {
177 decoration: BoxDecoration(
179 borderRadius: BorderRadius.circular(12.r),
182 color: Colors.black.withValues(alpha: 0.1),
184 offset:
const Offset(0, 2),
192 controller: widget.controller,
196 decoration: InputDecoration(
197 hintText:
'scheduling.search_for_location'.tr(),
198 hintStyle: TextStyle(
199 color: Colors.grey[500],
203 FluentIcons.search_16_regular,
204 color: Colors.grey[500],
207 border: InputBorder.none,
208 contentPadding: EdgeInsets.symmetric(
215 color: Colors.black87,
221 FluentIcons.dismiss_16_filled,
222 color: Colors.grey[600],
232 margin: EdgeInsets.only(top: 8.h),
233 decoration: BoxDecoration(
235 borderRadius: BorderRadius.circular(12.r),
238 color: Colors.black.withValues(alpha: 0.1),
240 offset:
const Offset(0, 2),
259 child: CircularProgressIndicator(
266 'scheduling.searching'.tr(),
269 color: Colors.grey[600],
283 FluentIcons.error_circle_16_filled,
284 color: Colors.red[400],
290 'scheduling.no_locations_found'.tr(),
293 color: Colors.grey[600],
303 return ListView.separated(
305 physics:
const NeverScrollableScrollPhysics(),
307 separatorBuilder: (context, index) => Divider(
309 color: Colors.grey[200],
311 itemBuilder: (context, index) {
312 final result = _searchResults[index];
315 FluentIcons.location_16_filled,
316 color: ColorPalette.lightGreen,
323 fontWeight: FontWeight.w500,
324 color: Colors.black87,
331 color: Colors.grey[600],
334 onTap: () => _onResultSelected(result),
class App extends StatefulWidget build(BuildContext context)
List< SearchResult > _searchResults
class LocationSearchBar extends StatefulWidget _isSearching
Future< void > _performGeocodingSearch(String query) async
void _onSearchChanged(String query)
final FocusNode _focusNode
String _buildAddressString(Placemark placemark)
Widget _buildSearchContent()
void _onResultSelected(SearchResult result)
class UpdateLocationEvent extends LocationSelectionEvent location
style Text( '${ 'scheduling.reference'.tr()}:${collection.internalCode}', style:Theme.of(context).textTheme.bodySmall,)
style SizedBox(height:2.h)
style Column(crossAxisAlignment:CrossAxisAlignment.end, children:[Container(padding:EdgeInsets.symmetric(horizontal:8.w, vertical:4.h), decoration:BoxDecoration(color:ColorPalette.tiffanyBlue.withValues(alpha:0.1), borderRadius:BorderRadius.circular(12),), child:Text(collection.type ?? '', style:Theme.of(context).textTheme.bodySmall?.copyWith(color:ColorPalette.tiffanyBlue, fontWeight:FontWeight.bold,),),),],)