navigation_safety 0.9.0
navigation_safety: ^0.9.0 copied to clipboard
Show drivers what matters before it's too late. Safety alert overlay that stays on top of your navigation UI. Navigation session state machine with configurable severity thresholds. Display-only, neve [...]
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:latlong2/latlong.dart';
import 'package:navigation_safety/navigation_safety.dart';
import 'package:routing_engine/routing_engine.dart';
/// Local adapter mirroring lib/adapters/navigation_route_adapter.dart.
/// Examples sit at the routing→navigation boundary; the production
/// adapter is internal to the main app and not exported from any
/// package, so examples carry their own identical copy.
extension _RouteResultToNavigation on RouteResult {
NavigationRoute toNavigationRoute() => NavigationRoute(
shape: shape,
maneuvers: maneuvers
.map((m) => NavigationManeuver(
index: m.index,
instruction: m.instruction,
type: m.type,
lengthKm: m.lengthKm,
timeSeconds: m.timeSeconds,
position: m.position,
))
.toList(),
totalDistanceKm: totalDistanceKm,
totalTimeSeconds: totalTimeSeconds,
summary: summary,
);
}
final _exampleRoute = RouteResult(
shape: const [LatLng(35.1709, 136.9066), LatLng(34.9551, 137.1771)],
maneuvers: const [
RouteManeuver(
index: 0,
instruction: 'Depart Sakae Station',
type: 'depart',
lengthKm: 12,
timeSeconds: 900,
position: LatLng(35.1709, 136.9066),
),
RouteManeuver(
index: 1,
instruction: 'Arrive Higashiokazaki Station',
type: 'arrive',
lengthKm: 0,
timeSeconds: 0,
position: LatLng(34.9551, 137.1771),
),
],
totalDistanceKm: 40.0,
totalTimeSeconds: 2400,
summary: '40 km, 40 min',
engineInfo: const EngineInfo(name: 'mock'),
);
void main() {
runApp(const NavigationSafetyExampleApp());
}
class NavigationSafetyExampleApp extends StatelessWidget {
const NavigationSafetyExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (_) => NavigationBloc()
..add(NavigationStarted(route: _exampleRoute.toNavigationRoute())),
child: const _ExampleScreen(),
),
);
}
}
class _ExampleScreen extends StatelessWidget {
const _ExampleScreen();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('navigation_safety example')),
body: Stack(
children: [
Positioned.fill(
child: ColoredBox(
color: Colors.blueGrey.shade50,
child: const Center(
child: Text('Map layer placeholder'),
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.all(16),
child: Wrap(
spacing: 12,
runSpacing: 12,
alignment: WrapAlignment.center,
children: [
FilledButton(
onPressed: () => context.read<NavigationBloc>().add(
const SafetyAlertReceived(
message: 'Snow expected in 30 minutes',
severity: AlertSeverity.info,
),
),
child: const Text('Info'),
),
FilledButton(
onPressed: () => context.read<NavigationBloc>().add(
const SafetyAlertReceived(
message: 'Icy road conditions ahead',
severity: AlertSeverity.warning,
),
),
child: const Text('Warning'),
),
FilledButton(
onPressed: () => context.read<NavigationBloc>().add(
const SafetyAlertReceived(
message: 'Visibility zero - pull over immediately',
severity: AlertSeverity.critical,
dismissible: false,
),
),
child: const Text('Critical'),
),
OutlinedButton(
onPressed: () => context
.read<NavigationBloc>()
.add(const SafetyAlertDismissed()),
child: const Text('Dismiss'),
),
],
),
),
),
const SafetyOverlay(),
],
),
);
}
}