no_screenshot 0.3.6 copy "no_screenshot: ^0.3.6" to clipboard
no_screenshot: ^0.3.6 copied to clipboard

Flutter plugin to enable, disable, toggle or stream screenshot activities in your application.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:no_screenshot/no_screenshot.dart';
import 'package:no_screenshot/screenshot_snapshot.dart';

import 'app_localizations.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isRTL = false;

  void _toggleRTL(bool value) {
    setState(() => _isRTL = value);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'No Screenshot Example',
      theme: ThemeData(
        colorSchemeSeed: Colors.deepPurple,
        useMaterial3: true,
      ),
      locale: _isRTL ? const Locale('ar') : const Locale('en'),
      supportedLocales: AppLocalizations.supportedLocales,
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      home: HomePage(isRTL: _isRTL, onRTLChanged: _toggleRTL),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key, required this.isRTL, required this.onRTLChanged});

  final bool isRTL;
  final ValueChanged<bool> onRTLChanged;

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _noScreenshot = NoScreenshot.instance;
  bool _isMonitoring = false;
  bool _isOverlayImageOn = false;
  ScreenshotSnapshot _latestSnapshot = ScreenshotSnapshot(
    isScreenshotProtectionOn: false,
    wasScreenshotTaken: false,
    screenshotPath: '',
  );

  @override
  void initState() {
    super.initState();
    _noScreenshot.screenshotStream.listen((value) {
      setState(() => _latestSnapshot = value);
      if (value.wasScreenshotTaken) {
        debugPrint('Screenshot taken at path: ${value.screenshotPath}');
        _showScreenshotAlert(value.screenshotPath);
      }
    });
  }

  // ── Screenshot Protection ──────────────────────────────────────────

  Future<void> _disableScreenshot() async {
    final result = await _noScreenshot.screenshotOff();
    debugPrint('screenshotOff: $result');
  }

  Future<void> _enableScreenshot() async {
    final result = await _noScreenshot.screenshotOn();
    debugPrint('screenshotOn: $result');
  }

  Future<void> _toggleScreenshot() async {
    final result = await _noScreenshot.toggleScreenshot();
    debugPrint('toggleScreenshot: $result');
  }

  // ── Screenshot Monitoring ──────────────────────────────────────────

  Future<void> _startMonitoring() async {
    await _noScreenshot.startScreenshotListening();
    setState(() => _isMonitoring = true);
  }

  Future<void> _stopMonitoring() async {
    await _noScreenshot.stopScreenshotListening();
    setState(() => _isMonitoring = false);
  }

  // ── Set Overlay Image ──────────────────────────────────────────────

  Future<void> _toggleScreenshotWithImage() async {
    final result = await _noScreenshot.toggleScreenshotWithImage();
    debugPrint('toggleScreenshotWithImage: $result');
    setState(() => _isOverlayImageOn = result);
  }

  // ── UI ─────────────────────────────────────────────────────────────

  @override
  Widget build(BuildContext context) {
    final l = AppLocalizations.of(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(l.appTitle),
        actions: [
          Text(l.rtl),
          Switch(
            value: widget.isRTL,
            onChanged: widget.onRTLChanged,
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          _buildSection(
            title: l.protectionSectionTitle,
            subtitle: l.platformSubtitle,
            children: [
              _StatusRow(
                label: l.protection,
                isOn: _latestSnapshot.isScreenshotProtectionOn,
              ),
              const SizedBox(height: 12),
              Row(
                children: [
                  Expanded(
                    child: _FeatureButton(
                      label: l.disableScreenshot,
                      subtitle: l.blocksCapture,
                      onPressed: _disableScreenshot,
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: _FeatureButton(
                      label: l.enableScreenshot,
                      subtitle: l.allowsCapture,
                      onPressed: _enableScreenshot,
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 8),
              _FeatureButton(
                label: l.toggleScreenshot,
                subtitle: l.toggleScreenshotSubtitle,
                onPressed: _toggleScreenshot,
              ),
            ],
          ),
          const SizedBox(height: 16),
          _buildSection(
            title: l.monitoringSectionTitle,
            subtitle: l.platformSubtitle,
            children: [
              _StatusRow(
                label: l.monitoring,
                isOn: _isMonitoring,
              ),
              const SizedBox(height: 8),
              _SnapshotInfo(snapshot: _latestSnapshot),
              const SizedBox(height: 12),
              Row(
                children: [
                  Expanded(
                    child: _FeatureButton(
                      label: l.enableMonitoring,
                      subtitle: l.startListening,
                      onPressed: _startMonitoring,
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: _FeatureButton(
                      label: l.disableMonitoring,
                      subtitle: l.stopListening,
                      onPressed: _stopMonitoring,
                    ),
                  ),
                ],
              ),
            ],
          ),
          const SizedBox(height: 16),
          _buildSection(
            title: l.overlaySectionTitle,
            subtitle: l.platformSubtitle,
            children: [
              _StatusRow(
                label: l.overlay,
                isOn: _isOverlayImageOn,
              ),
              const SizedBox(height: 12),
              _FeatureButton(
                label: l.toggleScreenshotWithImage,
                subtitle: l.overlaySubtitle,
                onPressed: _toggleScreenshotWithImage,
              ),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildSection({
    required String title,
    required String subtitle,
    required List<Widget> children,
  }) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Wrap(
              runAlignment: WrapAlignment.center,
              children: [
                Text(
                  title,
                  style: Theme.of(context).textTheme.titleMedium,
                ),
                const SizedBox(width: 8),
                Chip(
                  label: Text(subtitle),
                  visualDensity: VisualDensity.compact,
                ),
              ],
            ),
            const SizedBox(height: 12),
            ...children,
          ],
        ),
      ),
    );
  }

  void _showScreenshotAlert(String path) {
    final l = AppLocalizations.of(context);
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        icon: const Icon(Icons.warning_amber_outlined,
            size: 48, color: Colors.red),
        title: Text(l.screenshotDetected),
        content: Text('${l.path}: $path'),
        actions: [
          FilledButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text(l.ok),
          ),
        ],
      ),
    );
  }
}

// ── Reusable Widgets ───────────────────────────────────────────────────

class _FeatureButton extends StatelessWidget {
  const _FeatureButton({
    required this.label,
    required this.subtitle,
    required this.onPressed,
  });

  final String label;
  final String subtitle;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: OutlinedButton(
        onPressed: onPressed,
        style: OutlinedButton.styleFrom(
          padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
          alignment: AlignmentDirectional.centerStart,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(6),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(label),
            Text(
              subtitle,
              style: Theme.of(context).textTheme.bodySmall,
            ),
          ],
        ),
      ),
    );
  }
}

class _StatusRow extends StatelessWidget {
  const _StatusRow({required this.label, required this.isOn});

  final String label;
  final bool isOn;

  @override
  Widget build(BuildContext context) {
    final l = AppLocalizations.of(context);
    return Row(
      children: [
        Text('$label: ', style: Theme.of(context).textTheme.bodyMedium),
        Container(
          width: 12,
          height: 12,
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: isOn ? Colors.green : Colors.grey,
          ),
        ),
        const SizedBox(width: 6),
        Text(isOn ? l.on : l.off),
      ],
    );
  }
}

class _SnapshotInfo extends StatelessWidget {
  const _SnapshotInfo({required this.snapshot});

  final ScreenshotSnapshot snapshot;

  @override
  Widget build(BuildContext context) {
    final l = AppLocalizations.of(context);
    final style = Theme.of(context).textTheme.bodySmall;
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('${l.protectionActive}: ${snapshot.isScreenshotProtectionOn}',
              style: style?.copyWith(
                  color: snapshot.isScreenshotProtectionOn
                      ? Colors.green
                      : Colors.red)),
          Text('${l.screenshotTaken}: ${snapshot.wasScreenshotTaken}',
              style: style),
          Text('${l.path}: ${snapshot.screenshotPath}', style: style),
        ],
      ),
    );
  }
}
238
likes
0
points
80.7k
downloads

Publisher

verified publisherflutterplaza.com

Weekly Downloads

Flutter plugin to enable, disable, toggle or stream screenshot activities in your application.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on no_screenshot

Packages that implement no_screenshot