plug_location_map 1.0.1
plug_location_map: ^1.0.1 copied to clipboard
Plug-and-play Google Maps location package for Flutter. Body-only — host app provides its own AppBar. Handles permissions, GPS, Zomato map picker, Instacart address form, Firebase persistence, offline [...]
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:plug_location_map/plug_location_map.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// The ENTIRE host-side surface. Two package widgets, nothing else:
/// 1. PlugLocationApp — wraps the app, inits everything
/// 2. PlugHomeWrapper — body of your home page (automatic flow)
/// + PlugChooseAddressButton — opens Choose Address on tap
/// ─────────────────────────────────────────────────────────────────────────
// TODO: put your real keys + the signed-in user's id here.
const kGoogleApiKey = 'YOUR_ANDROID_API_KEY';
const kIosApiKey = 'YOUR_IOS_API_KEY';
const kUserId = 'demo-user-123';
void main() {
runApp(
// ① One wrapper. Handles Riverpod (auto-guard), permissions, Hive,
// offline sync, Firebase. You just pass keys + userId + theme.
PlugLocationApp(
config: PlugMapConfig(
googleApiKey: kGoogleApiKey,
iosApiKey: kIosApiKey,
enableFirebase: true,
userId: kUserId,
firebaseCollection: 'addresses',
// Your theme — everything in the package picks this up.
theme: const PlugMapTheme(
primaryColor: Color(0xFFFFE000),
onPrimaryColor: Color(0xFF0A0A0A),
successColor: Color(0xFF16A34A),
),
),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'plug_location_map demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true),
home: const HomePage(), // use go_router or anything — doesn't matter
);
}
}
/// Your home page. You build the AppBar; the package fills the body and runs
/// the whole location flow automatically.
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// ── YOUR styled AppBar ────────────────────────────────────────────────
appBar: AppBar(
backgroundColor: const Color(0xFFFFE000),
elevation: 0,
title: Text('My Store',
style: GoogleFonts.urbanist(
fontWeight: FontWeight.w800, color: const Color(0xFF0A0A0A))),
actions: const [
Padding(
padding: EdgeInsets.only(right: 12),
// ③ Tap → Choose Address flow (pick / edit / delete / add). Automatic.
child: Center(child: PlugChooseAddressButton()),
),
],
),
// ② The flow gate. No address → Select Location (no back arrow);
// address exists → your home content below.
body: PlugHomeWrapper(
homeBuilder: (context, address) => _HomeContent(address: address),
),
);
}
}
/// Your actual home content. Read the address straight off the param, or
/// anywhere else with `ref.watch(plugSelectedAddressProvider)`.
class _HomeContent extends ConsumerWidget {
const _HomeContent({this.address});
final PlugAddress? address;
@override
Widget build(BuildContext context, WidgetRef ref) {
// Either source works — they're the same address.
final a = address ?? ref.watch(plugSelectedAddressProvider);
return Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Delivering to',
style: GoogleFonts.urbanist(
fontSize: 12,
fontWeight: FontWeight.w700,
color: Colors.black54)),
const SizedBox(height: 4),
Text(a?.shortTitle ?? '—',
style: GoogleFonts.urbanist(
fontSize: 20, fontWeight: FontWeight.w800)),
const SizedBox(height: 2),
Text(a?.fullAddress ?? '',
style: GoogleFonts.urbanist(fontSize: 14, color: Colors.black54)),
const SizedBox(height: 24),
// Dot-notation access to everything:
_kv('name', a?.name),
_kv('street', a?.street),
_kv('city', a?.city),
_kv('pincode', a?.pincode),
_kv('lat', a?.lat.toString()),
_kv('lng', a?.lng.toString()),
_kv('type', a?.type.label),
_kv('synced', a?.isSynced.toString()),
const Spacer(),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () => PlugFlow.openChooseAddress(context),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFFE000),
foregroundColor: const Color(0xFF0A0A0A),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: Text('Change / manage addresses',
style: GoogleFonts.urbanist(fontWeight: FontWeight.w800)),
),
),
],
),
);
}
Widget _kv(String k, String? v) => Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Row(
children: [
SizedBox(
width: 80,
child: Text(k,
style: GoogleFonts.robotoMono(
fontSize: 12, color: Colors.black45))),
Expanded(
child: Text(v ?? '—',
style: GoogleFonts.robotoMono(fontSize: 12))),
],
),
);
}