import 'dart:async'; import 'package:no_screenshot/screenshot_snapshot.dart'; import 'no_screenshot_platform_interface.dart'; /// Callback type for screenshot and recording events. typedef ScreenshotEventCallback = void Function(ScreenshotSnapshot snapshot); /// A class that provides a platform-agnostic way to disable screenshots. /// class NoScreenshot implements NoScreenshotPlatform { NoScreenshotPlatform get _instancePlatform => NoScreenshotPlatform.instance; NoScreenshot._(); @Deprecated( "Using this may cause issue\nUse instance directly\ne.g: 'NoScreenshot.instance.screenshotOff()'", ) NoScreenshot(); static final NoScreenshot instance = NoScreenshot._(); // ── Granular Callbacks (P15) ──────────────────────────────────────── /// Called when a screenshot is detected. ScreenshotEventCallback? onScreenshotDetected; /// Called when screen recording starts. ScreenshotEventCallback? onScreenRecordingStarted; /// Called when screen recording stops. ScreenshotEventCallback? onScreenRecordingStopped; StreamSubscription? _callbackSubscription; bool _wasRecording = false; /// Starts dispatching events to [onScreenshotDetected], /// [onScreenRecordingStarted], and [onScreenRecordingStopped]. /// /// Listens to [screenshotStream] internally. Call [stopCallbacks] or /// [removeAllCallbacks] to cancel. void startCallbacks() { if (_callbackSubscription != null) return; _callbackSubscription = screenshotStream.listen(_dispatchCallbacks); } /// Stops dispatching events but keeps callback assignments. void stopCallbacks() { _callbackSubscription?.cancel(); _callbackSubscription = null; } /// Stops dispatching and clears all callback assignments. void removeAllCallbacks() { stopCallbacks(); onScreenshotDetected = null; onScreenRecordingStarted = null; onScreenRecordingStopped = null; _wasRecording = false; } /// Whether callbacks are currently being dispatched. bool get hasActiveCallbacks => _callbackSubscription != null; void _dispatchCallbacks(ScreenshotSnapshot snapshot) { if (snapshot.wasScreenshotTaken) { onScreenshotDetected?.call(snapshot); } if (!_wasRecording && snapshot.isScreenRecording) { onScreenRecordingStarted?.call(snapshot); } if (_wasRecording && !snapshot.isScreenRecording) { onScreenRecordingStopped?.call(snapshot); } _wasRecording = snapshot.isScreenRecording; } // ── Platform delegation ───────────────────────────────────────────── /// Return `true` if screenshot capabilities has been /// successfully disabled or is currently disabled and `false` otherwise. /// throw `UnmimplementedError` if not implement /// @override Future screenshotOff() { return _instancePlatform.screenshotOff(); } /// Return `true` if screenshot capabilities has been /// successfully enabled or is currently enabled and `false` otherwise. /// throw `UnmimplementedError` if not implement /// @override Future screenshotOn() { return _instancePlatform.screenshotOn(); } @override Future toggleScreenshotWithImage() { return _instancePlatform.toggleScreenshotWithImage(); } @override Future toggleScreenshotWithBlur({double blurRadius = 30.0}) { return _instancePlatform.toggleScreenshotWithBlur(blurRadius: blurRadius); } @override Future toggleScreenshotWithColor({int color = 0xFF000000}) { return _instancePlatform.toggleScreenshotWithColor(color: color); } /// Always enables image overlay mode (idempotent — safe to call repeatedly). @override Future screenshotWithImage() { return _instancePlatform.screenshotWithImage(); } /// Always enables blur overlay mode (idempotent — safe to call repeatedly). @override Future screenshotWithBlur({double blurRadius = 30.0}) { return _instancePlatform.screenshotWithBlur(blurRadius: blurRadius); } /// Always enables color overlay mode (idempotent — safe to call repeatedly). @override Future screenshotWithColor({int color = 0xFF000000}) { return _instancePlatform.screenshotWithColor(color: color); } /// Return `true` if screenshot capabilities has been /// successfully toggle from it previous state and `false` if the attempt /// to toggle failed. /// throw `UnmimplementedError` if not implement /// @override Future toggleScreenshot() { return _instancePlatform.toggleScreenshot(); } /// Stream to screenshot activities [ScreenshotSnapshot] /// @override Stream get screenshotStream { return _instancePlatform.screenshotStream; } /// Start listening to screenshot activities @override Future startScreenshotListening() { return _instancePlatform.startScreenshotListening(); } /// Stop listening to screenshot activities @override Future stopScreenshotListening() { return _instancePlatform.stopScreenshotListening(); } /// Start listening to screen recording activities @override Future startScreenRecordingListening() { return _instancePlatform.startScreenRecordingListening(); } /// Stop listening to screen recording activities @override Future stopScreenRecordingListening() { return _instancePlatform.stopScreenRecordingListening(); } @override bool operator ==(Object other) { return identical(this, other) || other is NoScreenshot && runtimeType == other.runtimeType && _instancePlatform == other._instancePlatform; } @override int get hashCode => _instancePlatform.hashCode; }