import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// Service for managing blocked phone numbers class BlockService { static const String _blockedNumbersKey = 'blocked_numbers'; static const MethodChannel _channel = MethodChannel('com.example.block'); // Private constructor BlockService._privateConstructor(); // Singleton instance static final BlockService _instance = BlockService._privateConstructor(); // Factory constructor to return the same instance factory BlockService() { return _instance; } /// Block a phone number (syncs with system and app) Future blockNumber(String phoneNumber) async { try { // First try to block in system try { await _channel.invokeMethod('blockNumber', {'number': phoneNumber}); } catch (e) { debugPrint('Failed to block in system: $e'); } // Always save to app storage as backup final prefs = await SharedPreferences.getInstance(); final blockedNumbers = prefs.getStringList(_blockedNumbersKey) ?? []; // Don't add if already blocked if (!blockedNumbers.contains(phoneNumber)) { blockedNumbers.add(phoneNumber); await prefs.setStringList(_blockedNumbersKey, blockedNumbers); } return true; // Return true if either system or app blocking succeeded } catch (e) { debugPrint('Error blocking number: $e'); return false; } } /// Unblock a phone number (syncs with system and app) Future unblockNumber(String phoneNumber) async { try { // First try to unblock from system try { await _channel.invokeMethod('unblockNumber', {'number': phoneNumber}); } catch (e) { debugPrint('Failed to unblock from system: $e'); } // Always remove from app storage final prefs = await SharedPreferences.getInstance(); final blockedNumbers = prefs.getStringList(_blockedNumbersKey) ?? []; if (blockedNumbers.contains(phoneNumber)) { blockedNumbers.remove(phoneNumber); await prefs.setStringList(_blockedNumbersKey, blockedNumbers); } return true; } catch (e) { debugPrint('Error unblocking number: $e'); return false; } } /// Check if a number is blocked (checks both system and app) Future isNumberBlocked(String phoneNumber) async { try { // Check system first try { bool systemBlocked = await _channel.invokeMethod('isNumberBlocked', {'number': phoneNumber}); if (systemBlocked) return true; } catch (e) { debugPrint('Failed to check system blocked status: $e'); } // Check app storage as fallback final prefs = await SharedPreferences.getInstance(); final blockedNumbers = prefs.getStringList(_blockedNumbersKey) ?? []; return blockedNumbers.contains(phoneNumber); } catch (e) { debugPrint('Error checking if number is blocked: $e'); return false; } } /// Get all blocked numbers (merges system and app blocked numbers) Future> getBlockedNumbers() async { try { Set allBlockedNumbers = {}; // Get system blocked numbers try { List systemBlocked = await _channel.invokeMethod('getBlockedNumbers'); allBlockedNumbers.addAll(systemBlocked.cast()); } catch (e) { debugPrint('Failed to get system blocked numbers: $e'); } // Get app blocked numbers try { final prefs = await SharedPreferences.getInstance(); final appBlocked = prefs.getStringList(_blockedNumbersKey) ?? []; allBlockedNumbers.addAll(appBlocked); } catch (e) { debugPrint('Failed to get app blocked numbers: $e'); } return allBlockedNumbers.toList()..sort(); } catch (e) { debugPrint('Error getting blocked numbers: $e'); return []; } } /// Sync app blocked numbers with system blocked numbers Future syncWithSystem() async { try { // Get system blocked numbers List systemBlocked = []; try { List result = await _channel.invokeMethod('getBlockedNumbers'); systemBlocked = result.cast(); } catch (e) { debugPrint('Failed to get system blocked numbers for sync: $e'); return; } // Get app blocked numbers final prefs = await SharedPreferences.getInstance(); List appBlocked = prefs.getStringList(_blockedNumbersKey) ?? []; // Merge them (system takes precedence) Set mergedBlocked = {...systemBlocked, ...appBlocked}; // Update app storage with merged list await prefs.setStringList(_blockedNumbersKey, mergedBlocked.toList()); debugPrint('Synced ${mergedBlocked.length} blocked numbers with system'); } catch (e) { debugPrint('Error syncing with system: $e'); } } }