import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(const IcingDialerApp()); } class IcingDialerApp extends StatefulWidget { const IcingDialerApp({Key? key}) : super(key: key); @override State createState() => _IcingDialerAppState(); } class _IcingDialerAppState extends State { // This channel must match the one in MainActivity.kt. static const platform = MethodChannel('com.example.dialer/call_events'); bool isDefaultDialer = false; @override void initState() { super.initState(); // Listen for method calls from the Android side. platform.setMethodCallHandler(handleMethodCalls); } Future handleMethodCalls(MethodCall call) async { switch (call.method) { case 'onDefaultDialerSet': // Update our UI to show that we are now the default dialer. setState(() { isDefaultDialer = true; }); break; case 'onDefaultDialerDenied': // Show a message to the user when they deny the request. _showDefaultDialerDeniedDialog(); break; case 'onIncomingCall': final phoneNumber = call.arguments as String? ?? "Unknown"; _showIncomingCallDialog(phoneNumber); break; default: print("Unhandled method: ${call.method}"); } } // Show a dialog when the user denies the default dialer request. void _showDefaultDialerDeniedDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Permission Denied'), content: const Text( 'To use this app as your default dialer, please grant the permission when prompted.'), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: const Text('OK'), ), ], ), ); } // Show a dialog when an incoming call is intercepted. void _showIncomingCallDialog(String phoneNumber) { showDialog( context: context, barrierDismissible: false, builder: (_) => AlertDialog( title: const Text('Incoming Call'), content: Text('Call from: $phoneNumber'), actions: [ TextButton( onPressed: () { // (Here you could add code to reject the call.) Navigator.of(context).pop(); }, child: const Text('Reject'), ), ElevatedButton( onPressed: () { // (Here you could add code to accept the call.) Navigator.of(context).pop(); }, child: const Text('Accept'), ), ], ), ); } // Invoke the native method to request to be the default dialer. Future requestDefaultDialer() async { try { await platform.invokeMethod('requestDefaultDialer'); } catch (e) { print('Error requesting default dialer: $e'); // Show an error message if the request fails. ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error requesting default dialer: $e')), ); } } @override Widget build(BuildContext context) { return MaterialApp( title: 'Icing Dialer', theme: ThemeData.dark(), home: isDefaultDialer ? const CallScreen() : DefaultDialerSetupScreen(onRequestDefaultDialer: requestDefaultDialer), ); } } /// Shown when the app is not yet the default dialer. class DefaultDialerSetupScreen extends StatelessWidget { final VoidCallback onRequestDefaultDialer; const DefaultDialerSetupScreen({Key? key, required this.onRequestDefaultDialer}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Set as Default Dialer')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'This app is not set as your default dialer.', textAlign: TextAlign.center, ), const SizedBox(height: 20), ElevatedButton( onPressed: onRequestDefaultDialer, child: const Text('Set as Default Dialer'), ), ], ), ), ); } } /// Shown when the app is the default dialer. class CallScreen extends StatelessWidget { const CallScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { // A simple UI indicating that the app is waiting for incoming calls. return Scaffold( appBar: AppBar(title: const Text('Icing Dialer')), body: const Center( child: Text('Waiting for incoming calls...'), ), ); } }