flutter_places_sdk 0.1.0 copy "flutter_places_sdk: ^0.1.0" to clipboard
flutter_places_sdk: ^0.1.0 copied to clipboard

Flutter plugin wrapping the native Google Places SDK (iOS & Android) with support for Places API (New). Works with API keys restricted by bundle ID / SHA-1 fingerprint.

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_places_sdk/flutter_places_sdk.dart';

void main() => runApp(const ExampleApp());

/// Fill in with a key that has **Places API (New)** enabled. The key may
/// be restricted by iOS bundle ID / Android package + SHA-1 — that's the
/// whole point of this plugin.
///
/// Run with:
/// ```
/// flutter run --dart-define=PLACES_API_KEY=AIza…
/// ```
const _apiKey = String.fromEnvironment('PLACES_API_KEY');

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'flutter_places_sdk example',
    theme: ThemeData(colorSchemeSeed: Colors.deepPurple, useMaterial3: true),
    home: const HomePage(),
  );
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _places = FlutterPlacesSdk(_apiKey);
  final _controller = TextEditingController();
  Timer? _debounce;
  List<AutocompletePrediction> _predictions = const [];
  Place? _selected;
  String? _error;

  @override
  void dispose() {
    _debounce?.cancel();
    _controller.dispose();
    super.dispose();
  }

  void _onChanged(String value) {
    _debounce?.cancel();
    _debounce = Timer(const Duration(milliseconds: 300), () async {
      if (value.trim().length < 3) {
        setState(() => _predictions = const []);
        return;
      }
      try {
        final predictions = await _places.findAutocompletePredictions(value);
        if (!mounted) return;
        setState(() {
          _predictions = predictions;
          _error = null;
        });
      } on PlacesException catch (e) {
        if (!mounted) return;
        setState(() => _error = '${e.code}: ${e.message}');
      }
    });
  }

  Future<void> _select(AutocompletePrediction prediction) async {
    try {
      final place = await _places.fetchPlace(
        prediction.placeId,
        fields: const [
          PlaceField.id,
          PlaceField.name,
          PlaceField.address,
          PlaceField.location,
        ],
      );
      if (!mounted) return;
      setState(() {
        _selected = place;
        _error = null;
      });
    } on PlacesException catch (e) {
      if (!mounted) return;
      setState(() => _error = '${e.code}: ${e.message}');
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(title: const Text('flutter_places_sdk')),
    body: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          TextField(
            controller: _controller,
            onChanged: _onChanged,
            decoration: const InputDecoration(
              labelText: 'Search places',
              border: OutlineInputBorder(),
            ),
          ),
          if (_apiKey.isEmpty)
            const Padding(
              padding: EdgeInsets.only(top: 8),
              child: Text(
                'Pass PLACES_API_KEY via --dart-define to enable requests.',
                style: TextStyle(color: Colors.orange),
              ),
            ),
          if (_error != null)
            Padding(
              padding: const EdgeInsets.only(top: 8),
              child: Text(_error!, style: const TextStyle(color: Colors.red)),
            ),
          const SizedBox(height: 12),
          Expanded(child: _PredictionsList(_predictions, _select)),
          if (_selected != null) _SelectedPlaceCard(_selected!),
        ],
      ),
    ),
  );
}

class _PredictionsList extends StatelessWidget {
  const _PredictionsList(this.predictions, this.onTap);

  final List<AutocompletePrediction> predictions;
  final void Function(AutocompletePrediction) onTap;

  @override
  Widget build(BuildContext context) => ListView.builder(
    itemCount: predictions.length,
    itemBuilder: (context, index) {
      final p = predictions[index];
      return ListTile(
        title: Text(p.primaryText),
        subtitle: Text(p.secondaryText),
        onTap: () => onTap(p),
      );
    },
  );
}

class _SelectedPlaceCard extends StatelessWidget {
  const _SelectedPlaceCard(this.place);

  final Place place;

  @override
  Widget build(BuildContext context) => Card(
    margin: const EdgeInsets.only(top: 8),
    child: Padding(
      padding: const EdgeInsets.all(12),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            place.name ?? '—',
            style: Theme.of(context).textTheme.titleMedium,
          ),
          const SizedBox(height: 4),
          Text(place.formattedAddress ?? ''),
          if (place.latLng != null)
            Text('${place.latLng!.lat}, ${place.latLng!.lng}'),
        ],
      ),
    ),
  );
}
0
likes
160
points
64
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin wrapping the native Google Places SDK (iOS & Android) with support for Places API (New). Works with API keys restricted by bundle ID / SHA-1 fingerprint.

Repository (GitHub)
View/report issues

Topics

#google #places #maps #autocomplete #location

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_places_sdk

Packages that implement flutter_places_sdk