feat: integrate Google Maps Places Autocomplete for hub address validation
This commit is contained in:
3
apps/mobile/config.dev.json
Normal file
3
apps/mobile/config.dev.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"GOOGLE_PLACES_API_KEY": "AIzaSyAS9yTf4q51_CNSZ7mbmeS9V3l_LZR80lU"
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class HubsConstants {
|
||||||
|
static const String googlePlacesApiKey = String.fromEnvironment('GOOGLE_PLACES_API_KEY');
|
||||||
|
static const List<String> supportedCountries = <String>['us'];
|
||||||
|
}
|
||||||
@@ -11,11 +11,7 @@ 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:
|
||||||
path: ../../../core
|
path: ../../../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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user