|
|
|
@@ -1,26 +1,25 @@
|
|
|
|
|
import 'dart:async';
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
import 'package:tripz_rider/services/geofencing_service.dart';
|
|
|
|
|
import 'package:siro_rider/services/geofencing_service.dart';
|
|
|
|
|
|
|
|
|
|
import 'package:geolocator/geolocator.dart';
|
|
|
|
|
import 'package:tripz_rider/constant/api_key.dart';
|
|
|
|
|
import 'package:tripz_rider/controller/firebase/firbase_messge.dart';
|
|
|
|
|
import 'package:tripz_rider/views/auth/otp_page.dart';
|
|
|
|
|
import 'package:tripz_rider/views/widgets/error_snakbar.dart';
|
|
|
|
|
import 'package:siro_rider/constant/api_key.dart';
|
|
|
|
|
import 'package:siro_rider/controller/firebase/firbase_messge.dart';
|
|
|
|
|
import 'package:siro_rider/views/auth/otp_page.dart';
|
|
|
|
|
import 'package:siro_rider/views/widgets/error_snakbar.dart';
|
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
|
|
|
|
|
|
import 'package:tripz_rider/constant/info.dart';
|
|
|
|
|
import 'package:tripz_rider/controller/functions/add_error.dart';
|
|
|
|
|
import 'package:tripz_rider/views/auth/login_page.dart';
|
|
|
|
|
import 'package:siro_rider/constant/info.dart';
|
|
|
|
|
import 'package:siro_rider/controller/functions/add_error.dart';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
import 'package:tripz_rider/constant/box_name.dart';
|
|
|
|
|
import 'package:tripz_rider/constant/links.dart';
|
|
|
|
|
import 'package:tripz_rider/controller/functions/crud.dart';
|
|
|
|
|
import 'package:tripz_rider/main.dart';
|
|
|
|
|
import 'package:tripz_rider/views/home/map_page_passenger.dart';
|
|
|
|
|
import 'package:siro_rider/constant/box_name.dart';
|
|
|
|
|
import 'package:siro_rider/constant/links.dart';
|
|
|
|
|
import 'package:siro_rider/controller/functions/crud.dart';
|
|
|
|
|
import 'package:siro_rider/main.dart';
|
|
|
|
|
import 'package:siro_rider/views/home/map_page_passenger.dart';
|
|
|
|
|
|
|
|
|
|
import 'package:location/location.dart' as loc;
|
|
|
|
|
|
|
|
|
@@ -82,26 +81,55 @@ class LoginController extends GetxController {
|
|
|
|
|
// • firstTimeLoadKey != false ← أول مرة يفتح التطبيق → loginFirstTime
|
|
|
|
|
// • firstTimeLoadKey == false ← مستخدم موجود → loginJwtRider
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
Future<void> getJWT({bool force = false}) async {
|
|
|
|
|
// إذا كان التوكن الحالي لا يزال صالحاً، لا داعي لطلب واحد جديد
|
|
|
|
|
static Future<bool>? _jwtFuture;
|
|
|
|
|
static DateTime _jwtCooldownUntil = DateTime(2000);
|
|
|
|
|
static int _jwtFailures = 0;
|
|
|
|
|
|
|
|
|
|
static Duration get jwtCooldownRemaining {
|
|
|
|
|
final d = _jwtCooldownUntil.difference(DateTime.now());
|
|
|
|
|
return d.isNegative ? Duration.zero : d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<bool> getJWT({bool force = false}) async {
|
|
|
|
|
if (_jwtFuture != null) {
|
|
|
|
|
Log.print('⏳ getJWT: تجديد قيد التنفيذ — إعادة استخدام نفس الـ future.');
|
|
|
|
|
return _jwtFuture!;
|
|
|
|
|
}
|
|
|
|
|
_jwtFuture = _getJwtInternal(force: force).catchError((e) {
|
|
|
|
|
return _onJwtFailure('exception: $e');
|
|
|
|
|
});
|
|
|
|
|
try {
|
|
|
|
|
return await _jwtFuture!;
|
|
|
|
|
} finally {
|
|
|
|
|
_jwtFuture = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<bool> _getJwtInternal({bool force = false}) async {
|
|
|
|
|
if (!force && isTokenValid()) {
|
|
|
|
|
Log.print("JWT is still valid. Skipping request.");
|
|
|
|
|
return;
|
|
|
|
|
_jwtFailures = 0;
|
|
|
|
|
_jwtCooldownUntil = DateTime(2000);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DateTime.now().isBefore(_jwtCooldownUntil)) {
|
|
|
|
|
Log.print(
|
|
|
|
|
'🛑 getJWT: بـ cooldown لمدة ${jwtCooldownRemaining.inSeconds}ث — تخطّي التجديد.');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
dev = Platform.isAndroid ? 'android' : 'ios';
|
|
|
|
|
|
|
|
|
|
// تأكد إن البصمة محدّثة قبل أي طلب
|
|
|
|
|
await DeviceHelper.getDeviceFingerprint();
|
|
|
|
|
final String fp = box.read(BoxName.deviceFpEncrypted) ?? '';
|
|
|
|
|
|
|
|
|
|
final passengerId = box.read(BoxName.passengerID);
|
|
|
|
|
final isRegistering = passengerId == null || passengerId.toString().isEmpty;
|
|
|
|
|
|
|
|
|
|
if (box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
|
|
|
|
|
// ── أول تسجيل ─────────────────────────────────────────
|
|
|
|
|
// نرسل البصمة المشفرة مع باقي البيانات
|
|
|
|
|
// السيرفر سيعمل hash لها ويخزنها في JWT payload
|
|
|
|
|
if (isRegistering && box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
|
|
|
|
|
var payload = {
|
|
|
|
|
'id': box.read(BoxName.passengerID) ?? AK.newId,
|
|
|
|
|
'id': passengerId ?? AK.newId,
|
|
|
|
|
'password': AK.passnpassenger,
|
|
|
|
|
'aud': '${AK.allowed}$dev',
|
|
|
|
|
'fingerPrint': fp,
|
|
|
|
@@ -110,12 +138,14 @@ class LoginController extends GetxController {
|
|
|
|
|
var response = await http.post(
|
|
|
|
|
Uri.parse(AppLink.loginFirstTime),
|
|
|
|
|
body: payload,
|
|
|
|
|
);
|
|
|
|
|
Log.print('AppLink.loginFirstTime: ${AppLink.loginFirstTime}');
|
|
|
|
|
|
|
|
|
|
Log.print('payload: $payload');
|
|
|
|
|
Log.print('response code: ${response.statusCode}');
|
|
|
|
|
Log.print('response body: ${response.body}');
|
|
|
|
|
).timeout(const Duration(seconds: 30));
|
|
|
|
|
|
|
|
|
|
if (response.statusCode == 429) {
|
|
|
|
|
final retryAfter = int.tryParse(response.headers['retry-after'] ?? '') ?? 60;
|
|
|
|
|
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: retryAfter));
|
|
|
|
|
Log.print('🛑 getJWT(firstTime): 429 — cooldown ${retryAfter}s');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (response.statusCode == 200) {
|
|
|
|
|
final decoded = jsonDecode(response.body);
|
|
|
|
@@ -126,18 +156,20 @@ class LoginController extends GetxController {
|
|
|
|
|
: decoded['jwt']);
|
|
|
|
|
|
|
|
|
|
if (jwt != null) {
|
|
|
|
|
// نشفر الـ JWT بالتشفير الثلاثي قبل التخزين في GetStorage
|
|
|
|
|
box.write(BoxName.jwt, c(jwt));
|
|
|
|
|
storage.write(key: BoxName.jwt, value: c(jwt));
|
|
|
|
|
await storage.write(key: BoxName.jwt, value: jwt);
|
|
|
|
|
await EncryptionHelper.initialize();
|
|
|
|
|
return _onJwtSuccess();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await EncryptionHelper.initialize();
|
|
|
|
|
return _onJwtFailure('firstTime: لا يوجد jwt بالرد');
|
|
|
|
|
}
|
|
|
|
|
return _onJwtFailure('firstTime: HTTP ${response.statusCode}');
|
|
|
|
|
} else {
|
|
|
|
|
// ── مستخدم موجود: تجديد التوكن
|
|
|
|
|
if (isRegistering) {
|
|
|
|
|
return _onJwtFailure('renew: لا يوجد passengerID');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var payload = {
|
|
|
|
|
'id': box.read(BoxName.passengerID),
|
|
|
|
|
'id': passengerId,
|
|
|
|
|
'fingerPrint': fp,
|
|
|
|
|
'aud': '${AK.allowed}$dev',
|
|
|
|
|
};
|
|
|
|
@@ -145,11 +177,15 @@ class LoginController extends GetxController {
|
|
|
|
|
var response = await http.post(
|
|
|
|
|
Uri.parse(AppLink.loginJwtRider),
|
|
|
|
|
body: payload,
|
|
|
|
|
);
|
|
|
|
|
Log.print('AppLink.loginJwtRider: ${AppLink.loginJwtRider}');
|
|
|
|
|
).timeout(const Duration(seconds: 30));
|
|
|
|
|
|
|
|
|
|
if (response.statusCode == 429) {
|
|
|
|
|
final retryAfter = int.tryParse(response.headers['retry-after'] ?? '') ?? 60;
|
|
|
|
|
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: retryAfter));
|
|
|
|
|
Log.print('🛑 getJWT: 429 — cooldown ${retryAfter}ث');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.print('payload: $payload');
|
|
|
|
|
Log.print('response: ${response.body}');
|
|
|
|
|
if (response.statusCode == 200) {
|
|
|
|
|
final decoded = jsonDecode(response.body);
|
|
|
|
|
final String? jwt = decoded['data'] != null
|
|
|
|
@@ -159,16 +195,33 @@ class LoginController extends GetxController {
|
|
|
|
|
: decoded['jwt']);
|
|
|
|
|
|
|
|
|
|
if (jwt != null) {
|
|
|
|
|
box.write(BoxName.jwt, c(jwt));
|
|
|
|
|
storage.write(key: BoxName.jwt, value: c(jwt));
|
|
|
|
|
await storage.write(key: BoxName.jwt, value: jwt);
|
|
|
|
|
return _onJwtSuccess();
|
|
|
|
|
}
|
|
|
|
|
return _onJwtFailure('renew: لا يوجد jwt بالرد');
|
|
|
|
|
}
|
|
|
|
|
return _onJwtFailure('renew: HTTP ${response.statusCode}');
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Log.print('Error in getJWT: $e');
|
|
|
|
|
return _onJwtFailure('Error: $e');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _onJwtSuccess() {
|
|
|
|
|
_jwtFailures = 0;
|
|
|
|
|
_jwtCooldownUntil = DateTime(2000);
|
|
|
|
|
Log.print('✅ getJWT: تم توليد توكن جديد بنجاح.');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _onJwtFailure(String reason) {
|
|
|
|
|
_jwtFailures++;
|
|
|
|
|
final seconds = _jwtFailures >= 6 ? 60 : (1 << _jwtFailures);
|
|
|
|
|
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: seconds));
|
|
|
|
|
Log.print('❌ getJWT فشل ($reason) — محاولة #$_jwtFailures، cooldown ${seconds}ث');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
// التحقق من صلاحية التوكن يدوياً (بدون مكاتب خارجية)
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
@@ -231,9 +284,67 @@ class LoginController extends GetxController {
|
|
|
|
|
// • يرجع hmac مع الـ jwt ويخزنه في GetStorage
|
|
|
|
|
// • الـ JWT لا يُشفَّر ثلاثياً (يُستخدم مباشرة في الـ header)
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
// • يُخزَّن التوكن ويُعاد استخدامه ما دام أمامه أكثر من 10 ثوانٍ
|
|
|
|
|
// (عمره 300ث)، فلا نُسجّل دخولاً مع كل طلب محفظة.
|
|
|
|
|
static Future<String?>? _walletJwtFuture;
|
|
|
|
|
|
|
|
|
|
Future<String?> getJwtWallet() async {
|
|
|
|
|
// طلب قيد التنفيذ؟ شارك نتيجته بدل إطلاق طلب ثانٍ.
|
|
|
|
|
if (_walletJwtFuture != null) {
|
|
|
|
|
Log.print('⏳ getJwtWallet: طلب قيد التنفيذ — إعادة استخدام نفس الـ future.');
|
|
|
|
|
return _walletJwtFuture!;
|
|
|
|
|
}
|
|
|
|
|
_walletJwtFuture = _getJwtWalletInternal();
|
|
|
|
|
try {
|
|
|
|
|
return await _walletJwtFuture!;
|
|
|
|
|
} finally {
|
|
|
|
|
_walletJwtFuture = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// هل التوكن المخزَّن صالح ويخصّ الراكب الحالي؟
|
|
|
|
|
/// نتحقق من `user_id` أيضاً كي لا يُعاد استخدام توكن حساب سابق
|
|
|
|
|
/// على نفس الجهاز بعد تبديل المستخدم.
|
|
|
|
|
bool _isWalletJwtUsable(String jwt, String passengerId) {
|
|
|
|
|
try {
|
|
|
|
|
final parts = jwt.split('.');
|
|
|
|
|
if (parts.length != 3) return false;
|
|
|
|
|
String payload = parts[1];
|
|
|
|
|
while (payload.length % 4 != 0) {
|
|
|
|
|
payload += '=';
|
|
|
|
|
}
|
|
|
|
|
final decoded = jsonDecode(utf8.decode(base64Url.decode(payload)));
|
|
|
|
|
|
|
|
|
|
if ((decoded['user_id'] ?? '').toString() != passengerId) return false;
|
|
|
|
|
|
|
|
|
|
final exp = decoded['exp'];
|
|
|
|
|
if (exp == null) return false;
|
|
|
|
|
// هامش 10 ثوانٍ حتى لا ينتهي التوكن أثناء الطلب نفسه
|
|
|
|
|
return DateTime.now().millisecondsSinceEpoch < (exp * 1000 - 10000);
|
|
|
|
|
} catch (_) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<String?> _getJwtWalletInternal() async {
|
|
|
|
|
dev = Platform.isAndroid ? 'android' : 'ios';
|
|
|
|
|
|
|
|
|
|
final String passengerId = box.read(BoxName.passengerID)?.toString() ?? '';
|
|
|
|
|
|
|
|
|
|
// ── إعادة استخدام التوكن المخزَّن إن كان صالحاً ────────────────
|
|
|
|
|
final String cachedJwt = box.read(BoxName.walletJwt)?.toString() ?? '';
|
|
|
|
|
final String cachedHmac = box.read(BoxName.hmac)?.toString() ?? '';
|
|
|
|
|
if (cachedJwt.isNotEmpty &&
|
|
|
|
|
cachedHmac.isNotEmpty &&
|
|
|
|
|
passengerId.isNotEmpty &&
|
|
|
|
|
_isWalletJwtUsable(cachedJwt, passengerId)) {
|
|
|
|
|
Log.print('🔑 توكن محفظة صالح في التخزين — تخطّي طلب السيرفر.');
|
|
|
|
|
return cachedJwt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// نعيد حساب البصمة أولاً كي لا نرسل قيمة GCM قديمة عالقة في التخزين
|
|
|
|
|
// من نسخة سابقة من التطبيق (مثل getJWT تماماً).
|
|
|
|
|
await DeviceHelper.getDeviceFingerprint();
|
|
|
|
|
final String fp = box.read(BoxName.deviceFpEncrypted) ?? '';
|
|
|
|
|
|
|
|
|
|
var payload = {
|
|
|
|
@@ -267,6 +378,11 @@ class LoginController extends GetxController {
|
|
|
|
|
box.write(BoxName.hmac, hmac);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// نخزّن التوكن ليُعاد استخدامه حتى قرب انتهائه بدل طلب جديد كل مرة
|
|
|
|
|
if (jwt != null) {
|
|
|
|
|
box.write(BoxName.walletJwt, jwt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return jwt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -362,39 +478,39 @@ class LoginController extends GetxController {
|
|
|
|
|
force: true); // Fetch access token after clearing firstTimeLoadKey
|
|
|
|
|
|
|
|
|
|
// ── 5. المقارنة: FCM token + fingerprint ──────────────────────
|
|
|
|
|
if (email != '962798583052@tripzapp.com') {
|
|
|
|
|
if (serverFCM == null &&
|
|
|
|
|
tokenResp != null &&
|
|
|
|
|
tokenResp != 'failure' &&
|
|
|
|
|
tokenResp != 'error' &&
|
|
|
|
|
tokenResp != 'token_expired') {
|
|
|
|
|
final tokenJson =
|
|
|
|
|
tokenResp is String ? jsonDecode(tokenResp) : tokenResp;
|
|
|
|
|
final serverData = tokenJson['data'] ?? tokenJson['message'];
|
|
|
|
|
if (serverData is Map) {
|
|
|
|
|
serverFCM = serverData['token']?.toString() ?? '';
|
|
|
|
|
serverFP = serverData['fingerPrint']?.toString() ?? '';
|
|
|
|
|
}
|
|
|
|
|
// ملاحظة: كان هنا استثناء لحساب اختبار بعينه يتخطى الفحص بالكامل.
|
|
|
|
|
// حُذف — لا استثناءات على التحقق من تغيّر الجهاز.
|
|
|
|
|
if (serverFCM == null &&
|
|
|
|
|
tokenResp != null &&
|
|
|
|
|
tokenResp != 'failure' &&
|
|
|
|
|
tokenResp != 'error' &&
|
|
|
|
|
tokenResp != 'token_expired') {
|
|
|
|
|
final tokenJson =
|
|
|
|
|
tokenResp is String ? jsonDecode(tokenResp) : tokenResp;
|
|
|
|
|
final serverData = tokenJson['data'] ?? tokenJson['message'];
|
|
|
|
|
if (serverData is Map) {
|
|
|
|
|
serverFCM = serverData['token']?.toString() ?? '';
|
|
|
|
|
serverFP = serverData['fingerPrint']?.toString() ?? '';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (serverFCM != null && serverFCM.isNotEmpty) {
|
|
|
|
|
final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();
|
|
|
|
|
if (serverFCM != null && serverFCM.isNotEmpty) {
|
|
|
|
|
final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();
|
|
|
|
|
|
|
|
|
|
// ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
|
|
|
|
|
final fcmChanged = serverFCM != localFCM;
|
|
|
|
|
final fpChanged =
|
|
|
|
|
serverFP != null && serverFP.isNotEmpty && serverFP != localFP;
|
|
|
|
|
// ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
|
|
|
|
|
final fcmChanged = serverFCM != localFCM;
|
|
|
|
|
final fpChanged =
|
|
|
|
|
serverFP != null && serverFP.isNotEmpty && serverFP != localFP;
|
|
|
|
|
|
|
|
|
|
if (fcmChanged || fpChanged) {
|
|
|
|
|
mySnackbarInfo('Device Change Detected'.tr);
|
|
|
|
|
await Get.to(() => OtpVerificationPage(
|
|
|
|
|
phone: data['phone'].toString(),
|
|
|
|
|
deviceToken: localFP,
|
|
|
|
|
token: tokenResp ?? '',
|
|
|
|
|
ptoken: serverFCM ?? '', // نمرر FCM القديم للـ OTP controller
|
|
|
|
|
));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (fcmChanged || fpChanged) {
|
|
|
|
|
mySnackbarInfo('Device Change Detected'.tr);
|
|
|
|
|
await Get.to(() => OtpVerificationPage(
|
|
|
|
|
phone: data['phone'].toString(),
|
|
|
|
|
deviceToken: localFP,
|
|
|
|
|
token: tokenResp ?? '',
|
|
|
|
|
ptoken: serverFCM ?? '', // نمرر FCM القديم للـ OTP controller
|
|
|
|
|
));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -482,7 +598,7 @@ class LoginController extends GetxController {
|
|
|
|
|
'aud': '${AK.allowed}${Platform.isAndroid ? 'android' : 'ios'}',
|
|
|
|
|
};
|
|
|
|
|
Log.print(
|
|
|
|
|
"Tester Login Payload: email=${payload['email']}, password=${payload['password']}, aud=${payload['aud']}");
|
|
|
|
|
"Tester Login Payload: email=${payload['email']}, aud=${payload['aud']}");
|
|
|
|
|
|
|
|
|
|
var response = await http.post(
|
|
|
|
|
Uri.parse(AppLink.loginUsingCredentialsWithoutGooglePassenger),
|
|
|
|
@@ -525,19 +641,27 @@ class LoginController extends GetxController {
|
|
|
|
|
Get.offAll(() => const MapPagePassenger());
|
|
|
|
|
} else {
|
|
|
|
|
Log.print(
|
|
|
|
|
"Tester Login Failed due to condition mismatch: status=${jsonDecoeded['status']}, verified=${jsonDecoeded['data']?[0]?['verified']}");
|
|
|
|
|
Get.offAll(() => LoginPage());
|
|
|
|
|
"Tester Login Condition mismatch: status=${jsonDecoeded['status']}, verified=${jsonDecoeded['data']?[0]?['verified']}");
|
|
|
|
|
mySnackbarError(
|
|
|
|
|
(jsonDecoeded['message'] ?? 'Login failed').toString().tr);
|
|
|
|
|
isloading = false;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
} else if (response.statusCode == 429) {
|
|
|
|
|
Log.print("Tester Login rate limited: ${response.body}");
|
|
|
|
|
mySnackbarError('Too many attempts. Please wait a minute.'.tr);
|
|
|
|
|
isloading = false;
|
|
|
|
|
update();
|
|
|
|
|
} else {
|
|
|
|
|
Log.print(
|
|
|
|
|
"Tester Login Failed with status code: ${response.statusCode}, body: ${response.body}");
|
|
|
|
|
"Tester Login HTTP error: ${response.statusCode}, body: ${response.body}");
|
|
|
|
|
mySnackbarError('Server error'.tr);
|
|
|
|
|
isloading = false;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Log.print("Tester Login Error: $e");
|
|
|
|
|
Log.print("Tester Login Exception: $e");
|
|
|
|
|
mySnackbarError('Network error'.tr);
|
|
|
|
|
isloading = false;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
@@ -594,7 +718,7 @@ class LoginController extends GetxController {
|
|
|
|
|
|
|
|
|
|
// Initialize geofencing now that we have permission
|
|
|
|
|
if (Platform.isAndroid || Platform.isIOS) {
|
|
|
|
|
await TripzGeofencingService.initAndStart();
|
|
|
|
|
await SiroGeofencingService.initAndStart();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (permissionGranted.toString() == 'PermissionStatus.granted' ||
|
|
|
|
|