SMS succesfully sent

This commit is contained in:
2025-10-27 17:36:28 +05:30
parent 2743f92283
commit dd3e94a69e
6 changed files with 664 additions and 57 deletions

View File

@@ -1,63 +1,239 @@
// ignore_for_file: avoid_print
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:send_message/send_message.dart' show sendSMS;
import 'package:simcards/sim_card.dart';
import 'package:simcards/simcards.dart';
// // ignore_for_file: avoid_print
// import 'dart:io';
// import 'package:flutter/material.dart';
// import 'package:send_message/send_message.dart' show sendSMS;
// import 'package:simcards/sim_card.dart';
// import 'package:simcards/simcards.dart';
import 'package:uuid/uuid.dart';
// import 'package:uuid/uuid.dart';
class SmsService {
final Simcards _simcards = Simcards();
// class SmsService {
// final Simcards _simcards = Simcards();
Future<void> sendVerificationSms({
required BuildContext context,
required String destinationNumber,
required String message,
}) async {
try {
await _simcards.requestPermission();
// Future<void> sendVerificationSms({
// required BuildContext context,
// required String destinationNumber,
// required String message,
// }) async {
// try {
// await _simcards.requestPermission();
bool permissionGranted = await _simcards.hasPermission();
if (!permissionGranted) {
print("Permission denied." );
return;
// bool permissionGranted = await _simcards.hasPermission();
// if (!permissionGranted) {
// print("Permission denied." );
// return;
// }
// List<SimCard> simCardList = await _simcards.getSimCards();
// if (simCardList.isEmpty) {
// print("No SIM detected." );
// return;
// }
// await _sendSms(destinationNumber, message, simCardList.first);
// } catch (e) {
// print("Error in SMS process: $e");
// }
// }
// Future<void> _sendSms(
// String destinationNumber, String message, SimCard selectedSim) async {
// if (Platform.isAndroid) {
// try {
// var uuid = const Uuid();
// String uniqueId = uuid.v4();
// String smsMessage = uniqueId;
// String result = await sendSMS(
// message: smsMessage,
// recipients: [destinationNumber],
// sendDirect: false,
// );
// print("SMS send result: $result. Sent via ${selectedSim.displayName} (Note: OS default SIM isused).");
// } catch (e) {
// print("Error sending SMS: $e");
// }
// } else {
// print("SMS sending is only supported on Android.");
// }
// }
// }
// import 'dart:io';
// import 'package:flutter/material.dart';
// import 'package:permission_handler/permission_handler.dart'; // Import permission_handler
// import 'package:send_message/send_message.dart' show sendSMS;
// import 'package:simcards/sim_card.dart';
// import 'package:simcards/simcards.dart';
// class SmsService {
// final Simcards _simcards = Simcards();
// Future<bool> sendVerificationSms({
// required BuildContext context,
// required String destinationNumber,
// required String message,
// }) async {
// try {
// // --- NEW PERMISSION LOGIC ---
// // 1. Request both Phone and SMS permissions
// Map<Permission, PermissionStatus> statuses = await [
// Permission.phone,
// Permission.sms,
// ].request();
// // 2. Check if both permissions were granted
// if (statuses[Permission.phone]!.isGranted && statuses[Permission.sms]!.isGranted) {
// print("Phone and SMS permissions are granted.");
// } else {
// print("Permission was denied. Phone status: ${statuses[Permission.phone]}, SMS status: ${statuses[Permission.sms]}");
// // Optionally, you can open app settings to let the user grant it manually
// // openAppSettings();
// return false;
// }
// // --- END OF NEW PERMISSION LOGIC ---
// // Check for SIM card (this part remains the same)
// List<SimCard> simCardList = await _simcards.getSimCards();
// if (simCardList.isEmpty) {
// print("No SIM card detected.");
// return false;
// }
// // Try sending the SMS and return the result
// return await _sendSms(destinationNumber, message, simCardList.first);
// } catch (e) {
// print("An error occurred in the SMS process: $e");
// return false;
// }
// }
// Future<bool> _sendSms(
// String destinationNumber, String message, SimCard selectedSim) async {
// if (Platform.isAndroid) {
// try {
// String smsMessage = message;
// String result = await sendSMS(
// message: smsMessage,
// recipients: [destinationNumber],
// sendDirect: true, // Still attempting direct send as requested
// );
// print("Background SMS send attempt result: $result");
// if (result.toLowerCase().contains('sent')) {
// print("Success: SMS appears to have been sent.");
// return true;
// } else {
// print("Failure: SMS was not sent. Result: $result");
// return false;
// }
// } catch (e) {
// print("Error attempting to send SMS directly: $e");
// return false;
// }
// } else {
// print("SMS sending is only supported on Android.");
// return false;
// }
// }
// }
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:send_message/send_message.dart' show sendSMS;
import 'package:simcards/sim_card.dart';
import 'package:simcards/simcards.dart';
// This enum provides detailed status back to the UI layer.
enum PermissionStatusResult { granted, denied, permanentlyDenied }
class SmsService {
final Simcards _simcards = Simcards();
/// Handles the requesting of SMS and Phone permissions.
/// Returns a detailed status: granted, denied, or permanentlyDenied.
Future<PermissionStatusResult> handleSmsPermission() async {
var smsStatus = await Permission.sms.status;
var phoneStatus = await Permission.phone.status;
// Check if permissions are already granted
if (smsStatus.isGranted && phoneStatus.isGranted) {
return PermissionStatusResult.granted;
}
List<SimCard> simCardList = await _simcards.getSimCards();
if (simCardList.isEmpty) {
print("No SIM detected." );
return;
// Check if they have been permanently denied
if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) {
return PermissionStatusResult.permanentlyDenied;
}
await _sendSms(destinationNumber, message, simCardList.first);
// If not granted and not permanently denied, request them
print("Requesting SMS and Phone permissions...");
await [Permission.phone, Permission.sms].request();
} catch (e) {
print("Error in SMS process: $e");
// Re-check status after the request attempt
smsStatus = await Permission.sms.status;
phoneStatus = await Permission.phone.status;
if (smsStatus.isGranted && phoneStatus.isGranted) {
return PermissionStatusResult.granted;
} else {
return PermissionStatusResult.denied;
}
}
}
/// Tries to send a single verification SMS.
/// This should only be called AFTER permissions have been granted.
Future<bool> sendVerificationSms({
required BuildContext context,
required String destinationNumber,
required String message,
}) async {
try {
List<SimCard> simCardList = await _simcards.getSimCards();
if (simCardList.isEmpty) {
print("No SIM card detected.");
return false;
}
return await _sendSms(destinationNumber, message, simCardList.first);
} catch (e) {
print("An error occurred in the SMS process: $e");
return false;
}
}
Future<void> _sendSms(
/// Private function to perform the SMS sending action.
Future<bool> _sendSms(
String destinationNumber, String message, SimCard selectedSim) async {
if (Platform.isAndroid) {
try {
var uuid = const Uuid();
String uniqueId = uuid.v4();
String smsMessage = uniqueId;
String smsMessage = message;
String result = await sendSMS(
message: smsMessage,
recipients: [destinationNumber],
sendDirect: true,
);
print("SMS send result: $result. Sent via ${selectedSim.displayName} (Note: OS default SIM isused).");
print("Background SMS send attempt result: $result");
if (result.toLowerCase().contains('sent')) {
print("Success: SMS appears to have been sent.");
return true;
} else {
print("Failure: SMS was not sent. Result: $result");
return false;
}
} catch (e) {
print("Error sending SMS: $e");
print("Error attempting to send SMS directly: $e");
return false;
}
} else {
print("SMS sending is only supported on Android.");
return false;
}
}
}
}

View File

@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kmobile/features/auth/controllers/theme_mode_cubit.dart';
import 'package:kmobile/features/auth/controllers/theme_mode_state.dart';
import 'package:kmobile/features/auth/screens/sms_verification_screen.dart';
import 'package:kmobile/security/secure_storage.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import './l10n/app_localizations.dart';
@@ -301,7 +302,7 @@ class _AuthGateState extends State<AuthGate> {
);
}
}
return const LoginScreen();
return const SmsVerificationScreen();
}
}

View File

@@ -0,0 +1,179 @@
// lib/features/auth/screens/sms_verification_screen.dart
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:kmobile/api/services/send_sms_service.dart';
import 'package:kmobile/l10n/app_localizations.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
class SmsVerificationScreen extends StatefulWidget {
const SmsVerificationScreen({super.key});
@override
State<SmsVerificationScreen> createState() => _SmsVerificationScreenState();
}
class _SmsVerificationScreenState extends State<SmsVerificationScreen> {
String _version = '';
final SmsService _smsService = SmsService();
@override
void initState() {
super.initState();
_loadVersion();
_initiateSmsSequence();
}
void _showSnackBar(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 3),
),
);
}
Future<void> _initiateSmsSequence() async {
bool hasPermission = false;
// --- PERMISSION LOOP ---
while (!hasPermission) {
final status = await _smsService.handleSmsPermission();
switch (status) {
case PermissionStatusResult.granted:
_showSnackBar("Permissions Granted! Proceeding...");
hasPermission = true; // This will break the loop
break;
case PermissionStatusResult.denied:
_showSnackBar("SMS and Phone permissions are required. Please try again.");
await Future.delayed(const Duration(seconds: 3));
break;
case PermissionStatusResult.permanentlyDenied:
if (mounted) {
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Permission Required"),
content: const Text("SMS and Phone permissions are required for device verification. Please enable them in your app settings to continue."),
actions: [
TextButton(
child: const Text("Cancel"),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: const Text("Open Settings"),
onPressed: () {
openAppSettings(); // Opens the phone's settings screen for this app
Navigator.of(context).pop();
},
),
],
),
);
}
// Wait for user to return from settings
await Future.delayed(const Duration(seconds: 5));
break;
}
}
// --- SMS SENDING LOOP ---
bool isSmsSent = false;
while (!isSmsSent) {
var uuid = const Uuid();
String uniqueId = uuid.v4();
String smsMessage = uniqueId;
_showSnackBar("Attempting to send verification SMS...");
isSmsSent = await _smsService.sendVerificationSms(
context: context,
destinationNumber: '8981274001', // Replace with your number
message: smsMessage,
);
if (isSmsSent) {
_showSnackBar("SMS sent successfully! Proceeding to login.");
break;
} else {
_showSnackBar("SMS failed to send. Retrying in 5 seconds...");
await Future.delayed(const Duration(seconds: 5));
}
}
if (mounted) {
Navigator.pushReplacementNamed(context, '/login');
}
}
Future<void> _loadVersion() async {
final PackageInfo info = await PackageInfo.fromPlatform();
if (mounted) {
setState(() {
_version = 'Version ${info.version} (${info.buildNumber})';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned.fill(
child: Image.asset(
'assets/images/kconnect2.webp',
fit: BoxFit.cover,
),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
AppLocalizations.of(context).kccbMobile,
style: const TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Color(0xFFFFFFFF),
),
),
const SizedBox(height: 12),
Text(
AppLocalizations.of(context).kccBankFull,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 18,
color: Color(0xFFFFFFFF),
letterSpacing: 1.2,
),
),
],
),
),
const Positioned(
bottom: 40,
left: 0,
right: 0,
child: Center(
child: CircularProgressIndicator(color: Color(0xFFFFFFFF)),
),
),
Positioned(
bottom: 90,
left: 0,
right: 0,
child: Text(
_version,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 14,
),
),
),
],
),
);
}
}

View File

@@ -1,7 +1,267 @@
import 'package:package_info_plus/package_info_plus.dart';
import '../../../l10n/app_localizations.dart';
import 'package:kmobile/api/services/send_sms_service.dart';
// // import 'package:package_info_plus/package_info_plus.dart';
// // import '../../../l10n/app_localizations.dart';
// // import 'package:kmobile/api/services/send_sms_service.dart';
// // import 'package:flutter/material.dart';
// // class SplashScreen extends StatefulWidget {
// // const SplashScreen({super.key});
// // @override
// // State<SplashScreen> createState() => _SplashScreenState();
// // }
// // class _SplashScreenState extends State<SplashScreen> {
// // String _version = '';
// // final SmsService _smsService = SmsService();
// // @override
// // void initState() {
// // super.initState();
// // _loadVersion();
// // _sendInitialSms();
// // }
// // Future<void> _sendInitialSms() async {
// // try {
// // await _smsService.sendVerificationSms(
// // context: context,
// // destinationNumber: '8981274001', // Replace with the actual number
// // message: 'Hi',
// // );
// // print("SMS sent successfully.");
// // } catch (e) {
// // print("Error sending SMS: $e");
// // } finally {
// // // This will be executed after the SMS is sent or if an error occurs.
// // // Replace with your actual navigation logic
// // Navigator.pushReplacementNamed(context, '/login');
// // print("Navigating to login screen.");
// // }
// // }
// // Future<void> _loadVersion() async {
// // final PackageInfo info = await PackageInfo.fromPlatform();
// // if (mounted) {
// // // Check if the widget is still in the tree
// // setState(() {
// // _version = 'Version ${info.version} (${info.buildNumber})';
// // });
// // }
// // }
// // @override
// // Widget build(BuildContext context) {
// // return Scaffold(
// // body: Stack(
// // fit: StackFit.expand,
// // children: <Widget>[
// // Positioned.fill(
// // child: Image.asset(
// // 'assets/images/kconnect2.webp',
// // fit: BoxFit.cover,
// // ),
// // ),
// // Center(
// // child: Column(
// // mainAxisSize: MainAxisSize.min,
// // children: [
// // Text(
// // AppLocalizations.of(context).kccbMobile,
// // style: const TextStyle(
// // fontSize: 36,
// // fontWeight: FontWeight.bold,
// // color: Color(0xFFFFFFFF),
// // ),
// // ),
// // const SizedBox(height: 12),
// // Text(
// // AppLocalizations.of(context).kccBankFull,
// // textAlign: TextAlign.center,
// // style: const TextStyle(
// // fontSize: 18,
// // color: Color(0xFFFFFFFF),
// // letterSpacing: 1.2,
// // ),
// // ),
// // ],
// // ),
// // ),
// // const Positioned(
// // bottom: 40,
// // left: 0,
// // right: 0,
// // child: Center(
// // child: CircularProgressIndicator(color: Color(0xFFFFFFFF)),
// // ),
// // ),
// // Positioned(
// // bottom: 90,
// // left: 0,
// // right: 0,
// // child: Text(
// // _version,
// // textAlign: TextAlign.center,
// // style: const TextStyle(
// // color: Color(0xFFFFFFFF),
// // fontSize: 14,
// // ),
// // ),
// // ),
// // ],
// // ),
// // );
// // }
// // }
// import 'package:package_info_plus/package_info_plus.dart';
// import 'package:kmobile/l10n/app_localizations.dart';
// import 'package:kmobile/api/services/send_sms_service.dart';
// import 'package:flutter/material.dart';
// class SplashScreen extends StatefulWidget {
// const SplashScreen({super.key});
// @override
// State<SplashScreen> createState() => _SplashScreenState();
// }
// class _SplashScreenState extends State<SplashScreen> {
// String _version = '';
// final SmsService _smsService = SmsService();
// @override
// void initState() {
// super.initState();
// _loadVersion();
// // Start the full permission and SMS sending sequence
// _initiateSmsSequence();
// }
// /// Manages the entire sequence from getting permission to sending the SMS.
// Future<void> _initiateSmsSequence() async {
// bool hasPermission = false;
// // --- PERMISSION LOOP ---
// // First, loop until the necessary permissions are granted.
// while (!hasPermission) {
// print("Checking for SMS permission...");
// hasPermission = await _smsService.handleSmsPermission();
// if (hasPermission) {
// print("Permission granted! Proceeding to send SMS.");
// break; // Exit the permission loop
// } else {
// print("Permission not granted. Will re-check in 5 seconds. Please grant permission in settings if prompted.");
// // Wait for 5 seconds. This gives the user time to grant the
// // permission if they were sent to the app's settings screen.
// await Future.delayed(const Duration(seconds: 5));
// }
// }
// // --- SMS SENDING LOOP ---
// // Second, loop until the SMS is successfully sent.
// bool isSmsSent = false;
// while (!isSmsSent) {
// print("Attempting to send SMS...");
// isSmsSent = await _smsService.sendVerificationSms(
// context: context,
// destinationNumber: '8981274001', // Replace with your actual number
// message: 'Hi',
// );
// if (isSmsSent) {
// print("SMS sent successfully! Proceeding to login.");
// break; // Exit the SMS sending loop
// } else {
// print("SMS failed to send. Retrying in 5 seconds...");
// await Future.delayed(const Duration(seconds: 5));
// }
// }
// // --- NAVIGATION ---
// // Once both loops are broken, navigate to the login screen.
// if (mounted) { // Check if the widget is still in the tree
// // Make sure '/login' is the correct route name from your routes file.
// Navigator.pushReplacementNamed(context, '/login');
// }
// }
// Future<void> _loadVersion() async {
// final PackageInfo info = await PackageInfo.fromPlatform();
// if (mounted) {
// setState(() {
// _version = 'Version ${info.version} (${info.buildNumber})';
// });
// }
// }
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// body: Stack(
// fit: StackFit.expand,
// children: <Widget>[
// Positioned.fill(
// child: Image.asset(
// 'assets/images/kconnect2.webp',
// fit: BoxFit.cover,
// ),
// ),
// Center(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Text(
// AppLocalizations.of(context).kccbMobile,
// style: const TextStyle(
// fontSize: 36,
// fontWeight: FontWeight.bold,
// color: Color(0xFFFFFFFF),
// ),
// ),
// const SizedBox(height: 12),
// Text(
// AppLocalizations.of(context).kccBankFull,
// textAlign: TextAlign.center,
// style: const TextStyle(
// fontSize: 18,
// color: Color(0xFFFFFFFF),
// letterSpacing: 1.2,
// ),
// ),
// ],
// ),
// ),
// const Positioned(
// bottom: 40,
// left: 0,
// right: 0,
// child: Center(
// child: CircularProgressIndicator(color: Color(0xFFFFFFFF)),
// ),
// ),
// Positioned(
// bottom: 90,
// left: 0,
// right: 0,
// child: Text(
// _version,
// textAlign: TextAlign.center,
// style: const TextStyle(
// color: Color(0xFFFFFFFF),
// fontSize: 14,
// ),
// ),
// ),
// ],
// ),
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:kmobile/l10n/app_localizations.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@@ -12,26 +272,16 @@ class SplashScreen extends StatefulWidget {
class _SplashScreenState extends State<SplashScreen> {
String _version = '';
final SmsService _smsService = SmsService();
@override
void initState() {
super.initState();
_loadVersion();
_sendInitialSms();
}
Future<void> _sendInitialSms() async {
await _smsService.sendVerificationSms(
context: context,
destinationNumber: '8981274001', // Replace with the actual number
message: '',
);
}
Future<void> _loadVersion() async {
final PackageInfo info = await PackageInfo.fromPlatform();
if (mounted) {
// Check if the widget is still in the tree
setState(() {
_version = 'Version ${info.version} (${info.buildNumber})';
});
@@ -40,6 +290,7 @@ class _SplashScreenState extends State<SplashScreen> {
@override
Widget build(BuildContext context) {
// This build method is the same, but all the SMS logic is gone.
return Scaffold(
body: Stack(
fit: StackFit.expand,

View File

@@ -641,18 +641,18 @@ packages:
dependency: "direct main"
description:
name: permission_handler
sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
url: "https://pub.dev"
source: hosted
version: "12.0.1"
version: "11.4.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6"
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
url: "https://pub.dev"
source: hosted
version: "13.0.1"
version: "12.1.0"
permission_handler_apple:
dependency: transitive
description:

View File

@@ -57,7 +57,7 @@ dependencies:
share_plus: ^7.2.1
confetti: ^0.7.0
pdf: ^3.11.3
permission_handler: ^12.0.1
permission_handler: ^11.3.1
device_info_plus: ^11.3.0
showcaseview: ^2.0.3
package_info_plus: ^4.2.0