// lib/widgets/activity/activity_auto_sync_controller.dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; class ActivityAutoSyncController { static const EventChannel _activityDirectoryChangeChannel = EventChannel('deckers.thibault/aves/activity_directory_change'); final Future Function(String reason) onScanRequested; StreamSubscription? _subscription; Timer? _debounce; bool _started = false; bool _disposed = false; ActivityAutoSyncController({ required this.onScanRequested, }); void start() { if (_disposed) return; if (_started) return; _started = true; _subscription = _activityDirectoryChangeChannel.receiveBroadcastStream().listen( _onNativeWatcherEvent, onError: _onNativeWatcherError, cancelOnError: false, ); debugPrint('[ActivityAutoSync] watcher started'); } void schedule({ required String reason, Duration delay = const Duration(seconds: 2), }) { if (_disposed) return; _debounce?.cancel(); debugPrint( '[ActivityAutoSync] schedule scan reason=$reason delay=${delay.inMilliseconds}ms', ); _debounce = Timer(delay, () { _run(reason); }); } Future _run(String reason) async { if (_disposed) return; try { debugPrint('[ActivityAutoSync] scan requested reason=$reason'); await onScanRequested(reason); } catch (e, st) { debugPrint('[ActivityAutoSync] scan failed reason=$reason error=$e'); debugPrint('[ActivityAutoSync] stack=$st'); } } void _onNativeWatcherEvent(Object? event) { if (_disposed) return; debugPrint('[ActivityAutoSync] native event=$event'); schedule( reason: 'native_watcher', delay: const Duration(seconds: 2), ); } void _onNativeWatcherError(Object error, StackTrace stack) { if (_disposed) return; debugPrint('[ActivityAutoSync] watcher error=$error'); debugPrint('[ActivityAutoSync] watcher stack=$stack'); } void dispose() { if (_disposed) return; _disposed = true; _debounce?.cancel(); _debounce = null; _subscription?.cancel(); _subscription = null; debugPrint('[ActivityAutoSync] disposed'); } }