import 'dart:async'; import 'dart:math' as math; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:sensors_plus/sensors_plus.dart'; final compassServiceProvider = Provider((ref) { return CompassService(); }); final headingStreamProvider = StreamProvider((ref) { return ref.watch(compassServiceProvider).headingStream; }); class CompassService { final _headingController = StreamController.broadcast(); StreamSubscription? _magSub; Stream get headingStream => _headingController.stream; CompassService() { _startSensors(); } void _startSensors() { _magSub = magnetometerEventStream(samplingPeriod: const Duration(milliseconds: 200)).listen((MagnetometerEvent event) { // Calculate heading from magnetometer (X and Y components). // Note: For a phone mounted vertically on a motorcycle, the axes might need mapping. // This calculates basic 2D heading assuming phone is flat. // Full tilt-compensated compass requires accelerometer fusion. double heading = math.atan2(event.y, event.x) * (180.0 / math.pi); // Adjust to 0-360 degrees if (heading < 0) { heading += 360; } _headingController.add(heading); }); } String getHeadingString(double heading) { const directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']; final index = ((heading + 22.5) % 360 / 45).floor(); return directions[index]; } void dispose() { _magSub?.cancel(); _headingController.close(); } }