twonly-app-dependencies/no_screenshot/lib/no_screenshot.dart
2026-03-14 00:16:48 +01:00

182 lines
5.7 KiB
Dart

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<ScreenshotSnapshot>? _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<bool> 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<bool> screenshotOn() {
return _instancePlatform.screenshotOn();
}
@override
Future<bool> toggleScreenshotWithImage() {
return _instancePlatform.toggleScreenshotWithImage();
}
@override
Future<bool> toggleScreenshotWithBlur({double blurRadius = 30.0}) {
return _instancePlatform.toggleScreenshotWithBlur(blurRadius: blurRadius);
}
@override
Future<bool> toggleScreenshotWithColor({int color = 0xFF000000}) {
return _instancePlatform.toggleScreenshotWithColor(color: color);
}
/// Always enables image overlay mode (idempotent — safe to call repeatedly).
@override
Future<bool> screenshotWithImage() {
return _instancePlatform.screenshotWithImage();
}
/// Always enables blur overlay mode (idempotent — safe to call repeatedly).
@override
Future<bool> screenshotWithBlur({double blurRadius = 30.0}) {
return _instancePlatform.screenshotWithBlur(blurRadius: blurRadius);
}
/// Always enables color overlay mode (idempotent — safe to call repeatedly).
@override
Future<bool> 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<bool> toggleScreenshot() {
return _instancePlatform.toggleScreenshot();
}
/// Stream to screenshot activities [ScreenshotSnapshot]
///
@override
Stream<ScreenshotSnapshot> get screenshotStream {
return _instancePlatform.screenshotStream;
}
/// Start listening to screenshot activities
@override
Future<void> startScreenshotListening() {
return _instancePlatform.startScreenshotListening();
}
/// Stop listening to screenshot activities
@override
Future<void> stopScreenshotListening() {
return _instancePlatform.stopScreenshotListening();
}
/// Start listening to screen recording activities
@override
Future<void> startScreenRecordingListening() {
return _instancePlatform.startScreenRecordingListening();
}
/// Stop listening to screen recording activities
@override
Future<void> 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;
}