import 'dart:async'; import 'dart:math' as math; import '../domain/entities/reverse_camera_data.dart'; /// 倒车影像数据源抽象:UI/Cubit 只依赖这个流,不关心数据真假。 abstract class ReverseCameraSource { Stream get dataStream; void start(); Future stop(); } /// Mock 源:嵌入式未就绪前,制造会“动起来”的假数据用于联调动画。 /// /// 将来接入真实数据时,只需在 Cubit 里把这里换成基于 /// MQTT vehicleStream / TCP 0x02 回包解析的实现类,其余 UI / state 全不动。 class MockReverseCameraSource implements ReverseCameraSource { final StreamController _controller = StreamController.broadcast(); Timer? _timer; final math.Random _rnd = math.Random(); int _tick = 0; @override Stream get dataStream => _controller.stream; @override void start() { stop(); // ~15Hz 推送,动画足够顺滑;将来真数据 5~10Hz 也够用。 _timer = Timer.periodic(const Duration(milliseconds: 66), (Timer t) { _tick++; // 转向角做正弦摆动(模拟倒车打方向),速度小幅抖动,距离缓慢变化便于测颜色刻度。 final double sway = math.sin(_tick / 6.0) * 28.0; // -28° ~ +28° final double speed = 0.3 + _rnd.nextDouble() * 0.5; // 0.3 ~ 0.8 m/s final int dist = 40 + (_tick % 160); // 40 ~ 199cm,循环变化 _controller.add( ReverseCameraData( gear: 2, // 假数据默认处于“倒车挡”,进页面即可看到动画 steeringAngle: sway, speed: speed, rearDistanceCm: dist, ), ); }); } @override Future stop() async { _timer?.cancel(); _timer = null; if (!_controller.isClosed) { _controller.add(const ReverseCameraData.idle()); } } /// 释放流控制器(Cubit close 时调用,避免资源泄漏)。 Future dispose() async { await stop(); await _controller.close(); } }