stopou_blocker 0.2.1 copy "stopou_blocker: ^0.2.1" to clipboard
stopou_blocker: ^0.2.1 copied to clipboard

Plugin do Stopou para bloqueio por VPN local (preparado para estratégias futuras).

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:stopou_blocker/stopou_blocker.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Stopou Blocker Demo',
      theme: ThemeData(useMaterial3: true),
      home: const DemoPage(),
    );
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key});
  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  final _log = <String>[];
  bool _vpnRunning = false;
  bool _keywordBlockerRunning = false;
  bool _hasVpnPermission = false;
  bool _hasAccessibilityPermission = false;
  bool _hasNotificationPermission = false;

  @override
  void initState() {
    super.initState();
    // ✅ Assina o stream de eventos do plugin.
    StopouBlocker.events.listen((e) {
      setState(() {
        _log.add(
          "${e.ts.toIso8601String()}   ${e.protocol.padRight(5)}   ${e.host}   ${e.appPackage ?? ''}",
        );
      });
    });
    
    // ✅ Verifica status inicial
    _updateStatus();
  }

  Future<void> _updateStatus() async {
    final vpnRunning = await StopouBlocker.isVpnRunning();
    final keywordRunning = await StopouBlocker.isKeywordBlockerRunning();
    final hasVpn = await StopouBlocker.hasVpnPermission();
    final hasAccessibility = await StopouBlocker.hasAccessibilityPermission();
    final hasNotification = await StopouBlocker.hasNotificationPermission();
    
    setState(() {
      _vpnRunning = vpnRunning;
      _keywordBlockerRunning = keywordRunning;
      _hasVpnPermission = hasVpn;
      _hasAccessibilityPermission = hasAccessibility;
      _hasNotificationPermission = hasNotification;
    });
  }

  void _showAccessibilityInstructions() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('⚠️ Permissão de Acessibilidade'),
        content: const SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Se o Android mostrar "permissão restrita", siga estes passos:',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 12),
              Text('1. Nas configurações de Acessibilidade, encontre "Stopou"'),
              SizedBox(height: 8),
              Text('2. Toque em "Stopou" para abrir as configurações'),
              SizedBox(height: 8),
              Text('3. Se aparecer aviso de "permissão restrita", toque em "Aprenda a conceder acesso"'),
              SizedBox(height: 8),
              Text('4. Ative o toggle para "Usar Stopou"'),
              SizedBox(height: 8),
              Text('5. Confirme tocando em "OK" quando perguntado'),
              SizedBox(height: 12),
              Text(
                'ℹ️ O Stopou é seguro: apenas detecta palavras específicas e exibe alertas. Não coleta dados pessoais.',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
            ],
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('Entendi'),
          ),
          ElevatedButton(
            onPressed: () async {
              Navigator.of(context).pop();
              await StopouBlocker.openAccessibilitySettings();
            },
            child: const Text('Abrir Configurações'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Stopou Blocker Demo'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _updateStatus,
            tooltip: 'Atualizar Status',
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // Status Section
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('📊 Status dos Serviços', 
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    const SizedBox(height: 12),
                    Row(
                      children: [
                        Icon(
                          _vpnRunning ? Icons.vpn_lock : Icons.vpn_lock_outlined,
                          color: _vpnRunning ? Colors.green : Colors.grey,
                        ),
                        const SizedBox(width: 8),
                        Text('VPN: ${_vpnRunning ? "Ativo" : "Inativo"}'),
                      ],
                    ),
                    const SizedBox(height: 8),
                    Row(
                      children: [
                        Icon(
                          _keywordBlockerRunning ? Icons.accessibility : Icons.accessibility_outlined,
                          color: _keywordBlockerRunning ? Colors.green : Colors.grey,
                        ),
                        const SizedBox(width: 8),
                        Text('Bloqueador Keywords: ${_keywordBlockerRunning ? "Ativo" : "Inativo"}'),
                      ],
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Permissions Section
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('🔑 Permissões', 
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    const SizedBox(height: 12),
                    
                    ElevatedButton.icon(
                      onPressed: () async {
                        final ok = await StopouBlocker.requestPermission();
                        await _updateStatus();
                        if (mounted) {
                          ScaffoldMessenger.of(context).showSnackBar(
                            SnackBar(content: Text('Permissão VPN: $ok')),
                          );
                        }
                      },
                      icon: Icon(_hasVpnPermission ? Icons.check : Icons.vpn_key),
                      label: Text('VPN ${_hasVpnPermission ? "✓" : "✗"}'),
                    ),
                    const SizedBox(height: 8),

                    ElevatedButton.icon(
                      onPressed: () async {
                        final ok = await StopouBlocker.requestAccessibilityPermission();
                        await _updateStatus();
                        if (mounted) {
                          if (!ok) {
                            _showAccessibilityInstructions();
                          } else {
                            ScaffoldMessenger.of(context).showSnackBar(
                              const SnackBar(content: Text('Permissão Acessibilidade: ✓')),
                            );
                          }
                        }
                      },
                      icon: Icon(_hasAccessibilityPermission ? Icons.check : Icons.accessibility),
                      label: Text('Acessibilidade ${_hasAccessibilityPermission ? "✓" : "✗"}'),
                    ),
                    const SizedBox(height: 8),

                    ElevatedButton.icon(
                      onPressed: () async {
                        final ok = await StopouBlocker.requestNotificationPermission();
                        await _updateStatus();
                        if (mounted) {
                          ScaffoldMessenger.of(context).showSnackBar(
                            SnackBar(content: Text('Permissão Notificação: $ok')),
                          );
                        }
                      },
                      icon: Icon(_hasNotificationPermission ? Icons.check : Icons.notifications),
                      label: Text('Notificações ${_hasNotificationPermission ? "✓" : "✗"}'),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Controls Section
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('🎛️ Controles', 
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                    const SizedBox(height: 12),
                    
                    ElevatedButton.icon(
                      onPressed: _vpnRunning ? null : () async {
                        await StopouBlocker.start(
                          blocklist: const ['.bet.br', 'exemplo.com'],
                          logAttempts: true,
                          dnsServers: const ['1.1.1.1', '8.8.8.8'],
                          strategies: const [BlockStrategies.vpn],
                        );
                        await _updateStatus();
                      },
                      icon: const Icon(Icons.play_arrow),
                      label: const Text('Iniciar VPN'),
                    ),
                    const SizedBox(height: 8),

                    ElevatedButton.icon(
                      onPressed: _keywordBlockerRunning ? null : () async {
                        await StopouBlocker.startKeywordBlocker([
                          'bet',
                          'casino',
                          'apostas',
                        ]);
                        await _updateStatus();
                      },
                      icon: const Icon(Icons.block),
                      label: const Text('Iniciar Bloqueador Keywords'),
                    ),
                    const SizedBox(height: 8),

                    ElevatedButton.icon(
                      onPressed: (!_vpnRunning && !_keywordBlockerRunning) ? null : () async {
                        await StopouBlocker.stop();
                        await StopouBlocker.stopKeywordBlocker();
                        await _updateStatus();
                      },
                      icon: const Icon(Icons.stop),
                      label: const Text('Parar Tudo'),
                      style: ElevatedButton.styleFrom(backgroundColor: Colors.red[100]),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Events Log
            const Align(
              alignment: Alignment.centerLeft,
              child: Text('📝 Log de Eventos:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            ),
            const SizedBox(height: 8),
            Expanded(
              child: Container(
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.shade300),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: _log.isEmpty 
                  ? const Center(child: Text('Nenhum evento registrado ainda...'))
                  : ListView.builder(
                      itemCount: _log.length,
                      itemBuilder: (_, i) => Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                        child: Text(
                          _log[_log.length - 1 - i], // Mais recentes primeiro
                          style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
                        ),
                      ),
                    ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
0
likes
0
points
9
downloads

Publisher

unverified uploader

Weekly Downloads

Plugin do Stopou para bloqueio por VPN local (preparado para estratégias futuras).

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on stopou_blocker

Packages that implement stopou_blocker