From 65c7a3195a7597548dae5f2cc5194a3f7c046cb8 Mon Sep 17 00:00:00 2001 From: agra Date: Sat, 9 May 2026 09:04:40 +0300 Subject: [PATCH] sensor: expose orientationListenable as a ValueListenable Backed by a Dart-side 100ms poll of the existing FFI getter; the polling timer starts on first listener and stops when the last listener detaches. --- lib/src/sensor.dart | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lib/src/sensor.dart b/lib/src/sensor.dart index ecf1b47..ee32509 100644 --- a/lib/src/sensor.dart +++ b/lib/src/sensor.dart @@ -1,6 +1,8 @@ +import 'dart:async'; import 'dart:ffi'; import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; DynamicLibrary? _initLib() { @@ -34,4 +36,47 @@ class UxSensor { } return DeviceOrientation.values[idx]; } + + /// Lazily-created listenable backing [orientationListenable]. + static _OrientationNotifier? _orientationNotifier; + + /// Listenable form of [orientation], updated as the device rotates. + /// Backed by a Dart-side 100ms poll of the underlying FFI getter. + static ValueListenable get orientationListenable { + return _orientationNotifier ??= _OrientationNotifier(); + } +} + +class _OrientationNotifier extends ChangeNotifier + implements ValueListenable { + _OrientationNotifier() : _value = UxSensor.orientation; + + Timer? _timer; + DeviceOrientation _value; + + @override + DeviceOrientation get value => _value; + + @override + void addListener(VoidCallback listener) { + super.addListener(listener); + _timer ??= Timer.periodic(const Duration(milliseconds: 100), _tick); + } + + @override + void removeListener(VoidCallback listener) { + super.removeListener(listener); + if (!hasListeners) { + _timer?.cancel(); + _timer = null; + } + } + + void _tick(Timer _) { + final next = UxSensor.orientation; + if (next != _value) { + _value = next; + notifyListeners(); + } + } }