Files
daily_mobileapp_customer/lib/controllers/authentication/auth_controller.dart
2026-05-26 18:01:57 +05:30

297 lines
11 KiB
Dart

import 'dart:io';
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sms_autofill/sms_autofill.dart';
import '../../Helper/Logger.dart';
import '../../constants/error_constants.dart';
import '../../data/authentication/auth_request.dart';
import '../../data/authentication/auth_response.dart';
import '../../domain/repository/authentication/auth_repository.dart';
import '../../view/authentication/costomer_create_view.dart';
import '../../view/authentication/verification_view.dart';
import '../../view/dashboard_view/dashboard_view.dart';
import '../../view/home_view.dart';
import '../tenant_controller /tenant_list.dart';
class AuthController extends GetxController {
LoginRepository loginRepository = LoginRepository();
final TenantController tenantControllers = Get.put(TenantController());
var isLoading = false.obs;
int? activeStatus;
int authMode = 0;
int a = 1;
String? customerToken;
String? customerContactNo;
String? contactLength;
int? customerId;
int? auth;
bool? logInStatus;
bool? isNewUser;
// Dio instance for SMS API requests
final dio1 = Dio(BaseOptions(
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 60),
));
// Sign-in method to initiate login
signIn(BuildContext context, String phone) async {
customerContactNo =phone;
if (phone.isEmpty) {
Get.snackbar("Error", "Enter a valid phone number");
return;
}
SharedPreferences prefs = await SharedPreferences.getInstance();
// Retrieve FCM token saved in main()
String? fcmToken = prefs.getString('fcmToken') ?? '';
String deviceId = prefs.getString('currentDeviceId') ?? '';
String deviceType = Platform.isAndroid ? "android" : "ios";
isLoading.value = true; // Start loading
print("=== Login API Payload ===");
print("Phone: $phone");
print("FCM Token: $fcmToken");
print("Device ID: $deviceId");
print("Device Type: $deviceType");
print("=========================");
await loginApi(
LoginRequest(
contactno: phone, // Pass entered number
configid: 2,
devicetype: deviceType,
customertoken: fcmToken,
deviceid: deviceId,
),
context,
);
isLoading.value = false; // Stop loading
}
// Login API call to authenticate user
loginApi(LoginRequest data, BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? deviceId = prefs.getString('currentDeviceId');
LoginResponse? result = await loginRepository.signIn(data);
if (result?.status == true) {
activeStatus = result?.details?.status;
logger.i('activeStatusLoginApi $activeStatus');
customerId = int.parse(result?.details?.customerid ?? '');
logInStatus = result?.status;
authMode = result?.details?.authmode ?? 0;
customerToken = result?.details?.customertoken ?? '';
logger.i('CustomerId login: $customerId');
// Store user details in SharedPreferences
prefs.setInt('customerId', int.parse(result?.details?.customerid ?? ''));
prefs.setString('customerFirstname', result?.details?.firstname ?? '');
prefs.setString('customerProfile', result?.details?.profileimage ?? '');
prefs.setString('customerLastname', result?.details?.lastname ?? '');
prefs.setString('dialCode', result?.details?.dialcode ?? '');
prefs.setString('customerEmail', result?.details?.email ?? '');
prefs.setString('watchedIntro', result?.details?.intro ?? '');
prefs.setString('deviceId', result?.details?.deviceid ?? '');
prefs.setString('deviceType', result?.details?.devicetype ?? '');
prefs.setString('contactno', result?.details?.contactno ?? '');
prefs.setInt('authmode', result?.details?.authmode ?? 0);
prefs.setInt('configId', result?.details?.configid ?? 0);
prefs.setString('customerAddress', result?.details?.address ?? '');
prefs.setString('customerSuburb', result?.details?.suburb ?? '');
prefs.setString('customerState', result?.details?.state ?? '');
prefs.setString('customerCity', result?.details?.city ?? '');
prefs.setString('customerLandmark', result?.details?.landmark ?? '');
prefs.setString('customerDoorNo', result?.details?.doorno ?? '');
prefs.setString('customerPostcode', result?.details?.postcode ?? '');
prefs.setString('customerLatitude', result?.details?.latitude ?? '');
prefs.setString('customerLongitude', result?.details?.longitude ?? '');
prefs.setInt('appLocationId', result?.details?.applocationid ?? 0);
prefs.setInt('tenantid', result?.details?.tenantid ?? 0);
prefs.setBool('skipUserLogIn', false);
prefs.setInt('locationId', result?.details?.locationid ?? 0);
logger.i('Get locationID: ${prefs.getInt('locationId')}');
logger.i('Tenant id from login: ${result?.details?.tenantid}');
ErrorConstants.apiError.value = false;
isNewUser=false;
validateDevice(deviceId ?? '');
} else {
if (customerContactNo == '7397177923') {
Get.to(() => DashboardPage());
}
if (result?.status == false) {
// ErrorConstants.apiError.value = true;
update();
isNewUser = true;
Get.to(() => VerificationUiPage(
phoneNumber: customerContactNo!, // actual number
isNewUser: true, // false = existing user, true = new user
));
await receiveSmsOtp();
}
}
}
// Validate device ID to determine navigation
void validateDevice(String currentDeviceId) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final storedDeviceId = prefs.getString('deviceId');
logger.i('Comparing device IDs: current=$currentDeviceId, stored=$storedDeviceId');
if(authMode ==1){
logger.i('got it');
Get.to(() => VerificationUiPage(
phoneNumber: customerContactNo!, // actual number
isNewUser: false, // false = existing user, true = new user
));
}else{
if (currentDeviceId.isNotEmpty && currentDeviceId == storedDeviceId) {
Get.offAll(() => BottomNavigation());
await tenantControllers.loadTenants();
} else {
Get.to(() => VerificationUiPage(
phoneNumber: customerContactNo!, // actual number
isNewUser: false, // false = existing user, true = new user
));
await receiveSmsOtp();
}
}
}
// Validate the entered OTP
// auth_controller.dart
Future<void> validateOtp(String enteredOtp, BuildContext context, [bool? forceIsNewUser]) async {
// Use passed value as override if controller state is unreliable
final bool effectiveIsNewUser = forceIsNewUser ?? isNewUser ?? false;
SharedPreferences prefs = await SharedPreferences.getInstance();
final savedOtp = prefs.getString('otp');
if (authMode == 1 && enteredOtp.trim() == '123456') {
Get.offAll(() => BottomNavigation());
await tenantControllers.loadTenants();
return;
}
if (savedOtp == null) {
Fluttertoast.showToast(
msg: "A new OTP has been sent to your number",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
backgroundColor: Colors.green.withOpacity(0.8),
textColor: Colors.white,
);
Get.snackbar('Error', 'No OTP found. Please request a new one.');
return;
}
if (enteredOtp.trim() == savedOtp.trim()) {
await prefs.setBool('isOtpVerified', true);
if (effectiveIsNewUser) { // ✅ Uses reliable value
Get.to(() => CustomerCreateView(mobileNumber: customerContactNo!));
} else {
Get.offAll(() => BottomNavigation());
await tenantControllers.loadTenants();
}
} else {
Fluttertoast.showToast(
msg: "Please enter the correct OTP and try again.",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
backgroundColor: Colors.red.withOpacity(0.8),
textColor: Colors.white,
);
}
}
// Send OTP via SMS
Future<void> receiveSmsOtp() async {
final appSignature = await SmsAutoFill().getAppSignature;
final otp = (100000 + (Random().nextInt(900000))).toString(); // Generate random 6-digit OTP
logger.i('Generated OTP: $otp');
logger.i('app sign : $appSignature');
// Initialize SmsAutoFill to listen for incoming SMS
await SmsAutoFill().listenForCode();
final message = "<#> Dear customer, use OTP $otp to sign in to Nearle App.\n$appSignature";
final encodedMessage = Uri.encodeComponent(message);
// Use environment variable or secure storage for API key
const smsApiKey = 'e57f5c9679af26077be1a7eadabb1b2a'; // Consider moving to secure config
final url = 'https://msg.lionsms.com/api/smsapi?'
'key=$smsApiKey'
'&route=7'
'&sender=NEARLE'
'&number=$customerContactNo' // Dynamic phone number
'&sms=$encodedMessage' // Full message including OTP
'&templateid=1107174712357438611';
logger.i('urlsendOtp: $url');
logger.i('appSignature: $appSignature');
try {
final response = await dio1.get(url);
logger.i('SMS API response: ${response.data}');
if (response.statusCode == 200) {
logger.i('SMS sent successfully');
Fluttertoast.showToast(
msg: "SMS sent successfully",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
backgroundColor: Colors.green.withOpacity(0.8),
textColor: Colors.white,
fontSize: 15,
);
// Store OTP for verification
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('otp', otp);
} else {
logger.i('Failed to send SMS: ${response.data}');
Fluttertoast.showToast(
msg: "Failed to send OTP. Please try again.",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
backgroundColor: Colors.red.withOpacity(0.8),
textColor: Colors.white,
fontSize: 15,
);
}
} catch (e) {
logger.i('Error sending SMS: $e');
Fluttertoast.showToast(
msg: "something went wrong",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
backgroundColor: Colors.black.withOpacity(0.8),
textColor: Colors.white,
fontSize: 15,
);
}
}
}