feat: integrate Google Maps Places Autocomplete for hub address validation

This commit is contained in:
Achintha Isuru
2026-01-29 03:01:14 -05:00
parent 8f55e3f758
commit c212e8be00
7 changed files with 106 additions and 11 deletions

View File

@@ -0,0 +1,3 @@
{
"GOOGLE_PLACES_API_KEY": "AIzaSyAS9yTf4q51_CNSZ7mbmeS9V3l_LZR80lU"
}

View File

@@ -6,7 +6,7 @@
/// Locales: 2 /// Locales: 2
/// Strings: 1038 (519 per locale) /// Strings: 1038 (519 per locale)
/// ///
/// Built on 2026-01-29 at 04:15 UTC /// Built on 2026-01-29 at 06:58 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint, unused_import // ignore_for_file: type=lint, unused_import

View File

@@ -2,6 +2,8 @@ import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:core_localization/core_localization.dart'; import 'package:core_localization/core_localization.dart';
import 'hub_address_autocomplete.dart';
/// A dialog for adding a new hub. /// A dialog for adding a new hub.
class AddHubDialog extends StatefulWidget { class AddHubDialog extends StatefulWidget {
/// Callback when the "Create Hub" button is pressed. /// Callback when the "Create Hub" button is pressed.
@@ -74,12 +76,9 @@ class _AddHubDialogState extends State<AddHubDialog> {
), ),
const SizedBox(height: UiConstants.space4), const SizedBox(height: UiConstants.space4),
_buildFieldLabel(t.client_hubs.add_hub_dialog.address_label), _buildFieldLabel(t.client_hubs.add_hub_dialog.address_label),
TextField( HubAddressAutocomplete(
controller: _addressController, controller: _addressController,
style: UiTypography.body1r.textPrimary, hintText: t.client_hubs.add_hub_dialog.address_hint,
decoration: _buildInputDecoration(
t.client_hubs.add_hub_dialog.address_hint,
),
), ),
const SizedBox(height: UiConstants.space8), const SizedBox(height: UiConstants.space8),
Row( Row(

View File

@@ -0,0 +1,55 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:google_places_flutter/google_places_flutter.dart';
import 'package:google_places_flutter/model/prediction.dart';
import '../../util/hubs_constants.dart';
class HubAddressAutocomplete extends StatelessWidget {
const HubAddressAutocomplete({
required this.controller,
required this.hintText,
super.key,
});
final TextEditingController controller;
final String hintText;
@override
Widget build(BuildContext context) {
return GooglePlaceAutoCompleteTextField(
textEditingController: controller,
googleAPIKey: HubsConstants.googlePlacesApiKey,
debounceTime: 500,
countries: HubsConstants.supportedCountries,
isLatLngRequired: false,
getPlaceDetailWithLatLng: (Prediction prediction) {
// Handle lat/lng if needed in the future
},
itemClick: (Prediction prediction) {
controller.text = prediction.description ?? '';
controller.selection = TextSelection.fromPosition(
TextPosition(offset: controller.text.length),
);
},
itemBuilder: (_, _, Prediction prediction) {
return Padding(
padding: const EdgeInsets.all(UiConstants.space2),
child: Row(
spacing: UiConstants.space1,
children: <Widget>[
const Icon(UiIcons.mapPin, color: UiColors.iconSecondary),
Expanded(
child: Text(
prediction.description ?? "",
style: UiTypography.body1r.textSecondary,
),
),
],
),
);
},
textStyle: UiTypography.body1r.textPrimary,
);
}
}

View File

@@ -0,0 +1,4 @@
class HubsConstants {
static const String googlePlacesApiKey = String.fromEnvironment('GOOGLE_PLACES_API_KEY');
static const List<String> supportedCountries = <String>['us'];
}

View File

@@ -11,10 +11,6 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_bloc: ^8.1.0
flutter_modular: ^6.3.2
equatable: ^2.0.5
lucide_icons: ^0.257.0
# Architecture Packages # Architecture Packages
krow_core: krow_core:
@@ -27,8 +23,14 @@ dependencies:
path: ../../../design_system path: ../../../design_system
core_localization: core_localization:
path: ../../../core_localization path: ../../../core_localization
flutter_bloc: ^8.1.0
flutter_modular: ^6.3.2
equatable: ^2.0.5
lucide_icons: ^0.257.0
firebase_auth: ^6.1.4 firebase_auth: ^6.1.4
firebase_data_connect: ^0.2.2+2 firebase_data_connect: ^0.2.2+2
google_places_flutter: ^2.1.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@@ -295,6 +295,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.1" version: "0.4.1"
dio:
dependency: transitive
description:
name: dio
sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25
url: "https://pub.dev"
source: hosted
version: "5.9.1"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
equatable: equatable:
dependency: transitive dependency: transitive
description: description:
@@ -515,6 +531,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.3+1" version: "0.3.3+1"
google_places_flutter:
dependency: transitive
description:
name: google_places_flutter
sha256: "37bd64221cf4a5aa97eb3a33dc2d40f6326aa5ae4e2f2a9a7116bdc1a14f5194"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
googleapis_auth: googleapis_auth:
dependency: transitive dependency: transitive
description: description:
@@ -939,6 +963,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
rxdart:
dependency: transitive
description:
name: rxdart
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.dev"
source: hosted
version: "0.28.0"
shared_preferences: shared_preferences:
dependency: transitive dependency: transitive
description: description: