first commit
This commit is contained in:
79
lib/constant/api_key.dart
Normal file
79
lib/constant/api_key.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
||||
|
||||
import '../env/env.dart';
|
||||
import 'char_map.dart';
|
||||
|
||||
class AK {
|
||||
static final String allowed = Env.allowed;
|
||||
static final String passnpassenger = X
|
||||
.r(X.r(X.r(Env.passnpassenger, cn), cC), cs)
|
||||
.toString()
|
||||
.split(Env.addd)[0];
|
||||
static final String newId = Env.newId;
|
||||
static final String publishableKey =
|
||||
X.r(X.r(X.r(Env.stripePublishableKe, cn), cC), cs);
|
||||
static final String secretKey = X.r(X.r(X.r(Env.secretKey, cn), cC), cs);
|
||||
static final String basicAuthCredentials =
|
||||
X.r(X.r(X.r(Env.basicAuthCredentials, cn), cC), cs);
|
||||
static final String accountSIDTwillo =
|
||||
X.r(X.r(X.r(Env.accountSIDTwillo, cn), cC), cs);
|
||||
static final String serverAPI = X.r(X.r(X.r(Env.serverAPI, cn), cC), cs);
|
||||
static final String mapAPIKEY = X.r(X.r(X.r(Env.mapAPIKEY, cn), cC), cs);
|
||||
static final String twilloRecoveryCode =
|
||||
X.r(X.r(X.r(Env.twilloRecoveryCode, cn), cC), cs);
|
||||
static final String authTokenTwillo =
|
||||
X.r(X.r(X.r(Env.authTokenTwillo, cn), cC), cs);
|
||||
static final String chatGPTkey = X.r(X.r(X.r(Env.chatGPTkey, cn), cC), cs);
|
||||
static final String transactionCloude =
|
||||
X.r(X.r(X.r(Env.transactionCloude, cn), cC), cs);
|
||||
static final String visionApi = X.r(X.r(X.r(Env.visionApi, cn), cC), cs);
|
||||
static final String chatGPTkeySefer =
|
||||
X.r(X.r(X.r(Env.chatGPTkeySefer, cn), cC), cs);
|
||||
static final String chatGPTkeySeferNew =
|
||||
X.r(X.r(X.r(Env.chatGPTkeySeferNew, cn), cC), cs);
|
||||
static final String serverPHP = Env.serverPHP;
|
||||
static final String llamaKey = X.r(X.r(X.r(Env.llamaKey, cn), cC), cs);
|
||||
static final String cohere = X.r(X.r(X.r(Env.cohere, cn), cC), cs);
|
||||
static final String claudeAiAPI = X.r(X.r(X.r(Env.claudeAiAPI, cn), cC), cs);
|
||||
static final String payPalClientId =
|
||||
X.r(X.r(X.r(Env.payPalClientId, cn), cC), cs);
|
||||
static final String payPalSecret =
|
||||
X.r(X.r(X.r(Env.payPalSecret, cn), cC), cs);
|
||||
static final String geminiApi = X.r(X.r(X.r(Env.geminiApi, cn), cC), cs);
|
||||
static final String agoraAppId = X.r(X.r(X.r(Env.agoraAppId, cn), cC), cs);
|
||||
static final String agoraAppCertificate =
|
||||
X.r(X.r(X.r(Env.agoraAppCertificate, cn), cC), cs);
|
||||
static final String payPalClientIdLive =
|
||||
X.r(X.r(X.r(Env.payPalClientIdLive, cn), cC), cs);
|
||||
static final String payPalSecretLive =
|
||||
X.r(X.r(X.r(Env.payPalSecretLive, cn), cC), cs);
|
||||
static final String integrationIdPayMob =
|
||||
X.r(X.r(X.r(Env.integrationIdPayMob, cn), cC), cs);
|
||||
static final String passwordPayMob =
|
||||
X.r(X.r(X.r(Env.passwordPayMob, cn), cC), cs);
|
||||
static final String usernamePayMob =
|
||||
X.r(X.r(X.r(Env.usernamePayMob, cn), cC), cs);
|
||||
static final String payMobApikey =
|
||||
X.r(X.r(X.r(Env.payMobApikey, cn), cC), cs);
|
||||
static final String integrationIdPayMobWallet =
|
||||
X.r(X.r(X.r(Env.integrationIdPayMobWallet, cn), cC), cs);
|
||||
static final String smsPasswordEgypt =
|
||||
X.r(X.r(X.r(Env.smsPasswordEgypt, cn), cC), cs);
|
||||
static final String ocpApimSubscriptionKey = Env.ocpApimSubscriptionKey;
|
||||
static final String chatGPTkeySeferNew4 =
|
||||
X.r(X.r(X.r(Env.chatGPTkeySeferNew4, cn), cC), cs);
|
||||
static final String anthropicAIkeySeferNew =
|
||||
X.r(X.r(X.r(Env.anthropicAIkeySeferNew, cn), cC), cs);
|
||||
static final String llama3Key = X.r(X.r(X.r(Env.llama3Key, cn), cC), cs);
|
||||
static final String payMobOutClientSecrret =
|
||||
X.r(X.r(X.r(Env.payMobOutClientSecrret, cn), cC), cs);
|
||||
static final String payMobOutClient_id =
|
||||
X.r(X.r(X.r(Env.payMobOutClient_id, cn), cC), cs);
|
||||
static final String payMobOutPassword =
|
||||
X.r(X.r(X.r(Env.payMobOutPassword, cn), cC), cs);
|
||||
static final String payMobOutUserName =
|
||||
X.r(X.r(X.r(Env.payMobOutUserName, cn), cC), cs);
|
||||
|
||||
///////////
|
||||
static final String keyOfApp = X.r(X.r(X.r(Env.keyOfApp, cn), cC), cs);
|
||||
}
|
||||
84
lib/constant/box_name.dart
Normal file
84
lib/constant/box_name.dart
Normal file
@@ -0,0 +1,84 @@
|
||||
class BoxName {
|
||||
static const String driverID = "driverID";
|
||||
static const String countryCode = "countryCode";
|
||||
static const String googlaMapApp = "googlaMapApp";
|
||||
|
||||
static const String lang = "lang";
|
||||
static const String carType = "carType";
|
||||
static const String carPlate = "carPlate";
|
||||
static const String statusDriverLocation = "statusDriverLocation";
|
||||
static const String password = "password";
|
||||
static const String keyOfApp = 'keyOfApp';
|
||||
static const String initializationVector = 'initializationVector';
|
||||
static const String firstTimeLoadKey = 'firstTimeLoadKey';
|
||||
static const String jwt = "jwt";
|
||||
static const String phoneVerified = "phoneVerified";
|
||||
static const String adminPhone = "adminPhone";
|
||||
static const String hmac = "hmac";
|
||||
static const String fingerPrint = "fingerPrint";
|
||||
static const String payMobApikey = "payMobApikey";
|
||||
static const String refreshToken = "refreshToken";
|
||||
static const String arrivalTime = "arrivalTime";
|
||||
static const String passwordDriver = "passwordDriver";
|
||||
static const String agreeTerms = "agreeTerms";
|
||||
static const String serverChosen = "serverChosen";
|
||||
static const String addWork = 'addWork';
|
||||
static const String addHome = 'addHome';
|
||||
static const String tipPercentage = 'tipPercentage';
|
||||
static const String accountIdStripeConnect = "accountIdStripeConnect";
|
||||
static const String faceDetectTimes = "faceDetectTimes";
|
||||
static const String sosPhonePassenger = "sosPhonePassenger";
|
||||
static const String sosPhoneDriver = "sosPhoneDriver";
|
||||
static const String passengerID = "pasengerID";
|
||||
static const String phone = "phone";
|
||||
static const String phoneDriver = "phoneDriver";
|
||||
static const String dobDriver = "dobDriver";
|
||||
static const String sexDriver = "sexDriver";
|
||||
static const String lastNameDriver = "lastNameDriver";
|
||||
static const String name = "name";
|
||||
static const String nameDriver = "nameDriver";
|
||||
static const String driverPhotoUrl = "driverPhotoUrl";
|
||||
static const String email = "email";
|
||||
static const String emailDriver = "emailDriver";
|
||||
static const String tokens = "tokens";
|
||||
static const String tokensDrivers = "tokensDrivers";
|
||||
static const String tokensPassengers = "tokensPassengers";
|
||||
static const String tokenFCM = "tokenFCM";
|
||||
static const String tokenDriver = "tokenDriver";
|
||||
static const String cardNumber = "cardNumber";
|
||||
static const String cardNumberDriver = "cardNumberDriver";
|
||||
static const String cardHolderName = "cardHolderName";
|
||||
static const String cardHolderNameDriver = "cardHolderNameDriver";
|
||||
static const String expiryDate = "expiryDate";
|
||||
static const String expiryDateDriver = "expiryDateDriver";
|
||||
static const String cvvCode = "cvvCode";
|
||||
static const String cvvCodeDriver = "cvvCodeDriver";
|
||||
static const String passengerWalletDetails = "passengerWalletDetails";
|
||||
static const String passengerWalletTotal = "passengerWalletTotal";
|
||||
static const String passengerWalletFound = "passengerWalletFound";
|
||||
static const String periods = 'periods';
|
||||
static const String onBoarding = 'onBoarding';
|
||||
static const String stripePublishableKey = 'stripe_publishableKe';
|
||||
static const String apiKeyRun = 'apiKeyRun';
|
||||
static const String serverAPI = 'serverAPI';
|
||||
static const String secretKey = 'secretKey';
|
||||
static const String basicAuthCredentials = 'basicAuthCredentials';
|
||||
static const String mapAPIKEY = 'mapAPIKEY';
|
||||
static const String twilloRecoveryCode = 'twilloRecoveryCode';
|
||||
static const String accountSIDTwillo = 'accountSIDTwillo';
|
||||
static const String authTokenTwillo = 'authTokenTwillo';
|
||||
static const String chatGPTkey = 'chatGPTkey';
|
||||
static const String chatGPTkeySefer = 'chatGPTkeySefer';
|
||||
static const String transactionCloude = 'transactionCloude';
|
||||
static const String visionApi = 'visionApi';
|
||||
static const String vin = "vin";
|
||||
static const String make = "make";
|
||||
static const String model = "model";
|
||||
static const String year = "year";
|
||||
static const String expirationDate = "expirationDate";
|
||||
static const String color = "color";
|
||||
static const String owner = "owner";
|
||||
static const String registrationDate = "registrationDate";
|
||||
static const String recentLocations = 'recentLocations';
|
||||
static const String tripData = 'tripData';
|
||||
}
|
||||
68
lib/constant/char_map.dart
Normal file
68
lib/constant/char_map.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
Map<String, String> cn = {
|
||||
"0": "3",
|
||||
"1": "7",
|
||||
"2": "1",
|
||||
"3": "9",
|
||||
"4": "0",
|
||||
"5": "5",
|
||||
"6": "2",
|
||||
"7": "6",
|
||||
"8": "4",
|
||||
"9": "8"
|
||||
};
|
||||
Map<String, String> cs = {
|
||||
"a": "q",
|
||||
"b": "x",
|
||||
"c": "f",
|
||||
"d": "y",
|
||||
"e": "j",
|
||||
"f": "u",
|
||||
"g": "k",
|
||||
"h": "w",
|
||||
"i": "o",
|
||||
"j": "e",
|
||||
"k": "g",
|
||||
"l": "r",
|
||||
"m": "n",
|
||||
"n": "b",
|
||||
"o": "i",
|
||||
"p": "v",
|
||||
"q": "a",
|
||||
"r": "l",
|
||||
"s": "z",
|
||||
"t": "c",
|
||||
"u": "h",
|
||||
"v": "p",
|
||||
"w": "t",
|
||||
"x": "d",
|
||||
"y": "s",
|
||||
"z": "m"
|
||||
};
|
||||
Map<String, String> cC = {
|
||||
"A": "Q",
|
||||
"B": "X",
|
||||
"C": "F",
|
||||
"D": "Y",
|
||||
"E": "J",
|
||||
"F": "U",
|
||||
"G": "K",
|
||||
"H": "W",
|
||||
"I": "O",
|
||||
"J": "E",
|
||||
"K": "G",
|
||||
"L": "R",
|
||||
"M": "N",
|
||||
"N": "B",
|
||||
"O": "I",
|
||||
"P": "V",
|
||||
"Q": "A",
|
||||
"R": "L",
|
||||
"S": "Z",
|
||||
"T": "C",
|
||||
"U": "H",
|
||||
"V": "P",
|
||||
"W": "T",
|
||||
"X": "D",
|
||||
"Y": "S",
|
||||
"Z": "M"
|
||||
};
|
||||
14
lib/constant/colors.dart
Normal file
14
lib/constant/colors.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppColor {
|
||||
static const Color primaryColor = Colors.black;
|
||||
static const Color secondaryColor = Colors.white;
|
||||
static const Color accentColor = Colors.grey;
|
||||
static const Color redColor = Color(0xFFEA4335); // Google Red
|
||||
static const Color greenColor = Color(0xFF34A853); // Google Green
|
||||
static const Color blueColor =
|
||||
Color.fromARGB(255, 66, 135, 246); // Google Blue
|
||||
static const Color yellowColor = Color(0xFFFBBC05); // Google Yellow
|
||||
static Color deepPurpleAccent =
|
||||
const Color.fromARGB(255, 123, 76, 254).withOpacity(0.3);
|
||||
}
|
||||
144
lib/constant/credential.dart
Normal file
144
lib/constant/credential.dart
Normal file
@@ -0,0 +1,144 @@
|
||||
import 'dart:convert';
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
import '../controller/functions/crud.dart';
|
||||
import '../main.dart';
|
||||
import 'box_name.dart';
|
||||
import 'char_map.dart';
|
||||
import 'links.dart';
|
||||
|
||||
class AC {
|
||||
gAK() async {
|
||||
if (box.read(BoxName.apiKeyRun).toString() != 'run') {
|
||||
var res = await CRUD().get(link: AppLink.getApiKey, payload: {});
|
||||
var decod = jsonDecode(res);
|
||||
print(decod);
|
||||
Map<String, dynamic> jsonData = {};
|
||||
for (var i = 0; i < decod['message'].length; i++) {
|
||||
String h = decod['message'][i]['hashed_key'].toString();
|
||||
String retrievedString = r(r(r(h, cn), cC), cs);
|
||||
|
||||
await storage.write(
|
||||
key: decod['message'][i]['name'].toString(),
|
||||
value: retrievedString.toString(),
|
||||
);
|
||||
//
|
||||
String name = decod['message'][i]['name'].toString();
|
||||
String value = decod['message'][i]['hashed_key'].toString();
|
||||
|
||||
jsonData[name] = value;
|
||||
}
|
||||
String jsonString = json.encode(jsonData);
|
||||
print(jsonString);
|
||||
box.write(BoxName.apiKeyRun, 'run');
|
||||
}
|
||||
}
|
||||
|
||||
String q(String b, String c) {
|
||||
final d = utf8.encode(c);
|
||||
final e = utf8.encode(b);
|
||||
|
||||
final f = Hmac(sha256, d);
|
||||
final g = f.convert(e);
|
||||
|
||||
final h = g.bytes;
|
||||
final i = base64Url.encode(h);
|
||||
return i;
|
||||
}
|
||||
|
||||
String j(String k, String l) {
|
||||
final m = utf8.encode(l);
|
||||
final n = base64Url.decode(k);
|
||||
|
||||
final o = Hmac(sha256, m);
|
||||
final p = o.convert(n);
|
||||
|
||||
final q = utf8.decode(p.bytes);
|
||||
return q;
|
||||
}
|
||||
|
||||
String a(String b, String c) {
|
||||
int d = b.length;
|
||||
int e = d ~/ 4;
|
||||
|
||||
List<String> f = [];
|
||||
for (int g = 0; g < d; g += e) {
|
||||
int h = g + e;
|
||||
if (h > d) {
|
||||
h = d;
|
||||
}
|
||||
String i = b.substring(g, h);
|
||||
f.add(i);
|
||||
}
|
||||
|
||||
print(f);
|
||||
Map<String, String> j = {};
|
||||
j['birinci'] = f[4];
|
||||
j['ikinci'] = f[2];
|
||||
j['üçüncü'] = c + f[1];
|
||||
j['dördüncü'] = f[0];
|
||||
j['beş'] = f[3];
|
||||
|
||||
String k = '';
|
||||
j.forEach((l, m) {
|
||||
k += m;
|
||||
});
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
Map<String, String> n(String o, String c) {
|
||||
String p = o.replaceAll(c, '');
|
||||
|
||||
Map<String, String> q = {};
|
||||
q['birinci'] = p[p.length - 5] + p[p.length - 3];
|
||||
q['ikinci'] = p[p.length - 1] + p[p.length - 15];
|
||||
q['üçüncü'] = p[p.length - 9] + p[p.length - 12];
|
||||
q['dördüncü'] = p[p.length - 11] + p[p.length - 6];
|
||||
q['beş'] = p[p.length - 2] + p[p.length - 8];
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
String c(String a, Map<String, String> b) {
|
||||
StringBuffer c = StringBuffer();
|
||||
c.write(a);
|
||||
|
||||
String d = "Bl";
|
||||
c.write(b[d] ?? d);
|
||||
|
||||
StringBuffer e = StringBuffer();
|
||||
String f = c.toString();
|
||||
|
||||
for (int g = 0; g < f.length; g++) {
|
||||
String h = f[g];
|
||||
e.write(b[h] ?? h);
|
||||
}
|
||||
|
||||
return e.toString();
|
||||
}
|
||||
|
||||
String r(String a, Map<String, String> b) {
|
||||
StringBuffer c = StringBuffer();
|
||||
String d = "Bl";
|
||||
int e = d.length;
|
||||
|
||||
for (int f = 0; f < a.length; f++) {
|
||||
String g = a[f];
|
||||
String h = b.keys.firstWhere(
|
||||
(i) => b[i] == g,
|
||||
orElse: () => g,
|
||||
);
|
||||
|
||||
c.write(h);
|
||||
}
|
||||
|
||||
String j = c.toString();
|
||||
|
||||
if (j.endsWith(d)) {
|
||||
j = j.substring(0, j.length - e);
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
}
|
||||
4471
lib/constant/info.dart
Normal file
4471
lib/constant/info.dart
Normal file
File diff suppressed because one or more lines are too long
299
lib/constant/links.dart
Normal file
299
lib/constant/links.dart
Normal file
@@ -0,0 +1,299 @@
|
||||
import '../env/env.dart';
|
||||
|
||||
class AppLink {
|
||||
static String seferPaymentServer =
|
||||
'https://walletintaleq.intaleq.xyz/v1/main';
|
||||
static final String tripzPaymentServer0 = seferPaymentServer;
|
||||
static final String tripzPaymentServer = '$seferPaymentServer/ride';
|
||||
static final String tripzAlexandriaServer = Env.seferAlexandriaServer;
|
||||
static final String tripzCairoServer = Env.seferCairoServer;
|
||||
static final String tripzGizaServer = Env.seferGizaServer;
|
||||
// static final String endPoint = box.read(BoxName.serverChosen);
|
||||
// static final String server = Env.seferCairoServer;
|
||||
|
||||
static final String server = 'https://intaleq.xyz/intaleq';
|
||||
static String loginJwtDriver = "https://intaleq.xyz/intaleq/loginAdmin.php";
|
||||
|
||||
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
|
||||
static String llama = 'https://api.llama-api.com/chat/completions';
|
||||
static String gemini =
|
||||
'https://generativelanguage.googleapis.com/v1beta3/models/text-bison-001:generateText';
|
||||
|
||||
static String test = "$server/test.php";
|
||||
static String loginWalletAdmin = "$seferPaymentServer/loginWalletAdmin.php";
|
||||
//===============firebase==========================
|
||||
static String getTokens = "$server/ride/firebase/get.php";
|
||||
static String getInvoices = "$server/Admin/adminUser/invoice_total.php";
|
||||
static String addInvoice = "$server/Admin/adminUser/add_invoice.php";
|
||||
static String getAllTokenDrivers =
|
||||
"$server/ride/firebase/getALlTokenDrivers.php";
|
||||
|
||||
static String getAllTokenPassengers =
|
||||
"$server/ride/firebase/getAllTokenPassengers.php";
|
||||
static String addTokens = "$server/ride/firebase/add.php";
|
||||
static String addTokensDriver = "$server/ride/firebase/addDriver.php";
|
||||
|
||||
//=======================Wallet===================
|
||||
static String addPaymentTokenDriver =
|
||||
"$tripzPaymentServer/driverWallet/addPaymentToken.php";
|
||||
static String addSeferWallet = "$tripzPaymentServer/seferWallet/add.php";
|
||||
static String getPaymentsDashboard =
|
||||
"$seferPaymentServer/Admin/getPaymentsDashboard.php";
|
||||
static String getSeferWallet = "$tripzPaymentServer/seferWallet/get.php";
|
||||
static String addDrivePayment = "$tripzPaymentServer/payment/add.php";
|
||||
static String updatePaymetToPaid =
|
||||
"$tripzPaymentServer/payment/updatePaymetToPaid.php";
|
||||
static String wallet = '$tripzPaymentServer/passengerWallet';
|
||||
static String walletDriver = '$tripzPaymentServer/driverWallet';
|
||||
static String getAllPassengerTransaction =
|
||||
"$wallet/getAllPassengerTransaction.php";
|
||||
static String getWalletByPassenger = "$wallet/getWalletByPassenger.php";
|
||||
static String getPassengersWallet = "$wallet/get.php";
|
||||
static String getPassengerWalletArchive =
|
||||
"$wallet/getPassengerWalletArchive.php";
|
||||
static String addPassengersWallet = "$wallet/add.php";
|
||||
static String deletePassengersWallet = "$wallet/delete.php";
|
||||
static String updatePassengersWallet = "$wallet/update.php";
|
||||
|
||||
static String getWalletByDriver = "$walletDriver/getWalletByDriver.php";
|
||||
static String getDriversWallet = "$walletDriver/get.php";
|
||||
static String addDriversWalletPoints = "$walletDriver/add.php";
|
||||
static String deleteDriversWallet = "$walletDriver/delete.php";
|
||||
static String updateDriversWallet = "$walletDriver/update.php";
|
||||
|
||||
//=======================promo===================ride.mobile-app.store/ride/promo/get.php
|
||||
static String promo = '$server/ride/promo';
|
||||
static String getPassengersPromo = "$promo/get.php";
|
||||
static String getPromoBytody = "$promo/getPromoBytody.php";
|
||||
static String addPassengersPromo = "$promo/add.php";
|
||||
static String deletePassengersPromo = "$promo/delete.php";
|
||||
static String updatePassengersPromo = "$promo/update.php";
|
||||
|
||||
////=======================cancelRide===================
|
||||
static String ride = '$server/ride';
|
||||
static String addCancelRideFromPassenger = "$server/ride/cancelRide/add.php";
|
||||
static String cancelRide = "$server/ride/cancelRide/get.php";
|
||||
//-----------------ridessss------------------
|
||||
static String addRides = "$ride/rides/add.php";
|
||||
static String getRides = "$ride/rides/get.php";
|
||||
static String getRideOrderID = "$ride/rides/getRideOrderID.php";
|
||||
static String getRideStatus = "$ride/rides/getRideStatus.php";
|
||||
static String getRideStatusBegin = "$ride/rides/getRideStatusBegin.php";
|
||||
static String getRideStatusFromStartApp =
|
||||
"$ride/rides/getRideStatusFromStartApp.php";
|
||||
static String updateRides = "$ride/rides/update.php";
|
||||
static String updateStausFromSpeed = "$ride/rides/updateStausFromSpeed.php";
|
||||
static String deleteRides = "$ride/rides/delete.php";
|
||||
|
||||
//-----------------DriverPayment------------------
|
||||
static String adddriverScam = "$ride/driver_scam/add.php";
|
||||
static String getdriverScam = "$ride/driver_scam/get.php";
|
||||
|
||||
/////////---getKazanPercent===////////////
|
||||
static String getKazanPercent = "$ride/kazan/get.php";
|
||||
static String addKazanPercent = "$ride/kazan/add.php";
|
||||
|
||||
////-----------------DriverPayment------------------
|
||||
static String addDriverpayment = "$tripzPaymentServer/payment/add.php";
|
||||
static String addDriverPaymentPoints =
|
||||
"$tripzPaymentServer/driverPayment/add.php";
|
||||
static String getDriverPaymentPoints =
|
||||
"$tripzPaymentServer/driverWallet/get.php";
|
||||
static String getDriverpaymentToday = "$tripzPaymentServer/payment/get.php";
|
||||
static String getCountRide = "$tripzPaymentServer/payment/getCountRide.php";
|
||||
static String getAllPaymentFromRide =
|
||||
"$tripzPaymentServer/payment/getAllPayment.php";
|
||||
static String getAllPaymentVisa =
|
||||
"$tripzPaymentServer/payment/getAllPaymentVisa.php";
|
||||
|
||||
//-----------------Passenger NotificationCaptain------------------
|
||||
static String addNotificationPassenger =
|
||||
"$ride/notificationPassenger/add.php";
|
||||
static String send_whatsapp_message =
|
||||
"$server/Admin/send_whatsapp_message.php";
|
||||
static String getNotificationPassenger =
|
||||
"$ride/notificationPassenger/get.php";
|
||||
static String updateNotificationPassenger =
|
||||
"$ride/notificationPassenger/update.php";
|
||||
|
||||
//-----------------Driver NotificationCaptain------------------
|
||||
static String addNotificationCaptain = "$ride/notificationCaptain/add.php";
|
||||
static String addWaitingRide = "$ride/notificationCaptain/addWaitingRide.php";
|
||||
static String getRideWaiting = "$ride/notificationCaptain/getRideWaiting.php";
|
||||
static String getNotificationCaptain = "$ride/notificationCaptain/get.php";
|
||||
static String updateNotificationCaptain =
|
||||
"$ride/notificationCaptain/update.php";
|
||||
static String deleteNotificationCaptain =
|
||||
"$ride/notificationCaptain/delete.php";
|
||||
//-----------------Api Key------------------
|
||||
static String addApiKey = "$ride/apiKey/add.php";
|
||||
static String getApiKey = "$ride/apiKey/get.php";
|
||||
static String getCnMap = "$server/auth/cnMap.php";
|
||||
static String updateApiKey = "$ride/apiKey/update.php";
|
||||
static String deleteApiKey = "$ride/apiKey/delete.php";
|
||||
|
||||
//-----------------Feed Back------------------
|
||||
static String addFeedBack = "$ride/feedBack/add.php";
|
||||
static String getFeedBack = "$ride/feedBack/get.php";
|
||||
static String updateFeedBack = "$ride/feedBack/updateFeedBack.php";
|
||||
|
||||
//-----------------Tips------------------
|
||||
static String addTips = "$ride/tips/add.php";
|
||||
static String getTips = "$ride/tips/get.php";
|
||||
static String updateTips = "$ride/tips/update.php";
|
||||
|
||||
//-----------------Help Center------------------
|
||||
static String addhelpCenter = "$ride/helpCenter/add.php";
|
||||
static String gethelpCenter = "$ride/helpCenter/get.php";
|
||||
static String getByIdhelpCenter = "$ride/helpCenter/getById.php";
|
||||
static String updatehelpCenter = "$ride/helpCenter/update.php";
|
||||
static String deletehelpCenter = "$ride/helpCenter/delete.php";
|
||||
|
||||
//-----------------license------------------
|
||||
static String addLicense = "$ride/license/add.php";
|
||||
static String getLicense = "$ride/license/get.php";
|
||||
static String updateLicense = "$ride/license/updateFeedBack.php";
|
||||
//-----------------RegisrationCar------------------
|
||||
static String addRegisrationCar = "$ride/RegisrationCar/add.php";
|
||||
static String getRegisrationCar = "$ride/RegisrationCar/get.php";
|
||||
static String updateRegisrationCar = "$ride/RegisrationCar/update.php";
|
||||
|
||||
//-----------------DriverOrder------------------
|
||||
|
||||
static String addDriverOrder = "$ride/driver_order/add.php";
|
||||
static String getDriverOrder = "$ride/driver_order/get.php";
|
||||
static String getOrderCancelStatus =
|
||||
"$ride/driver_order/getOrderCancelStatus.php";
|
||||
static String updateDriverOrder = "$ride/driver_order/update.php";
|
||||
static String deleteDriverOrder = "$ride/driver_order/delete.php";
|
||||
|
||||
// =====================================
|
||||
static String addRateToPassenger = "$ride/rate/add.php";
|
||||
static String addRateToDriver = "$ride/rate/addRateToDriver.php";
|
||||
static String getDriverRate = "$ride/rate/getDriverRate.php";
|
||||
static String getPassengerRate = "$ride/rate/getPassengerRate.php";
|
||||
|
||||
////////////////emails ============//
|
||||
static String sendEmailToPassengerForTripDetails =
|
||||
"$ride/rides/emailToPassengerTripDetail.php";
|
||||
static String sendEmailToDrivertransaction =
|
||||
"$server/Admin/sendEmailToDrivertransaction.php";
|
||||
|
||||
// ===========================================
|
||||
static String pathImage = "$server/upload/types/";
|
||||
static String uploadImage = "$server/uploadImage.php";
|
||||
static String uploadImage1 = "$server/uploadImage1.php";
|
||||
static String uploadImagePortrate = "$server/uploadImagePortrate.php";
|
||||
static String uploadImageType = "$server/uploadImageType.php";
|
||||
//=============egypt documents ==============
|
||||
static String uploadEgyptidFront =
|
||||
"$server/EgyptDocuments/uploadEgyptidFront.php";
|
||||
static String uploadEgypt = "$server/uploadEgypt.php";
|
||||
|
||||
//==================certifcate==========
|
||||
static String location = '$server/ride/location';
|
||||
static String getCarsLocationByPassenger = "$location/get.php";
|
||||
static String getFemalDriverLocationByPassenger =
|
||||
"$location/getFemalDriver.php";
|
||||
static String getDriverCarsLocationToPassengerAfterApplied =
|
||||
"$location/getDriverCarsLocationToPassengerAfterApplied.php";
|
||||
static String addCarsLocationByPassenger = "$location/add.php";
|
||||
static String deleteCarsLocationByPassenger = "$location/delete.php";
|
||||
static String updateCarsLocationByPassenger = "$location/update.php";
|
||||
static String getTotalDriverDuration = "$location/getTotalDriverDuration.php";
|
||||
static String getTotalDriverDurationToday =
|
||||
"$location/getTotalDriverDurationToday.php";
|
||||
|
||||
//==================Blog=============
|
||||
static String profile = '$server/ride/profile';
|
||||
static String getprofile = "$profile/get.php";
|
||||
static String getCaptainProfile = "$profile/getCaptainProfile.php";
|
||||
static String addprofile = "$profile/add.php";
|
||||
static String deleteprofile = "$profile/delete.php";
|
||||
static String updateprofile = "$profile/update.php";
|
||||
|
||||
//===================Auth============
|
||||
|
||||
static String auth = '$server/auth';
|
||||
static String login = "$auth/login.php";
|
||||
static String signUp = "$auth/signup.php";
|
||||
static String sendVerifyEmail = "$auth/sendVerifyEmail.php";
|
||||
static String passengerRemovedAccountEmail =
|
||||
"$auth/passengerRemovedAccountEmail.php";
|
||||
static String verifyEmail = "$auth/verifyEmail.php";
|
||||
//===================Auth Captin============
|
||||
static String authCaptin = '$server/auth/captin';
|
||||
static String loginCaptin = "$authCaptin/login.php";
|
||||
static String signUpCaptin = "$authCaptin/register.php";
|
||||
static String sendVerifyEmailCaptin = "$authCaptin/sendVerifyEmail.php";
|
||||
static String verifyEmailCaptin = "$authCaptin/verifyEmail.php";
|
||||
static String removeUser = "$authCaptin/removeAccount.php";
|
||||
static String deletecaptainAccounr = "$authCaptin/deletecaptainAccounr.php";
|
||||
static String updateAccountBank = "$authCaptin/updateAccountBank.php";
|
||||
static String getAccount = "$authCaptin/getAccount.php";
|
||||
|
||||
//===================Admin Captin============
|
||||
static String getDriversPhonesAndTokens =
|
||||
"$server/Admin/AdminCaptain/getDriversPhonesAndTokens.php";
|
||||
static String getPassengerDetailsByPassengerID =
|
||||
"$server/Admin/getPassengerDetailsByPassengerID.php";
|
||||
static String getPassengerDetails = "$server/Admin/getPassengerDetails.php";
|
||||
static String getPassengerbyEmail = "$server/Admin/getPassengerbyEmail.php";
|
||||
static String addAdminUser = "$server/Admin/adminUser/add.php";
|
||||
static String getdashbord = "$server/Admin/dashbord.php";
|
||||
static String getEmployee = "$server/Admin/employee/get.php";
|
||||
static String getBestDriver = "$server/Admin/driver/getBestDriver.php";
|
||||
static String getBestDriverGiza =
|
||||
"https://gizasefer.online/sefer/Admin/driver/getBestDriver.php";
|
||||
static String getBestDriverAlexandria =
|
||||
"$tripzAlexandriaServer/Admin/driver/getBestDriver.php";
|
||||
static String deleteRecord = "$server/Admin/driver/deleteRecord.php";
|
||||
static String addEmployee = "$server/Admin/employee/add.php";
|
||||
static String getdashbordPayment = "$server/Admin/dashbordPayment.php";
|
||||
static String getAdminUser = "$server/Admin/adminUser/get.php";
|
||||
static String getCaptainDetailsByEmailOrIDOrPhone =
|
||||
"$server/Admin/AdminCaptain/getCaptainDetailsByEmailOrIDOrPhone.php";
|
||||
static String getCaptainDetails = "$server/Admin/AdminCaptain/get.php";
|
||||
static String getVisaForEachDriver =
|
||||
"$seferPaymentServer/Admin/getVisaForEachDriver.php";
|
||||
static String getRidesPerMonth =
|
||||
"$server/Admin/AdminRide/getRidesPerMonth.php";
|
||||
static String getRidesDetails = "$server/Admin/AdminRide/get.php";
|
||||
static String getPassengersStatic = "$serviceApp/getPassengersStatic.php";
|
||||
static String getRidesStatic = "$serviceApp/getRidesStatic.php";
|
||||
static String getEmployeeStatic = "$serviceApp/getEmployeeStatic.php";
|
||||
static String getdriverstotalMonthly =
|
||||
"$serviceApp/getdriverstotalMonthly.php";
|
||||
|
||||
////////////////////////
|
||||
static String serviceApp = "$server/serviceapp";
|
||||
static String editCarPlate = "$serviceApp/editCarPlate.php";
|
||||
static String getComplaintAllData = "$serviceApp/getComplaintAllData.php";
|
||||
static String getComplaintAllDataForDriver =
|
||||
"$serviceApp/getComplaintAllDataForDriver.php";
|
||||
static String addCriminalDocuments = "$authCaptin/addCriminalDocuments.php";
|
||||
static String getPassengersByPhone =
|
||||
"$server/serviceApp/getPassengersByPhone.php";
|
||||
static String getDriverByPhone = "$serviceApp/getDriverByPhone.php";
|
||||
static String getNewDriverRegister = "$serviceApp/getNewDriverRegister.php";
|
||||
static String addWelcomeDriverNote = "$serviceApp/addWelcomeDriverNote.php";
|
||||
static String getDriverNotCompleteRegistration =
|
||||
"$serviceApp/getDriverNotCompleteRegistration.php";
|
||||
static String getPassengersNotCompleteRegistration =
|
||||
"$serviceApp/getPassengersNotCompleteRegistration.php";
|
||||
static String addNotesDriver = "$serviceApp/addNotesDriver.php";
|
||||
static String getCarPlateNotEdit = "$serviceApp/getCarPlateNotEdit.php";
|
||||
static String addNotesPassenger = "$serviceApp/addNotesPassenger.php";
|
||||
static String getPackages = "$serviceApp/getPackages.php";
|
||||
static String updatePackages = "$serviceApp/updatePackages.php";
|
||||
//////
|
||||
static String sendSms = "https://sms.kazumi.me/api/sms/send-sms";
|
||||
static String senddlr = "https://sms.kazumi.me/api/sms/send-dlr";
|
||||
static String sendvalidity = "https://sms.kazumi.me/api/sms/send-validity";
|
||||
static String sendmany = "https://sms.kazumi.me/api/sms/send-many";
|
||||
static String checkCredit = "https://sms.kazumi.me/api/sms/check-credit";
|
||||
static String getSender = "$server/auth/sms/getSender.php";
|
||||
static String checkStatus = "https://sms.kazumi.me/api/sms/check-status";
|
||||
static String updatePhoneInvalidSMSPassenger =
|
||||
"$server/auth/sms/updatePhoneInvalidSMSPassenger.php";
|
||||
}
|
||||
64
lib/constant/style.dart
Normal file
64
lib/constant/style.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../main.dart';
|
||||
import 'box_name.dart';
|
||||
import 'colors.dart';
|
||||
|
||||
class AppStyle {
|
||||
static TextStyle headTitle = const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 40,
|
||||
color: AppColor.accentColor,
|
||||
);
|
||||
static TextStyle headTitle2 = const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 26,
|
||||
color: AppColor.primaryColor,
|
||||
);
|
||||
static TextStyle title = const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: AppColor.primaryColor,
|
||||
);
|
||||
static TextStyle subtitle = const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 13,
|
||||
color: AppColor.primaryColor,
|
||||
);
|
||||
static TextStyle number = const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: AppColor.primaryColor,
|
||||
);
|
||||
|
||||
static BoxDecoration boxDecoration = const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
color: AppColor.secondaryColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor,
|
||||
offset: Offset(-3, -3),
|
||||
blurRadius: 0,
|
||||
spreadRadius: 0,
|
||||
blurStyle: BlurStyle.outer),
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor,
|
||||
offset: Offset(3, 3),
|
||||
blurRadius: 0,
|
||||
spreadRadius: 0,
|
||||
blurStyle: BlurStyle.outer)
|
||||
]);
|
||||
static BoxDecoration boxDecoration1 = const BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor, blurRadius: 5, offset: Offset(2, 4)),
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor, blurRadius: 5, offset: Offset(-2, -2))
|
||||
],
|
||||
color: AppColor.secondaryColor,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.elliptical(15, 30),
|
||||
),
|
||||
);
|
||||
}
|
||||
9
lib/constant/table_names.dart
Normal file
9
lib/constant/table_names.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
class TableName {
|
||||
static const String placesFavorite = "placesFavorite";
|
||||
static const String recentLocations = "recentLocations";
|
||||
static const String carLocations = "carLocations";
|
||||
static const String driverOrdersRefuse = "driverOrdersRefuse";
|
||||
static const String rideLocation = "rideLocation";
|
||||
static const String faceDetectTimes = "faceDetectTimes";
|
||||
static const String captainNotification = "captainNotification";
|
||||
}
|
||||
105
lib/controller/admin/captain_admin_controller.dart
Normal file
105
lib/controller/admin/captain_admin_controller.dart
Normal file
@@ -0,0 +1,105 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class CaptainAdminController extends GetxController {
|
||||
bool isLoading = false;
|
||||
Map captainData = {};
|
||||
Map captain = {};
|
||||
final captainController = TextEditingController();
|
||||
final captainPrizeController = TextEditingController();
|
||||
final titleNotify = TextEditingController();
|
||||
final bodyNotify = TextEditingController();
|
||||
final formCaptainKey = GlobalKey<FormState>();
|
||||
final formCaptainPrizeKey = GlobalKey<FormState>();
|
||||
|
||||
Future getCaptainCount() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
var res = await CRUD().get(link: AppLink.getCaptainDetails, payload: {});
|
||||
var d = jsonDecode(res);
|
||||
if (d['status'] == 'success') {
|
||||
captainData = d;
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Future addCaptainPrizeToWallet() async {
|
||||
String? paymentId;
|
||||
//todo link to add wallet to captain
|
||||
for (var i = 0; i < captainData['message'].length; i++) {
|
||||
await CRUD().post(link: AppLink.addDriverPaymentPoints, payload: {
|
||||
'driverID': captainData['message'][i]['id'],
|
||||
'amount': captainPrizeController.text,
|
||||
'paymentMethod': 'Prize',
|
||||
}).then((value) {
|
||||
paymentId = value['message'].toString();
|
||||
});
|
||||
await CRUD().post(link: AppLink.addPassengersWallet, payload: {
|
||||
'driverID': captainData['message'][i]['id'],
|
||||
'amount': captainPrizeController.text,
|
||||
'paymentMethod': 'Prize',
|
||||
'paymentID': paymentId.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
Get.back();
|
||||
}
|
||||
|
||||
void addCaptainsPrizeToWalletSecure() async {
|
||||
try {
|
||||
// Check if local authentication is available
|
||||
bool isAvailable = await LocalAuthentication().isDeviceSupported();
|
||||
if (isAvailable) {
|
||||
// Authenticate the user
|
||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||
);
|
||||
if (didAuthenticate) {
|
||||
// User authenticated successfully, proceed with payment
|
||||
await addCaptainPrizeToWallet();
|
||||
Get.snackbar('Prize Added', '', backgroundColor: AppColor.greenColor);
|
||||
} else {
|
||||
// Authentication failed, handle accordingly
|
||||
Get.snackbar('Authentication failed', '',
|
||||
backgroundColor: AppColor.redColor);
|
||||
// 'Authentication failed');
|
||||
}
|
||||
} else {
|
||||
// Local authentication not available, proceed with payment without authentication
|
||||
await addCaptainPrizeToWallet();
|
||||
Get.snackbar('Prize Added', '', backgroundColor: AppColor.greenColor);
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future getCaptains() async {
|
||||
var res = await CRUD()
|
||||
.get(link: AppLink.getCaptainDetailsByEmailOrIDOrPhone, payload: {
|
||||
'driver_id': captainController.text,
|
||||
'driverEmail': captainController.text,
|
||||
'driverPhone': captainController.text,
|
||||
});
|
||||
var d = jsonDecode(res);
|
||||
if (d['status'] == 'success') {
|
||||
captain = d;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getCaptainCount();
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
86
lib/controller/admin/dashboard_controller.dart
Normal file
86
lib/controller/admin/dashboard_controller.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
|
||||
class DashboardController extends GetxController {
|
||||
bool isLoading = false;
|
||||
List dashbord = [];
|
||||
String creditSMS = '0';
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final smsText = TextEditingController();
|
||||
|
||||
Future getDashBoard() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
// الطلب من السيرفر الرئيسي
|
||||
var res = await CRUD().get(link: AppLink.getdashbord, payload: {});
|
||||
if (res != 'failure') {
|
||||
var d = jsonDecode(res);
|
||||
// Log.print('d: ${d}');
|
||||
dashbord = d['message']; // هذا عبارة عن List<Map>
|
||||
}
|
||||
|
||||
// الطلب من سيرفر المحافظ
|
||||
var resPayments = await CRUD().postWallet(
|
||||
link: AppLink.getPaymentsDashboard,
|
||||
payload: {},
|
||||
);
|
||||
|
||||
if (resPayments != 'failure') {
|
||||
var p = resPayments;
|
||||
// Log.print('p: ${p}');
|
||||
|
||||
// نتأكد أن الكل Map بداخل List
|
||||
if (dashbord.isNotEmpty &&
|
||||
p['message'] is List &&
|
||||
p['message'].isNotEmpty) {
|
||||
dashbord[0].addAll(p['message'][0]); // ندمج المعلومات داخل نفس الـ Map
|
||||
}
|
||||
}
|
||||
|
||||
// كريدت الرسائل
|
||||
var res2 = await CRUD().kazumiSMS(
|
||||
link: 'https://sms.kazumi.me/api/sms/check-credit',
|
||||
payload: {"username": "Sefer", "password": AK.smsPasswordEgypt},
|
||||
);
|
||||
|
||||
creditSMS = res2['credit'];
|
||||
Log.print(' res2[credit]: ${res2['credit']}');
|
||||
Log.print('creditSMS: ${creditSMS}');
|
||||
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
sendSMSMethod() async {
|
||||
if (formKey.currentState!.validate()) {
|
||||
for (var phoneNumber in box.read(BoxName.tokensDrivers)['message']) {
|
||||
// for (var i = 0; i < 2; i++) {
|
||||
await CRUD().sendSmsEgypt(
|
||||
phoneNumber['phone'].toString(),
|
||||
// box.read(BoxName.tokensDrivers)['message'][i]['phone'].toString(),
|
||||
smsText.text,
|
||||
);
|
||||
// Log.print('CRUD().phoneDriversTest.: ${phoneNumber['phone']}');
|
||||
Future.delayed(const Duration(microseconds: 20));
|
||||
}
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
getDashBoard();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
25
lib/controller/admin/get_all_invoice_controller.dart
Normal file
25
lib/controller/admin/get_all_invoice_controller.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
class InvoiceModel {
|
||||
final String invoiceNumber;
|
||||
final String amount;
|
||||
final String date;
|
||||
final String name;
|
||||
final String? imageLink;
|
||||
|
||||
InvoiceModel({
|
||||
required this.invoiceNumber,
|
||||
required this.amount,
|
||||
required this.date,
|
||||
required this.name,
|
||||
this.imageLink,
|
||||
});
|
||||
|
||||
factory InvoiceModel.fromJson(Map<String, dynamic> json) {
|
||||
return InvoiceModel(
|
||||
invoiceNumber: json['invoice_number'],
|
||||
amount: json['amount'].toString(),
|
||||
date: json['date'],
|
||||
name: json['name'],
|
||||
imageLink: json['image_link'],
|
||||
);
|
||||
}
|
||||
}
|
||||
108
lib/controller/admin/passenger_admin_controller.dart
Normal file
108
lib/controller/admin/passenger_admin_controller.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class PassengerAdminController extends GetxController {
|
||||
bool isLoading = false;
|
||||
Map passengersData = {};
|
||||
Map passengers = {};
|
||||
double height = 150;
|
||||
final formPassKey = GlobalKey<FormState>();
|
||||
final formPrizeKey = GlobalKey<FormState>();
|
||||
final titleNotify = TextEditingController();
|
||||
final bodyNotify = TextEditingController();
|
||||
final passengerController = TextEditingController();
|
||||
final passengerPrizeController = TextEditingController();
|
||||
|
||||
Future getPassengerCount() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
var res = await CRUD().get(link: AppLink.getPassengerDetails, payload: {});
|
||||
var d = jsonDecode(res);
|
||||
if (d['status'] == 'success') {
|
||||
passengersData = d;
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Future addPassengerPrizeToWallet() async {
|
||||
for (var i = 0; i < passengersData['message'].length; i++) {
|
||||
await CRUD().post(link: AppLink.addPassengersWallet, payload: {
|
||||
'passenger_id': passengersData['message'][i]['id'],
|
||||
'balance': passengerPrizeController.text,
|
||||
});
|
||||
}
|
||||
|
||||
Get.back();
|
||||
}
|
||||
|
||||
void addPassengerPrizeToWalletSecure() async {
|
||||
try {
|
||||
// Check if local authentication is available
|
||||
bool isAvailable = await LocalAuthentication().isDeviceSupported();
|
||||
if (isAvailable) {
|
||||
// Authenticate the user
|
||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||
);
|
||||
if (didAuthenticate) {
|
||||
// User authenticated successfully, proceed with payment
|
||||
await addPassengerPrizeToWallet();
|
||||
Get.snackbar('Prize Added', '', backgroundColor: AppColor.greenColor);
|
||||
} else {
|
||||
// Authentication failed, handle accordingly
|
||||
Get.snackbar('Authentication failed', '',
|
||||
backgroundColor: AppColor.redColor);
|
||||
// 'Authentication failed');
|
||||
}
|
||||
} else {
|
||||
// Local authentication not available, proceed with payment without authentication
|
||||
await addPassengerPrizeToWallet();
|
||||
Get.snackbar('Prize Added', '', backgroundColor: AppColor.greenColor);
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future getPassengers() async {
|
||||
var res = await CRUD().get(link: AppLink.getPassengerbyEmail, payload: {
|
||||
'passengerEmail': passengerController.text,
|
||||
'passengerId': passengerController.text,
|
||||
'passengerphone': passengerController.text,
|
||||
});
|
||||
var d = jsonDecode(res);
|
||||
if (d['status'] == 'success') {
|
||||
passengers = d;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
changeHeight() {
|
||||
if (passengers.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
}
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
|
||||
void clearPlaces() {
|
||||
passengers = {};
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getPassengerCount();
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
590
lib/controller/admin/register_captain_controller.dart
Normal file
590
lib/controller/admin/register_captain_controller.dart
Normal file
@@ -0,0 +1,590 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/info.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../main.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class RegisterCaptainController extends GetxController {
|
||||
bool isDriverSaved = false;
|
||||
bool isCarSaved = false;
|
||||
Map<String, dynamic>? arguments;
|
||||
String? driverId;
|
||||
String? email;
|
||||
String? phone;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
arguments = Get.arguments;
|
||||
initArguments();
|
||||
}
|
||||
|
||||
void driveInit() {
|
||||
arguments = Get.arguments;
|
||||
initArguments();
|
||||
}
|
||||
|
||||
void initArguments() {
|
||||
if (arguments != null) {
|
||||
driverId = arguments!['driverId'];
|
||||
email = arguments!['email'];
|
||||
phone = arguments!['phone_number'];
|
||||
} else {
|
||||
print('Arguments are null');
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> responseMap = {};
|
||||
Map<String, dynamic> responseCarLicenseMapJordan = {};
|
||||
Map<String, dynamic> responseBackCarLicenseMap = {};
|
||||
Map<String, dynamic> responseIdCardMap = {};
|
||||
Map<String, dynamic> responseIdCardDriverEgyptBack = {};
|
||||
Map<String, dynamic> responseForComplaint = {};
|
||||
Map<String, dynamic> responseIdCardDriverEgyptFront = {};
|
||||
Map<String, dynamic> responseIdEgyptFront = {};
|
||||
Map<String, dynamic> responseCriminalRecordEgypt = {};
|
||||
Map<String, dynamic> responseIdEgyptBack = {};
|
||||
Map<String, dynamic> responseIdEgyptDriverLicense = {};
|
||||
String? responseIdCardDriverEgypt1;
|
||||
bool isloading = false;
|
||||
var image;
|
||||
DateTime now = DateTime.now();
|
||||
|
||||
bool isLoading = false;
|
||||
Future allMethodForAI(String prompt, imagePath, driverID) async {
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
var extractedString = await CRUD().arabicTextExtractByVisionAndAI(
|
||||
imagePath: imagePath, driverID: driverID);
|
||||
var json = jsonDecode(extractedString);
|
||||
var textValues = extractTextFromLines(json);
|
||||
// await Get.put(AI()).geminiAiExtraction(prompt, textValues, imagePath);
|
||||
await Get.put(RegisterCaptainController())
|
||||
.anthropicAI(textValues, prompt, imagePath);
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
String extractTextFromLines(Map<String, dynamic> jsonData) {
|
||||
final readResult = jsonData['readResult'];
|
||||
final blocks = readResult['blocks'];
|
||||
|
||||
final StringBuffer buffer = StringBuffer();
|
||||
|
||||
for (final block in blocks) {
|
||||
final lines = block['lines'];
|
||||
for (final line in lines) {
|
||||
final text = line['text'];
|
||||
buffer.write(text);
|
||||
buffer.write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString().trim();
|
||||
}
|
||||
|
||||
List driverNotCompleteRegistration = [];
|
||||
getDriverNotCompleteRegistration() async {
|
||||
var res = await CRUD()
|
||||
.get(link: AppLink.getDriverNotCompleteRegistration, payload: {});
|
||||
if (res != 'failure') {
|
||||
var d = jsonDecode(res)['message'];
|
||||
driverNotCompleteRegistration = d;
|
||||
update();
|
||||
} else {
|
||||
Get.snackbar(res, '');
|
||||
}
|
||||
}
|
||||
|
||||
final today = DateTime.now();
|
||||
|
||||
Future<void> addDriverAndCarEgypt() async {
|
||||
final expiryDate = responseIdEgyptDriverLicense['expiry_date'];
|
||||
final expiryDateTime = DateTime.tryParse(expiryDate);
|
||||
final isExpired = expiryDateTime != null && expiryDateTime.isBefore(today);
|
||||
|
||||
final taxExpiryDate = responseIdCardDriverEgyptBack['tax_expiry'];
|
||||
|
||||
// Get the inspection date from the response
|
||||
final inspectionDate = responseIdCardDriverEgyptBack['inspection_date'];
|
||||
final year = int.parse(inspectionDate.split('-')[0]);
|
||||
// Try parsing the tax expiry date. If it fails, set it to null.
|
||||
final taxExpiryDateTime = DateTime.tryParse(taxExpiryDate ?? '');
|
||||
final isExpiredCar =
|
||||
taxExpiryDateTime != null && taxExpiryDateTime.isBefore(today);
|
||||
|
||||
// Check if the inspection date is before today
|
||||
final inspectionDateTime = DateTime(year, 1, 1);
|
||||
final isInspectionExpired = inspectionDateTime.isBefore(today);
|
||||
|
||||
if (isExpiredCar || isInspectionExpired) {
|
||||
Get.defaultDialog(
|
||||
title: 'Expired Driver’s License'.tr,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.warning, size: 48, color: Colors.red),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Your driver’s license and/or car tax has expired. Please renew them before proceeding.'
|
||||
.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
// await Get.find<TextToSpeechController>().speakText(
|
||||
// 'Your driver’s license and/or car tax has expired. Please renew them before proceeding.'
|
||||
// .tr,
|
||||
// );
|
||||
},
|
||||
icon: const Icon(Icons.volume_up),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else if (isExpired) {
|
||||
Get.defaultDialog(
|
||||
title: 'Expired Driver’s License'.tr,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.warning, size: 48, color: Colors.red),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Your driver’s license has expired. Please renew it before proceeding.'
|
||||
.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
// await Get.find<TextToSpeechController>().speakText(
|
||||
// 'Your driver’s license has expired. Please renew it before proceeding.'
|
||||
// .tr,
|
||||
// );
|
||||
},
|
||||
icon: const Icon(Icons.volume_up),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else if (responseIdEgyptDriverLicense['national_number']
|
||||
.toString()
|
||||
.substring(0, 12) !=
|
||||
responseIdEgyptBack['nationalID'].toString().substring(0, 12)) {
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: 'ID Mismatch',
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.warning, size: 48, color: Colors.red),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'The national number on your driver’s license does not match the one on your ID document. Please verify and provide the correct documents.'
|
||||
.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
// await Get.find<TextToSpeechController>().speakText(
|
||||
// 'The national number on your driver’s license does not match the one on your ID document. Please verify and provide the correct documents.',
|
||||
// );
|
||||
},
|
||||
icon: const Icon(Icons.volume_up),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
// else if (responseCriminalRecordEgypt['FullName'] !=
|
||||
// responseIdEgyptDriverLicense['name_arabic']) {
|
||||
// Get.defaultDialog(
|
||||
// barrierDismissible: false,
|
||||
// title: 'Criminal Record Mismatch',
|
||||
// content: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// const Icon(Icons.warning, size: 48, color: Colors.red),
|
||||
// const SizedBox(height: 16),
|
||||
// Text(
|
||||
// 'The full name on your criminal record does not match the one on your driver’s license. Please verify and provide the correct documents.'
|
||||
// .tr,
|
||||
// textAlign: TextAlign.center,
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
// const SizedBox(height: 16),
|
||||
// IconButton(
|
||||
// onPressed: () async {
|
||||
// await Get.find<TextToSpeechController>().speakText(
|
||||
// 'The full name on your criminal record does not match the one on your driver’s license. Please verify and provide the correct documents.'
|
||||
// .tr,
|
||||
// );
|
||||
// },
|
||||
// icon: const Icon(Icons.volume_up),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Get.back();
|
||||
// },
|
||||
// child: const Text('OK'),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
else {
|
||||
await addDriverEgypt();
|
||||
await addRegistrationCarEgypt();
|
||||
|
||||
if (isCarSaved && isDriverSaved) {
|
||||
Get.snackbar('added', '',
|
||||
backgroundColor:
|
||||
AppColor.greenColor); // Get.offAll(() => HomeCaptain());
|
||||
// Get.offAll(() => HomeCaptain());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addDriverEgypt() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
var payload = {
|
||||
'first_name': responseIdEgyptDriverLicense['firstName']?.toString() ??
|
||||
'Not specified',
|
||||
'last_name': responseIdEgyptDriverLicense['lastName']?.toString() ??
|
||||
'Not specified',
|
||||
'email': email?.toString() ?? 'Not specified',
|
||||
'phone': phone?.toString() ?? 'Not specified',
|
||||
'id': driverId?.toString() ?? 'Not specified',
|
||||
'password': '123456',
|
||||
'gender': responseIdEgyptBack['gender']?.toString() ?? 'Not specified',
|
||||
'license_type':
|
||||
responseIdEgyptDriverLicense['license_type']?.toString() ??
|
||||
'Not specified',
|
||||
'national_number':
|
||||
responseIdEgyptBack['nationalID']?.toString() ?? 'Not specified',
|
||||
'name_arabic': responseIdEgyptDriverLicense['name_arabic']?.toString() ??
|
||||
'Not specified',
|
||||
'name_english':
|
||||
responseIdEgyptDriverLicense['name_english']?.toString() ??
|
||||
'Not specified',
|
||||
'issue_date': responseIdEgyptDriverLicense['issue_date']?.toString() ??
|
||||
'Not specified',
|
||||
'expiry_date': responseIdEgyptDriverLicense['expiry_date']?.toString() ??
|
||||
'Not specified',
|
||||
'license_categories': responseIdEgyptDriverLicense['license_categories']
|
||||
is List
|
||||
? responseIdEgyptDriverLicense['license_categories'].join(', ')
|
||||
: responseIdEgyptDriverLicense['license_categories']?.toString() ??
|
||||
'Not specified',
|
||||
'address': responseIdEgyptFront['address']?.toString() ?? 'Not specified',
|
||||
'card_id': responseIdEgyptFront['card_id']?.toString() ?? 'Not specified',
|
||||
'occupation':
|
||||
responseIdEgyptBack['occupation']?.toString() ?? 'Not specified',
|
||||
'education':
|
||||
responseIdEgyptBack['occupation']?.toString() ?? 'Not specified',
|
||||
'licenseIssueDate':
|
||||
responseIdEgyptDriverLicense['issue_date']?.toString() ??
|
||||
'Not specified',
|
||||
'religion':
|
||||
responseIdEgyptBack['religion']?.toString() ?? 'Not specified',
|
||||
'status': 'yet',
|
||||
'birthdate': responseIdEgyptFront['dob']?.toString() ?? 'Not specified',
|
||||
'maritalStatus':
|
||||
responseIdEgyptBack['maritalStatus']?.toString() ?? 'Not specified',
|
||||
'site': responseIdEgyptDriverLicense['address']?.toString() ??
|
||||
'Not specified',
|
||||
'employmentType':
|
||||
responseIdEgyptDriverLicense['employmentType']?.toString() ??
|
||||
'Not specified',
|
||||
};
|
||||
var res = await CRUD().post(link: AppLink.signUpCaptin, payload: payload);
|
||||
var status1 = jsonDecode(res);
|
||||
isLoading = false;
|
||||
update();
|
||||
// Handle response
|
||||
if (status1['status'] == 'success') {
|
||||
isDriverSaved = true;
|
||||
Get.snackbar('Success', 'Driver data saved successfully',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
} else {
|
||||
Get.snackbar('Error', 'Failed to save driver data',
|
||||
backgroundColor: Colors.red);
|
||||
}
|
||||
}
|
||||
|
||||
addCriminalDeocuments() async {
|
||||
var res = await CRUD().post(link: AppLink.addCriminalDocuments, payload: {
|
||||
"driverId": box.read(BoxName.driverID),
|
||||
"IssueDate": responseCriminalRecordEgypt['IssueDate'],
|
||||
"InspectionResult": responseCriminalRecordEgypt['InspectionResult'],
|
||||
});
|
||||
if (res != 'failure') {
|
||||
Get.snackbar('uploaded sucssefuly'.tr, '');
|
||||
}
|
||||
}
|
||||
|
||||
Future addRegistrationCarEgypt() async {
|
||||
try {
|
||||
isLoading = true;
|
||||
update();
|
||||
var res = await CRUD().post(link: AppLink.addRegisrationCar, payload: {
|
||||
'driverID': driverId,
|
||||
'vin': responseIdCardDriverEgyptBack['chassis'].toString(),
|
||||
'car_plate': responseIdCardDriverEgyptFront['car_plate'].toString(),
|
||||
'make': responseIdCardDriverEgyptBack['make'].toString(),
|
||||
'model': responseIdCardDriverEgyptBack['model'],
|
||||
'year': responseIdCardDriverEgyptBack['year'].toString(),
|
||||
'expiration_date':
|
||||
responseIdCardDriverEgyptFront['LicenseExpirationDate'].toString(),
|
||||
'color': responseIdCardDriverEgyptBack['color'],
|
||||
'owner': responseIdCardDriverEgyptFront['owner'],
|
||||
'color_hex': responseIdCardDriverEgyptBack['color_hex'].toString(),
|
||||
'address': responseIdCardDriverEgyptFront['address'].toString(),
|
||||
'displacement': responseIdCardDriverEgyptBack['engine'].toString(),
|
||||
'fuel': responseIdCardDriverEgyptBack['fuel'].toString(),
|
||||
'registration_date':
|
||||
'${responseIdCardDriverEgyptBack['inspection_date']}',
|
||||
});
|
||||
isLoading = false;
|
||||
update();
|
||||
var status = jsonDecode(res);
|
||||
if (status['status'] == 'success') {
|
||||
isCarSaved = true;
|
||||
Get.snackbar('Success', 'message',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
Future getComplaintDataToAI() async {
|
||||
var res = await CRUD().get(
|
||||
link: AppLink.getComplaintAllDataForDriver,
|
||||
payload: {'driver_id': driverId.toString()},
|
||||
);
|
||||
if (res != 'failure') {
|
||||
var d = jsonDecode(res)['message'];
|
||||
return d;
|
||||
} else {
|
||||
return [
|
||||
{'data': 'no data'}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Future<dynamic> anthropicAIForComplaint() async {
|
||||
var dataComplaint = await getComplaintDataToAI();
|
||||
var messagesData = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "$dataComplaint ${AppInformation.complaintPrompt} "
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
var requestBody = jsonEncode({
|
||||
"model": "claude-3-haiku-20240307",
|
||||
"max_tokens": 1024,
|
||||
"temperature": 0,
|
||||
"system": "Json output only without any additional ",
|
||||
"messages": messagesData,
|
||||
});
|
||||
final response = await http.post(
|
||||
Uri.parse('https://api.anthropic.com/v1/messages'),
|
||||
headers: {
|
||||
'x-api-key': AK.anthropicAIkeySeferNew,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: requestBody,
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
var responseData = jsonDecode(utf8.decode(response.bodyBytes));
|
||||
// Process the responseData as needed
|
||||
|
||||
responseForComplaint = jsonDecode(responseData['content'][0]['text']);
|
||||
}
|
||||
}
|
||||
|
||||
Future<dynamic> anthropicAI(
|
||||
String payload, String prompt, String idType) async {
|
||||
var messagesData = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "text": "$payload $prompt"}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var requestBody = jsonEncode({
|
||||
"model": "claude-3-haiku-20240307",
|
||||
"max_tokens": 1024,
|
||||
"temperature": 0,
|
||||
"system": "Json output only without any additional ",
|
||||
"messages": messagesData,
|
||||
});
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse('https://api.anthropic.com/v1/messages'),
|
||||
headers: {
|
||||
'x-api-key': AK.anthropicAIkeySeferNew,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var responseData = jsonDecode(utf8.decode(response.bodyBytes));
|
||||
// Process the responseData as needed
|
||||
if (idType == 'car_back') {
|
||||
responseIdCardDriverEgyptBack =
|
||||
jsonDecode(responseData['content'][0]['text']);
|
||||
} else if (idType == 'car_front') {
|
||||
responseIdCardDriverEgyptFront =
|
||||
jsonDecode(responseData['content'][0]['text']);
|
||||
} else if (idType == 'id_front') {
|
||||
responseIdEgyptFront = jsonDecode(responseData['content'][0]['text']);
|
||||
} else if (idType == 'id_back') {
|
||||
responseIdEgyptBack = jsonDecode(responseData['content'][0]['text']);
|
||||
} else if (idType == 'driver_license') {
|
||||
responseIdEgyptDriverLicense =
|
||||
jsonDecode(responseData['content'][0]['text']);
|
||||
} else if (idType == 'criminalRecord') {
|
||||
responseCriminalRecordEgypt =
|
||||
jsonDecode(responseData['content'][0]['text']);
|
||||
}
|
||||
|
||||
update();
|
||||
return responseData.toString();
|
||||
}
|
||||
return responseIdCardDriverEgyptBack.toString();
|
||||
}
|
||||
|
||||
Future<void> geminiAiExtraction(String prompt, payload, String idType) async {
|
||||
var requestBody = jsonEncode({
|
||||
"contents": [
|
||||
{
|
||||
"parts": [
|
||||
{"text": "$payload $prompt"}
|
||||
]
|
||||
}
|
||||
],
|
||||
"generationConfig": {
|
||||
"temperature": 1,
|
||||
"topK": 64,
|
||||
"topP": 0.95,
|
||||
"maxOutputTokens": 8192,
|
||||
"stopSequences": []
|
||||
},
|
||||
"safetySettings": [
|
||||
{
|
||||
"category": "HARM_CATEGORY_HARASSMENT",
|
||||
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_HATE_SPEECH",
|
||||
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
||||
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
||||
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?key=${AK.geminiApi}'),
|
||||
'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro:generateContent?key=${AK.geminiApi}'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var responseData = jsonDecode(response.body);
|
||||
// Process the responseData as needed
|
||||
|
||||
var result = responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
String? jsonString =
|
||||
regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
if (jsonString != null) {
|
||||
// Convert the JSON object to a String
|
||||
jsonString = jsonEncode(json.decode(jsonString));
|
||||
|
||||
if (idType == 'car_back') {
|
||||
responseIdCardDriverEgyptBack = jsonDecode(jsonString);
|
||||
} else if (idType == 'car_front') {
|
||||
responseIdCardDriverEgyptFront = jsonDecode(jsonString);
|
||||
} else if (idType == 'id_front') {
|
||||
responseIdEgyptFront = jsonDecode(jsonString);
|
||||
} else if (idType == 'id_back') {
|
||||
responseIdEgyptBack = jsonDecode(jsonString);
|
||||
} else if (idType == 'driver_license') {
|
||||
responseIdEgyptDriverLicense = jsonDecode(jsonString);
|
||||
}
|
||||
|
||||
update();
|
||||
} else {
|
||||
Get.snackbar('Error', "JSON string not found",
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
|
||||
// Rest of your code...
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
73
lib/controller/admin/ride_admin_controller.dart
Normal file
73
lib/controller/admin/ride_admin_controller.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/links.dart';
|
||||
import '../../models/model/admin/monthly_ride.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class RideAdminController extends GetxController {
|
||||
bool isLoading = false;
|
||||
late List<MonthlyDataModel> rideData;
|
||||
late Map<String, dynamic> jsonResponse;
|
||||
List<dynamic> ridesDetails = [];
|
||||
var chartData;
|
||||
// late List<ChartDataS> chartDatasync;
|
||||
Future getRidesAdminDash() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
var res = await CRUD().get(link: AppLink.getRidesPerMonth, payload: {});
|
||||
jsonResponse = jsonDecode(res);
|
||||
rideData = (jsonResponse['message'] as List)
|
||||
.map((item) => MonthlyDataModel.fromJson(item))
|
||||
.toList();
|
||||
|
||||
chartData = rideData
|
||||
.map((data) => FlSpot(data.day.toDouble(), data.ridesCount.toDouble()))
|
||||
.toList();
|
||||
|
||||
// chartDatasync = (jsonResponse['message'] as List)
|
||||
// .map((item) => ChartDataS(
|
||||
// item['year'],
|
||||
// item['month'],
|
||||
// item['day'],
|
||||
// item['rides_count'],
|
||||
// ))
|
||||
// .toList();
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Future getRidesDetails() async {
|
||||
// isLoading = true;
|
||||
// update();
|
||||
var res = await CRUD().get(link: AppLink.getRidesDetails, payload: {});
|
||||
|
||||
var d = jsonDecode(res);
|
||||
ridesDetails = d['message'];
|
||||
|
||||
// isLoading = false;
|
||||
// update();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
List<Future> initializationTasks = [
|
||||
getRidesAdminDash(),
|
||||
getRidesDetails(),
|
||||
];
|
||||
// cameras = await availableCameras();
|
||||
await Future.wait(initializationTasks);
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
|
||||
// class ChartDataS {
|
||||
// ChartDataS(this.year, this.month, this.day, this.ridesCount);
|
||||
|
||||
// final int year;
|
||||
// final int month;
|
||||
// final int day;
|
||||
// final int ridesCount;
|
||||
// }
|
||||
238
lib/controller/admin/static_controller.dart
Normal file
238
lib/controller/admin/static_controller.dart
Normal file
@@ -0,0 +1,238 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/links.dart';
|
||||
import '../../models/model/passengers_model.dart';
|
||||
import '../../print.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class StaticController extends GetxController {
|
||||
Map<String, dynamic> jsonData1 = {};
|
||||
Map<String, dynamic> jsonData2 = {};
|
||||
List staticList = [];
|
||||
var chartDataPassengers;
|
||||
var chartDataDrivers;
|
||||
var chartDataDriversCalling;
|
||||
var chartDataRides;
|
||||
var chartDataEmployee;
|
||||
var chartDataEmployeeMaryam;
|
||||
var chartDataEmployeeRawda;
|
||||
var chartDataEmployeeMena;
|
||||
var chartDataEmployeeSefer4;
|
||||
var chartDataDriversMatchingNotes;
|
||||
bool isLoading = false;
|
||||
String totalMonthlyPassengers = '';
|
||||
String totalMonthlyRides = '';
|
||||
String totalMonthlyEmployee = '';
|
||||
String totalMonthlyDrivers = '';
|
||||
late List<MonthlyPassengerInstall> passengersData;
|
||||
late List<MonthlyRidesInstall> ridesData;
|
||||
late List<MonthlyEmployeeData> employeeData;
|
||||
late List<MonthlyDriverInstall> driversData;
|
||||
|
||||
Future<void> fetch() async {
|
||||
isLoading = true;
|
||||
update(); // Notify the observers about the loading state change
|
||||
|
||||
var res = await CRUD().get(
|
||||
link: AppLink.getPassengersStatic,
|
||||
payload: {},
|
||||
);
|
||||
jsonData1 = jsonDecode(res);
|
||||
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
|
||||
isLoading = false;
|
||||
final List<dynamic> jsonData = jsonResponse['message'];
|
||||
totalMonthlyPassengers = jsonData[0]['totalMonthly'].toString();
|
||||
passengersData = jsonData.map<MonthlyPassengerInstall>((item) {
|
||||
return MonthlyPassengerInstall.fromJson(item);
|
||||
}).toList();
|
||||
final List<FlSpot> spots = passengersData
|
||||
.map((data) => FlSpot(
|
||||
data.day.toDouble(),
|
||||
data.totalPassengers.toDouble(),
|
||||
))
|
||||
.toList();
|
||||
chartDataPassengers = spots;
|
||||
|
||||
update(); // Notify the observers about the data and loading state change
|
||||
}
|
||||
|
||||
Future<void> fetchRides() async {
|
||||
isLoading = true;
|
||||
update(); // Notify the observers about the loading state change
|
||||
|
||||
var res = await CRUD().get(
|
||||
link: AppLink.getRidesStatic,
|
||||
payload: {},
|
||||
);
|
||||
jsonData1 = jsonDecode(res);
|
||||
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
|
||||
isLoading = false;
|
||||
final List<dynamic> jsonData = jsonResponse['message'];
|
||||
totalMonthlyRides = jsonData[0]['totalMonthly'].toString();
|
||||
ridesData = jsonData.map<MonthlyRidesInstall>((item) {
|
||||
return MonthlyRidesInstall.fromJson(item);
|
||||
}).toList();
|
||||
final List<FlSpot> spots = ridesData
|
||||
.map((data) => FlSpot(
|
||||
data.day.toDouble(),
|
||||
data.totalRides.toDouble(),
|
||||
))
|
||||
.toList();
|
||||
chartDataRides = spots;
|
||||
|
||||
update(); // Notify the observers about the data and loading state change
|
||||
}
|
||||
|
||||
Future<void> fetchEmployee() async {
|
||||
try {
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
var res = await CRUD().get(link: AppLink.getEmployeeStatic, payload: {});
|
||||
|
||||
// First check if the response is valid JSON
|
||||
if (res == 'failure') {
|
||||
throw FormatException('Invalid response: $res');
|
||||
}
|
||||
|
||||
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
|
||||
|
||||
// Initialize empty lists for all chart data
|
||||
chartDataEmployeeMaryam = <FlSpot>[];
|
||||
chartDataEmployeeRawda = <FlSpot>[];
|
||||
chartDataEmployeeMena = <FlSpot>[];
|
||||
chartDataEmployeeSefer4 = <FlSpot>[];
|
||||
totalMonthlyRides = '0';
|
||||
|
||||
// Check for error response
|
||||
if (jsonResponse['status'] == 'failure') {
|
||||
isLoading = false;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
final List<dynamic> jsonData = jsonResponse['message'];
|
||||
if (jsonData.isEmpty) {
|
||||
isLoading = false;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
totalMonthlyRides = jsonData[0]['totalMonthly']?.toString() ?? '0';
|
||||
|
||||
// Group data by employee
|
||||
Map<String, List<MonthlyEmployeeData>> employeeDataMap = {};
|
||||
|
||||
for (var item in jsonData) {
|
||||
var employeeData = MonthlyEmployeeData.fromJson(item);
|
||||
if (!employeeDataMap.containsKey(employeeData.name)) {
|
||||
employeeDataMap[employeeData.name] = [];
|
||||
}
|
||||
employeeDataMap[employeeData.name]!.add(employeeData);
|
||||
}
|
||||
|
||||
final today = DateTime.now().day;
|
||||
|
||||
// Create data for each employee
|
||||
final employeeNames = {
|
||||
'maryam': chartDataEmployeeMaryam,
|
||||
'yasmine': chartDataEmployeeRawda,
|
||||
'mena': chartDataEmployeeMena,
|
||||
'ashjan': chartDataEmployeeSefer4,
|
||||
};
|
||||
|
||||
employeeNames.forEach((name, chartData) {
|
||||
var spots = <FlSpot>[];
|
||||
for (int day = 1; day <= today; day++) {
|
||||
spots.add(FlSpot(
|
||||
day.toDouble(),
|
||||
employeeDataMap[name]
|
||||
?.firstWhere(
|
||||
(e) => e.day == day,
|
||||
orElse: () => MonthlyEmployeeData(
|
||||
day: day,
|
||||
totalEmployees: 0,
|
||||
name: name,
|
||||
),
|
||||
)
|
||||
.totalEmployees
|
||||
.toDouble() ??
|
||||
0,
|
||||
));
|
||||
}
|
||||
|
||||
// Explicitly cast to List<FlSpot>
|
||||
if (name == 'maryam')
|
||||
chartDataEmployeeMaryam = List<FlSpot>.from(spots);
|
||||
if (name == 'yasmine')
|
||||
chartDataEmployeeRawda = List<FlSpot>.from(spots);
|
||||
if (name == 'mena') chartDataEmployeeMena = List<FlSpot>.from(spots);
|
||||
if (name == 'ashjan')
|
||||
chartDataEmployeeSefer4 = List<FlSpot>.from(spots);
|
||||
});
|
||||
} catch (e) {
|
||||
Log.print('Error in fetchEmployee: $e');
|
||||
// Set empty FlSpot lists in case of error
|
||||
chartDataEmployeeMaryam = <FlSpot>[];
|
||||
chartDataEmployeeRawda = <FlSpot>[];
|
||||
chartDataEmployeeMena = <FlSpot>[];
|
||||
chartDataEmployeeSefer4 = <FlSpot>[];
|
||||
totalMonthlyRides = '0';
|
||||
} finally {
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchDrivers() async {
|
||||
isLoading = true;
|
||||
update(); // Notify the observers about the loading state change
|
||||
|
||||
var res = await CRUD().get(
|
||||
link: AppLink.getdriverstotalMonthly,
|
||||
payload: {},
|
||||
);
|
||||
jsonData2 = jsonDecode(res);
|
||||
var jsonResponse = jsonDecode(res) as Map<String, dynamic>;
|
||||
isLoading = false;
|
||||
final List<dynamic> jsonData = jsonResponse['message'];
|
||||
staticList = jsonData;
|
||||
totalMonthlyDrivers = jsonData[0]['totalDrivers'].toString();
|
||||
driversData = jsonData.map<MonthlyDriverInstall>((item) {
|
||||
return MonthlyDriverInstall.fromJson(item);
|
||||
}).toList();
|
||||
final List<FlSpot> spots = driversData
|
||||
.map((data) => FlSpot(
|
||||
data.day.toDouble(),
|
||||
data.dailyTotalDrivers.toDouble(),
|
||||
))
|
||||
.toList();
|
||||
chartDataDrivers = spots;
|
||||
final List<FlSpot> spotsCalling = driversData
|
||||
.map((data) => FlSpot(
|
||||
data.day.toDouble(),
|
||||
data.dailyTotalCallingDrivers.toDouble(),
|
||||
))
|
||||
.toList();
|
||||
chartDataDriversCalling = spotsCalling;
|
||||
final List<FlSpot> spotsTotalMatchingNotes = driversData
|
||||
.map((data) => FlSpot(
|
||||
data.day.toDouble(),
|
||||
data.dailyMatchingNotes.toDouble(),
|
||||
))
|
||||
.toList();
|
||||
chartDataDriversMatchingNotes = spotsTotalMatchingNotes;
|
||||
|
||||
update(); // Notify the observers about the data and loading state change
|
||||
}
|
||||
|
||||
Future getAll() async {
|
||||
await fetch();
|
||||
await fetchRides();
|
||||
await fetchDrivers();
|
||||
await fetchEmployee();
|
||||
}
|
||||
}
|
||||
195
lib/controller/admin/wallet_admin_controller.dart
Normal file
195
lib/controller/admin/wallet_admin_controller.dart
Normal file
@@ -0,0 +1,195 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class WalletAdminController extends GetxController {
|
||||
bool isLoading = false;
|
||||
|
||||
late Map<String, dynamic> jsonResponse;
|
||||
List<dynamic> walletDetails = [];
|
||||
List driversWalletPoints = [];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getWalletForEachDriverToPay();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future getWalletAdminDash() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
var res = await CRUD().get(link: AppLink.getRidesPerMonth, payload: {});
|
||||
jsonResponse = jsonDecode(res);
|
||||
}
|
||||
|
||||
Future payToBankDriverAll() async {
|
||||
for (var i = 0; i < driversWalletPoints.length; i++) {
|
||||
String token = await getToken();
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
try {
|
||||
await payToDriverBankAccount(
|
||||
token,
|
||||
driversWalletPoints[i]['total_amount'].toString(),
|
||||
driversWalletPoints[i]['accountBank'].toString(),
|
||||
driversWalletPoints[i]['bankCode'].toString(),
|
||||
driversWalletPoints[i]['name_arabic'].toString(),
|
||||
driversWalletPoints[i]['driverID'].toString(),
|
||||
driversWalletPoints[i]['phone'].toString(),
|
||||
driversWalletPoints[i]['email'].toString(),
|
||||
);
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
} on FormatException catch (e) {
|
||||
// Handle the error or rethrow the exception as needed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> payToDriverBankAccount(
|
||||
String token,
|
||||
String amount,
|
||||
String bankCardNumber,
|
||||
String bankCode,
|
||||
String name,
|
||||
String driverId,
|
||||
String phone,
|
||||
String email) async {
|
||||
var headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
var body = jsonEncode({
|
||||
"issuer": "bank_card",
|
||||
"amount": amount,
|
||||
"full_name": name,
|
||||
"bank_card_number": bankCardNumber,
|
||||
"bank_code": bankCode,
|
||||
"bank_transaction_type": "cash_transfer"
|
||||
});
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(
|
||||
'https://stagingpayouts.paymobsolutions.com/api/secure/disburse/'),
|
||||
headers: headers,
|
||||
body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var d = jsonDecode(response.body);
|
||||
|
||||
if (d['status_description'] ==
|
||||
"Transaction received and validated successfully. Dispatched for being processed by the bank") {
|
||||
await addPayment('payFromSeferToDriver', driverId,
|
||||
((-1) * double.parse(amount)).toString());
|
||||
await addSeferWallet('payFromSeferToDriver', driverId,
|
||||
((-1) * double.parse(amount)).toString());
|
||||
await updatePaymentToPaid(driverId);
|
||||
await sendEmail(driverId, amount, phone, name, bankCardNumber, email);
|
||||
}
|
||||
} else {}
|
||||
}
|
||||
|
||||
// String paymentToken = '';
|
||||
Future<String> generateToken(String amount) async {
|
||||
var res = await CRUD().post(link: AppLink.addPaymentTokenDriver, payload: {
|
||||
'driverID': box.read(BoxName.driverID).toString(),
|
||||
'amount': amount.toString(),
|
||||
});
|
||||
var d = jsonDecode(res);
|
||||
return d['message'];
|
||||
}
|
||||
|
||||
Future sendEmail(
|
||||
String driverId, amount, phone, name, bankCardNumber, email) async {
|
||||
await CRUD().sendEmail(AppLink.sendEmailToDrivertransaction, {
|
||||
"driverID": driverId,
|
||||
"total_amount": amount,
|
||||
"phone": phone,
|
||||
"name_arabic": name,
|
||||
"accountBank": bankCardNumber,
|
||||
"email": email
|
||||
});
|
||||
}
|
||||
|
||||
Future addSeferWallet(
|
||||
String paymentMethod, String driverID, String point) async {
|
||||
var seferToken = await generateToken(point.toString());
|
||||
await CRUD().post(link: AppLink.addSeferWallet, payload: {
|
||||
'amount': point.toString(),
|
||||
'paymentMethod': paymentMethod,
|
||||
'passengerId': 'driver',
|
||||
'token': seferToken,
|
||||
'driverId': driverID.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
Future addPayment(
|
||||
String paymentMethod, String driverID, String amount) async {
|
||||
var paymentToken =
|
||||
await generateToken(((double.parse(amount))).toStringAsFixed(0));
|
||||
await CRUD().post(link: AppLink.addDrivePayment, payload: {
|
||||
'rideId': DateTime.now().toIso8601String(),
|
||||
'amount': ((double.parse(amount))).toStringAsFixed(0),
|
||||
'payment_method': paymentMethod,
|
||||
'passengerID': 'myself',
|
||||
'token': paymentToken,
|
||||
'driverID': driverID.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
Future updatePaymentToPaid(String driverID) async {
|
||||
await CRUD().post(link: AppLink.updatePaymetToPaid, payload: {
|
||||
'driverID': driverID.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> getToken() async {
|
||||
var headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
// 'Cookie':
|
||||
// 'csrftoken=74iZJ8XYyuTm5WRq2W4tpWX5eqoJLZVK5QhuDrChWpDtzpgGA269bbCWuEcW85t4'
|
||||
};
|
||||
var body = {
|
||||
'grant_type': 'password',
|
||||
'username': AK.payMobOutUserName,
|
||||
'password': AK.payMobOutPassword,
|
||||
'client_id': AK.payMobOutClient_id,
|
||||
'client_secret': AK.payMobOutClientSecrret
|
||||
};
|
||||
var res = await http.post(
|
||||
Uri.parse(
|
||||
'https://stagingpayouts.paymobsolutions.com/api/secure/o/token/'),
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
String token = '';
|
||||
if (res.statusCode == 200) {
|
||||
var decode = jsonDecode(res.body);
|
||||
token = decode['access_token'];
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
Future getWalletForEachDriverToPay() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
var res = await CRUD()
|
||||
.postWallet(link: AppLink.getVisaForEachDriver, payload: {});
|
||||
var d = (res);
|
||||
if (d != 'failure') {
|
||||
driversWalletPoints = d['message'];
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
driversWalletPoints = [];
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
56
lib/controller/auth/login_controller.dart
Normal file
56
lib/controller/auth/login_controller.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'otp_helper.dart';
|
||||
|
||||
class OtpVerificationAdmin extends StatefulWidget {
|
||||
final String phone;
|
||||
const OtpVerificationAdmin({required this.phone});
|
||||
|
||||
@override
|
||||
State<OtpVerificationAdmin> createState() => _OtpVerificationAdminState();
|
||||
}
|
||||
|
||||
class _OtpVerificationAdminState extends State<OtpVerificationAdmin> {
|
||||
final _otpController = TextEditingController();
|
||||
bool _isLoading = false;
|
||||
|
||||
Future<void> _verifyOtp() async {
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
final otpHelper = OtpHelper();
|
||||
await otpHelper.verifyOtp(widget.phone, _otpController.text.trim());
|
||||
// if (success) {
|
||||
// Get.offAllNamed('/admin-dashboard');
|
||||
// } else {
|
||||
// Get.snackbar('خطأ', 'رمز التحقق غير صحيح');
|
||||
// }
|
||||
setState(() => _isLoading = false);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('التحقق من الرمز')),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _otpController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(labelText: 'رمز التحقق'),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_isLoading
|
||||
? const CircularProgressIndicator()
|
||||
: ElevatedButton(
|
||||
onPressed: _verifyOtp,
|
||||
child: const Text('تحقق وأدخل'),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
114
lib/controller/auth/otp_helper.dart
Normal file
114
lib/controller/auth/otp_helper.dart
Normal file
@@ -0,0 +1,114 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/controller/functions/device_info.dart';
|
||||
import 'package:sefer_admin1/views/auth/login_page.dart';
|
||||
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
import '../../views/admin/admin_home_page.dart';
|
||||
import '../../views/widgets/snackbar.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class OtpHelper extends GetxController {
|
||||
static final String _sendOtpUrl =
|
||||
'${AppLink.server}/Admin/auth/send_otp_admin.php';
|
||||
static final String _verifyOtpUrl =
|
||||
'${AppLink.server}/Admin/auth/verify_otp_admin.php';
|
||||
static final String _checkAdminLogin =
|
||||
'${AppLink.server}/Admin/auth/login.php';
|
||||
|
||||
/// إرسال OTP
|
||||
static Future<bool> sendOtp(String phoneNumber) async {
|
||||
try {
|
||||
final response = await CRUD().post(
|
||||
link: _sendOtpUrl,
|
||||
payload: {'receiver': phoneNumber},
|
||||
);
|
||||
|
||||
if (response != 'failure') {
|
||||
mySnackeBarError('تم إرسال رمز التحقق إلى رقمك عبر WhatsApp');
|
||||
return true;
|
||||
} else {
|
||||
mySnackeBarError('حدث خطأ من الخادم. حاول مجددًا.');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print('OTP SEND ERROR: $e');
|
||||
mySnackeBarError('حدث خطأ أثناء الإرسال: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// التحقق من OTP
|
||||
Future<void> verifyOtp(String phoneNumber, String otp) async {
|
||||
try {
|
||||
final response = await CRUD().post(
|
||||
link: _verifyOtpUrl,
|
||||
payload: {
|
||||
'phone_number': phoneNumber,
|
||||
'otp': otp,
|
||||
'device_number': box.read(BoxName.fingerPrint)
|
||||
},
|
||||
);
|
||||
|
||||
if (response != 'failure') {
|
||||
if (response['status'] == 'success') {
|
||||
box.write(BoxName.phoneVerified, true);
|
||||
box.write(BoxName.adminPhone, phoneNumber);
|
||||
|
||||
mySnackbarSuccess('تم التحقق من الرقم بنجاح');
|
||||
await checkAdminLogin();
|
||||
} else {
|
||||
mySnackeBarError(response['message'] ?? 'فشل في التحقق.');
|
||||
}
|
||||
} else {
|
||||
mySnackeBarError('فشل من الخادم. حاول مرة أخرى.');
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print('OTP VERIFY ERROR: $e');
|
||||
mySnackeBarError('خطأ في التحقق: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkAdminLogin() async {
|
||||
final deviceNumber =
|
||||
box.read(BoxName.fingerPrint); // خزّنه عند التشغيل أول مرة
|
||||
final phoneNumber = box.read(BoxName.adminPhone); // عند التحقق من OTP
|
||||
|
||||
if (deviceNumber != null && phoneNumber != null) {
|
||||
final response = await CRUD().post(
|
||||
link: _checkAdminLogin,
|
||||
payload: {
|
||||
"device_number": deviceNumber,
|
||||
"phone_number": phoneNumber,
|
||||
},
|
||||
);
|
||||
|
||||
if (response != "failure") {
|
||||
Get.offAll(() => AdminHomePage());
|
||||
} else {
|
||||
Get.offAll(() => AdminLoginPage());
|
||||
}
|
||||
} else {
|
||||
Get.offAll(() => AdminLoginPage());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
DeviceHelper.getDeviceFingerprint().then((deviceFingerprint) {
|
||||
box.write(BoxName.fingerPrint, deviceFingerprint);
|
||||
});
|
||||
// تأجيل تنفيذ التنقل حتى تنتهي مرحلة البناء
|
||||
Future.microtask(() {
|
||||
if (box.read(BoxName.phoneVerified) == true &&
|
||||
box.read(BoxName.adminPhone) != null) {
|
||||
checkAdminLogin();
|
||||
} else {
|
||||
Get.offAll(() => AdminLoginPage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
113
lib/controller/bank_account/payout.dart
Normal file
113
lib/controller/bank_account/payout.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../constant/links.dart';
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../main.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class PaymobPayout extends GetxController {
|
||||
bool isLoading = false;
|
||||
String dropdownValue = 'etisalat';
|
||||
|
||||
Future<String> getToken() async {
|
||||
var headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
// 'Cookie':
|
||||
// 'csrftoken=74iZJ8XYyuTm5WRq2W4tpWX5eqoJLZVK5QhuDrChWpDtzpgGA269bbCWuEcW85t4'
|
||||
};
|
||||
var body = {
|
||||
'grant_type': 'password',
|
||||
'username': AK.payMobOutUserName,
|
||||
'password': AK.payMobOutPassword,
|
||||
'client_id': AK.payMobOutClient_id,
|
||||
'client_secret': AK.payMobOutClientSecrret
|
||||
};
|
||||
var res = await http.post(
|
||||
Uri.parse('https://payouts.paymobsolutions.com/api/secure/o/token/'),
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
String token = '';
|
||||
if (res.statusCode == 200) {
|
||||
var decode = jsonDecode(res.body);
|
||||
token = decode['access_token'];
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
payToDriverWallet(
|
||||
String token, String amount, String issuer, String msisdn) async {
|
||||
var headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
var body = json.encode({
|
||||
"amount": amount, //"10.00",
|
||||
"issuer": issuer, //"vodafone",
|
||||
"msisdn": msisdn, // "01023456789"
|
||||
});
|
||||
var res = await http.post(
|
||||
Uri.parse('https://payouts.paymobsolutions.com/api/secure/disburse/'),
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
var dec = jsonDecode(res.body);
|
||||
if (dec['disbursement_status'] == 'successful') {
|
||||
await CRUD().post(link: AppLink.addDriverpayment, payload: {
|
||||
'rideId': DateTime.now().toIso8601String(),
|
||||
'amount': ((-1) * (double.parse(dec['amount'])) + 5).toStringAsFixed(0),
|
||||
'payment_method': 'payout',
|
||||
'passengerID': 'admin',
|
||||
'driverID': box.read(BoxName.driverID).toString(),
|
||||
});
|
||||
Get.snackbar('Transaction successful'.tr,
|
||||
'${'Transaction successful'.tr} ${dec['amount']}',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
// Get.find<CaptainWalletController>().getCaptainWalletFromRide();
|
||||
} else if (dec['disbursement_status'] == 'failed') {
|
||||
Get.snackbar('Transaction failed'.tr, 'Transaction failed'.tr,
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
payToDriverBankAccount(String token, String amount, String bankCardNumber,
|
||||
String bankCode) async {
|
||||
var headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
var body = {
|
||||
"issuer": "bank_card",
|
||||
"amount": amount, //9.0,
|
||||
"full_name":
|
||||
'${box.read(BoxName.nameDriver)} ${box.read(BoxName.lastNameDriver)}',
|
||||
"bank_card_number": bankCardNumber, //"1111-2222-3333-4444",
|
||||
"bank_code": bankCode, //"CIB",
|
||||
"bank_transaction_type": "cash_transfer"
|
||||
};
|
||||
var res = await http
|
||||
.post(
|
||||
Uri.parse('https://payouts.paymobsolutions.com/api/secure/disburse/'),
|
||||
headers: headers,
|
||||
body: body,
|
||||
)
|
||||
.then((value) {});
|
||||
}
|
||||
|
||||
Future payToWalletDriverAll(
|
||||
String amount, String issuer, String msisdn) async {
|
||||
String token = await getToken();
|
||||
await payToDriverWallet(token, amount, issuer, msisdn);
|
||||
}
|
||||
|
||||
Future payToBankDriverAll(
|
||||
String amount, String bankCardNumber, String bankCode) async {
|
||||
String token = await getToken();
|
||||
await payToDriverBankAccount(token, amount, bankCardNumber, bankCode);
|
||||
}
|
||||
}
|
||||
68
lib/controller/drivers/driverthebest.dart
Normal file
68
lib/controller/drivers/driverthebest.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../functions/crud.dart';
|
||||
|
||||
class Driverthebest extends GetxController {
|
||||
bool isLoading = false;
|
||||
List driver = [];
|
||||
getBestDriver() async {
|
||||
var res = await CRUD().get(link: AppLink.getBestDriver, payload: {});
|
||||
if (res != 'failure') {
|
||||
driver = jsonDecode(res)['message'];
|
||||
update();
|
||||
} else {
|
||||
Get.snackbar('error', '', backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getBestDriver();
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
|
||||
class DriverTheBestGizaController extends GetxController {
|
||||
bool isLoading = false;
|
||||
List driver = [];
|
||||
getBestDriver() async {
|
||||
var res = await CRUD().get(link: AppLink.getBestDriverGiza, payload: {});
|
||||
if (res != 'failure') {
|
||||
driver = jsonDecode(res)['message'];
|
||||
update();
|
||||
} else {
|
||||
Get.snackbar('error', '', backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getBestDriver();
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
|
||||
class DriverTheBestAlexandriaController extends GetxController {
|
||||
bool isLoading = false;
|
||||
List driver = [];
|
||||
getBestDriver() async {
|
||||
var res =
|
||||
await CRUD().get(link: AppLink.getBestDriverAlexandria, payload: {});
|
||||
if (res != 'failure') {
|
||||
driver = jsonDecode(res)['message'];
|
||||
update();
|
||||
} else {
|
||||
Get.snackbar('error', '', backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getBestDriver();
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
76
lib/controller/employee_controller/employee_controller.dart
Normal file
76
lib/controller/employee_controller/employee_controller.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/colors.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
|
||||
class EmployeeController extends GetxController {
|
||||
List employee = [];
|
||||
final name = TextEditingController();
|
||||
final education = TextEditingController();
|
||||
final site = TextEditingController();
|
||||
final phone = TextEditingController();
|
||||
final status = TextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
fetchEmployee() async {
|
||||
var res = await CRUD().get(link: AppLink.getEmployee, payload: {});
|
||||
if (res != 'failure') {
|
||||
employee = jsonDecode(res)['message'];
|
||||
update();
|
||||
} else {
|
||||
Get.snackbar('error', '', backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
late String id;
|
||||
String generateRandomId(int length) {
|
||||
const String chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
Random random = Random();
|
||||
|
||||
return String.fromCharCodes(Iterable.generate(
|
||||
length,
|
||||
(_) => chars.codeUnitAt(random.nextInt(chars.length)),
|
||||
));
|
||||
}
|
||||
|
||||
addEmployee() async {
|
||||
// Create the payload with the employee data
|
||||
var res = await CRUD().post(link: AppLink.addEmployee, payload: {
|
||||
"id": id,
|
||||
"name": name.text,
|
||||
"education": education.text,
|
||||
"site": site.text,
|
||||
"phone": phone.text,
|
||||
"status": status.text,
|
||||
});
|
||||
|
||||
// Check the response from the API
|
||||
if (res != 'failure') {
|
||||
// You can handle the success case here, such as showing a success message
|
||||
|
||||
Get.back();
|
||||
Get.snackbar('Success', 'Employee added successfully',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
name.clear();
|
||||
education.clear();
|
||||
site.clear();
|
||||
phone.clear();
|
||||
status.clear();
|
||||
fetchEmployee();
|
||||
} else {
|
||||
// Handle the error case by showing a snackbar with an error message
|
||||
Get.snackbar('Error', 'Failed to add employee',
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
fetchEmployee();
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
517
lib/controller/firebase/firbase_messge.dart
Normal file
517
lib/controller/firebase/firbase_messge.dart
Normal file
@@ -0,0 +1,517 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
||||
import 'package:sefer_admin1/constant/info.dart';
|
||||
import 'package:sefer_admin1/env/env.dart';
|
||||
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/char_map.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
import '../../views/widgets/elevated_btn.dart';
|
||||
import '../functions/encrypt_decrypt.dart';
|
||||
import '../notification_controller.dart';
|
||||
import 'local_notification.dart';
|
||||
import 'token_access.dart';
|
||||
|
||||
class FirebaseMessagesController extends GetxController {
|
||||
final fcmToken = FirebaseMessaging.instance;
|
||||
|
||||
List<String> tokens = [];
|
||||
List<String> tokensPassengers = [];
|
||||
List dataTokens = [];
|
||||
List dataTokensPassenger = [];
|
||||
late String driverID;
|
||||
late String driverToken;
|
||||
NotificationSettings? notificationSettings;
|
||||
bool isLoading = false;
|
||||
Future<void> getNotificationSettings() async {
|
||||
// Get the current notification settings
|
||||
NotificationSettings? notificationSettings =
|
||||
await FirebaseMessaging.instance.getNotificationSettings();
|
||||
'Notification authorization status: ${notificationSettings.authorizationStatus}';
|
||||
|
||||
// Call the update function if needed
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> requestFirebaseMessagingPermission() async {
|
||||
FirebaseMessaging messaging = FirebaseMessaging.instance;
|
||||
|
||||
// Check if the platform is Android
|
||||
if (Platform.isAndroid) {
|
||||
// Request permission for Android
|
||||
await messaging.requestPermission();
|
||||
} else if (Platform.isIOS) {
|
||||
// Request permission for iOS
|
||||
NotificationSettings settings = await messaging.requestPermission(
|
||||
alert: true,
|
||||
announcement: true,
|
||||
badge: true,
|
||||
carPlay: true,
|
||||
criticalAlert: true,
|
||||
provisional: false,
|
||||
sound: true,
|
||||
);
|
||||
messaging.setForegroundNotificationPresentationOptions(
|
||||
alert: true, badge: true, sound: true);
|
||||
}
|
||||
}
|
||||
|
||||
Future getTokens() async {
|
||||
var res = await http.post(
|
||||
Uri.parse(AppLink.getTokens),
|
||||
headers: {
|
||||
'Authorization':
|
||||
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
|
||||
},
|
||||
body: {},
|
||||
);
|
||||
var jsonResponse = jsonDecode(res.body);
|
||||
if (jsonResponse['status'] == 'success') {
|
||||
dataTokens = jsonResponse['data'];
|
||||
for (var i = 0; i < dataTokens.length; i++) {
|
||||
tokens.add(jsonResponse['data'][i]['token']);
|
||||
}
|
||||
box.write(BoxName.tokens, tokens);
|
||||
} else {
|
||||
Get.defaultDialog(title: "Warning", middleText: "Server Error");
|
||||
}
|
||||
}
|
||||
|
||||
var currentPage = 1;
|
||||
var totalPages = 1;
|
||||
Future<void> getAllTokenDrivers() async {
|
||||
isLoading = true;
|
||||
try {
|
||||
var res = await http.post(
|
||||
Uri.parse(AppLink.getDriversPhonesAndTokens),
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
'Authorization':
|
||||
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
||||
// 'Authorization': 'Bearer ${box.read(BoxName.jwt)}'
|
||||
},
|
||||
body: {
|
||||
// 'page': page.toString(),
|
||||
},
|
||||
);
|
||||
|
||||
var jsonResponse = jsonDecode(res.body);
|
||||
Log.print('jsonResponse: ${jsonResponse}');
|
||||
if (jsonResponse['status'] == 'success') {
|
||||
// var newData = jsonResponse['data'] as List;
|
||||
// Log.print('newData: ${newData}');
|
||||
// // if (page == 1) {
|
||||
// // dataTokens.clear();
|
||||
// // tokens.clear();
|
||||
// // }
|
||||
// dataTokens.addAll(newData);
|
||||
// for (var item in newData) {
|
||||
// tokens.add(item['token']);
|
||||
// }
|
||||
// currentPage = int.parse(jsonResponse['currentPage']);
|
||||
// totalPages = jsonResponse['totalPages'];
|
||||
box.write(BoxName.tokensDrivers, jsonResponse);
|
||||
Log.print(
|
||||
'box.write(BoxName.tokensDrivers: ${box.read(BoxName.tokensDrivers)}');
|
||||
} else {
|
||||
Get.defaultDialog(
|
||||
title: "Warning", middleText: "No more data available");
|
||||
}
|
||||
} catch (e) {
|
||||
Get.defaultDialog(title: "Error", middleText: "Server Error: $e");
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
var currentPagePassenger = 1;
|
||||
var totalPagesPassenger = 1;
|
||||
Future<void> getAllTokenPassenger({int page = 1}) async {
|
||||
isLoading = true;
|
||||
try {
|
||||
var res = await http.post(
|
||||
Uri.parse(AppLink.getAllTokenPassengers),
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
'Authorization':
|
||||
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
||||
},
|
||||
body: {},
|
||||
);
|
||||
|
||||
var jsonResponse = jsonDecode(res.body);
|
||||
if (jsonResponse['status'] == 'success') {
|
||||
box.write(BoxName.tokensPassengers, jsonResponse);
|
||||
Log.print(
|
||||
'box.write(BoxName.tokensPassenger: ${box.read(BoxName.tokensPassengers)}');
|
||||
} else {
|
||||
Get.defaultDialog(
|
||||
title: "Warning", middleText: "No more data available");
|
||||
}
|
||||
} catch (e) {
|
||||
Get.defaultDialog(title: "Error", middleText: "Server Error: $e");
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isSendingNotifications = false;
|
||||
Future<void> loadAllPagesAndSendNotifications() async {
|
||||
isSendingNotifications = true;
|
||||
// currentPage = 1;
|
||||
|
||||
// while (currentPage <= totalPages) {
|
||||
// await getAllTokenDrivers(page: currentPage);
|
||||
await getAllTokenDrivers();
|
||||
// Log.print('tokens: ${tokens}');
|
||||
await NotificationController().sendNotificationDrivers();
|
||||
// print(tokens);
|
||||
|
||||
// if (currentPage < totalPages) {
|
||||
// await Future.delayed(const Duration(seconds: 3));
|
||||
// }
|
||||
// currentPage++;
|
||||
// }
|
||||
|
||||
isSendingNotifications = false;
|
||||
Get.snackbar("Success", "All notifications sent!");
|
||||
}
|
||||
|
||||
bool isSendingNotificationsPassenger = false;
|
||||
Future<void> loadAllPagesAndSendNotificationsPassengers() async {
|
||||
isSendingNotificationsPassenger = true;
|
||||
currentPage = 1;
|
||||
|
||||
// while (currentPagePassenger <= totalPagesPassenger) {
|
||||
await getAllTokenPassenger();
|
||||
await NotificationController().sendNotificationPassengers();
|
||||
// print(tokensPassengers);
|
||||
// if (currentPagePassenger < totalPagesPassenger) {
|
||||
// await Future.delayed(const Duration(seconds: 3));
|
||||
// }
|
||||
// currentPagePassenger++;
|
||||
// }
|
||||
|
||||
isSendingNotificationsPassenger = false;
|
||||
Get.snackbar("Success", "All notifications sent!");
|
||||
}
|
||||
|
||||
Future getAllTokenPassengers() async {
|
||||
var res = await http.post(
|
||||
Uri.parse(AppLink.getAllTokenPassengers),
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
'Authorization':
|
||||
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
||||
// 'Authorization': 'Bearer ${box.read(BoxName.jwt)}'
|
||||
},
|
||||
body: {},
|
||||
);
|
||||
var jsonResponse = jsonDecode(res.body);
|
||||
if (jsonResponse['status'] == 'success') {
|
||||
dataTokens = jsonResponse['data'];
|
||||
for (var i = 0; i < dataTokens.length; i++) {
|
||||
tokensPassengers.add(jsonResponse['data'][i]['token']);
|
||||
}
|
||||
box.write(BoxName.tokensPassengers, jsonResponse['data']);
|
||||
} else {
|
||||
Get.defaultDialog(title: "Warning", middleText: "Server Error");
|
||||
}
|
||||
}
|
||||
|
||||
Future getToken() async {
|
||||
fcmToken.getToken().then((token) {
|
||||
if (box.read(BoxName.email) == null) {
|
||||
box.write(BoxName.tokenDriver, token);
|
||||
} else {
|
||||
box.write(BoxName.tokenFCM, token);
|
||||
}
|
||||
});
|
||||
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||
// If the app is in the background or terminated, show a system tray message
|
||||
RemoteNotification? notification = message.notification;
|
||||
AndroidNotification? android = notification?.android;
|
||||
// if (notification != null && android != null) {
|
||||
if (message.data.isNotEmpty && message.notification != null) {
|
||||
fireBaseTitles(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void fireBaseTitles(RemoteMessage message) {
|
||||
if (message.notification!.title! == 'Order') {
|
||||
if (Platform.isAndroid) {
|
||||
// NotificationController().showNotification('Order', '', 'order');
|
||||
}
|
||||
var myListString = message.data['DriverList'];
|
||||
// var points = message.data['PolylineJson'];
|
||||
|
||||
var myList = jsonDecode(myListString) as List<dynamic>;
|
||||
// var myPoints = jsonDecode(points) as List<dynamic>;
|
||||
driverToken = myList[14].toString();
|
||||
// This is for location using and uploading status
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
SnackbarController driverAppliedTripSnakBar() {
|
||||
return Get.snackbar(
|
||||
'Driver Applied the Ride for You'.tr,
|
||||
'',
|
||||
colorText: AppColor.greenColor,
|
||||
duration: const Duration(seconds: 3),
|
||||
snackPosition: SnackPosition.TOP,
|
||||
titleText: Text(
|
||||
'Applied'.tr,
|
||||
style: const TextStyle(color: AppColor.redColor),
|
||||
),
|
||||
messageText: Text(
|
||||
'Driver Applied the Ride for You'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
icon: const Icon(Icons.approval),
|
||||
shouldIconPulse: true,
|
||||
margin: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
);
|
||||
}
|
||||
|
||||
Future<dynamic> passengerDialog(String message) {
|
||||
return Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: 'message From passenger'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
middleTextStyle: AppStyle.title,
|
||||
middleText: message.tr,
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () {
|
||||
// FirebaseMessagesController().sendNotificationToPassengerToken(
|
||||
// 'Hi ,I will go now'.tr,
|
||||
// 'I will go now'.tr,
|
||||
// Get.find<MapPassengerController>().driverToken, []);
|
||||
// Get.find<MapPassengerController>()
|
||||
// .startTimerDriverWaitPassenger5Minute();
|
||||
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
|
||||
// Future<dynamic> driverFinishTripDialoge(List<dynamic> driverList) {
|
||||
// return Get.defaultDialog(
|
||||
// title: 'Driver Finish Trip'.tr,
|
||||
// content: const DriverTipWidget(),
|
||||
// confirm: MyElevatedButton(
|
||||
// title: 'Yes'.tr,
|
||||
// onPressed: () async {
|
||||
// var tip = (Get.find<MapPassengerController>().totalPassenger) *
|
||||
// (double.parse(box.read(BoxName.tipPercentage.toString())));
|
||||
// var res = await CRUD().post(link: AppLink.addTips, payload: {
|
||||
// 'passengerID': box.read(BoxName.passengerID),
|
||||
// 'driverID': driverList[0].toString(),
|
||||
// 'rideID': driverList[1].toString(),
|
||||
// 'tipAmount': tip.toString(),
|
||||
// });
|
||||
// await CRUD().post(link: AppLink.addPassengersWallet, payload: {
|
||||
// 'passenger_id': box.read(BoxName.passengerID).toString(),
|
||||
// 'balance': ((-1) * tip).toString()
|
||||
// });
|
||||
|
||||
// await CRUD().post(link: AppLink.addDriversWalletPoints, payload: {
|
||||
// 'driverID': driverList[0].toString(),
|
||||
// 'paymentID': '${Get.find<MapPassengerController>().rideId}tip',
|
||||
// 'amount': (tip * 100).toString(),
|
||||
// 'paymentMethod': 'visa-tip',
|
||||
// });
|
||||
|
||||
// if (res != 'failure') {
|
||||
// FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
||||
// 'You Have Tips',
|
||||
// '${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + (Get.find<MapPassengerController>().totalPassenger)}',
|
||||
// driverList[2].toString(),
|
||||
// );
|
||||
// }
|
||||
// Get.to(() => RateDriverFromPassenger(), arguments: {
|
||||
// 'driverId': driverList[0].toString(),
|
||||
// 'rideId': driverList[1].toString(),
|
||||
// 'price': driverList[3].toString()
|
||||
// });
|
||||
// },
|
||||
// kolor: AppColor.greenColor,
|
||||
// ),
|
||||
// cancel: MyElevatedButton(
|
||||
// title: 'No,I want'.tr,
|
||||
// onPressed: () {
|
||||
// Get.to(() => RateDriverFromPassenger(), arguments: {
|
||||
// 'driverId': driverList[0].toString(),
|
||||
// 'rideId': driverList[1].toString(),
|
||||
// 'price': driverList[3].toString()
|
||||
// });
|
||||
// },
|
||||
// kolor: AppColor.redColor,
|
||||
// ));
|
||||
// }
|
||||
|
||||
void sendNotificationAll(String title, body) async {
|
||||
// Get the token you want to subtract.
|
||||
String token = box.read(BoxName.tokenFCM);
|
||||
tokens = box.read(BoxName.tokens);
|
||||
// Subtract the token from the list of tokens.
|
||||
tokens.remove(token);
|
||||
|
||||
// Save the list of tokens back to the box.
|
||||
// box.write(BoxName.tokens, tokens);
|
||||
tokens = box.read(BoxName.tokens);
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
String serviceAccountKeyJson = '''{
|
||||
"type": "service_account",
|
||||
"project_id": "ride-b1bd8",
|
||||
"private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n",
|
||||
"client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com",
|
||||
"client_id": "111210077025005706623",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
||||
'''; // As defined above
|
||||
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
|
||||
// Send the notification
|
||||
final response = await http
|
||||
.post(
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'notification': <String, dynamic>{
|
||||
'title': title,
|
||||
'body': body,
|
||||
'sound': 'ding.wav'
|
||||
},
|
||||
'priority': 'high',
|
||||
'data': <String, dynamic>{
|
||||
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
|
||||
'id': '1',
|
||||
'status': 'done'
|
||||
},
|
||||
'to': tokens[i],
|
||||
}))
|
||||
.whenComplete(() {})
|
||||
.catchError((e) {});
|
||||
}
|
||||
}
|
||||
|
||||
// for (var i = 0; i < tokens.length; i++) {
|
||||
// http
|
||||
// .post(Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
||||
// headers: <String, String>{
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': 'key=${storage.read(key: BoxName.serverAPI}'
|
||||
// },
|
||||
// body: jsonEncode({
|
||||
// 'notification': <String, dynamic>{
|
||||
// 'title': title,
|
||||
// 'body': body,
|
||||
// 'sound': 'true'
|
||||
// },
|
||||
// 'priority': 'high',
|
||||
// 'data': <String, dynamic>{
|
||||
// 'click_action': 'FLUTTER_NOTIFICATION_CLICK',
|
||||
// 'id': '1',
|
||||
// 'status': 'done'
|
||||
// },
|
||||
// 'to': tokens[i],
|
||||
// }))
|
||||
// .whenComplete(() {})
|
||||
// .catchError((e) {
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//android/app/src/main/res/raw/iphone_ringtone.wav
|
||||
|
||||
late String serviceAccountKeyJson;
|
||||
void sendNotificationToAnyWithoutData(
|
||||
String title, String body, String token, String tone) async {
|
||||
try {
|
||||
var encryptedKey = Env.privateKeyFCM;
|
||||
// Log.print('encryptedKey: ${encryptedKey}');
|
||||
serviceAccountKeyJson =
|
||||
EncryptionHelper.instance.decryptData(encryptedKey);
|
||||
// As defined above
|
||||
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
// Log.print('accessToken: ${accessToken}');
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/intaleq-d48a7/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'message': {
|
||||
'token': token,
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': body,
|
||||
},
|
||||
'android': {
|
||||
'notification': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
'apns': {
|
||||
'payload': {
|
||||
'aps': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
SnackBar(content: Text('${response.statusCode}'));
|
||||
print(
|
||||
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
} else {
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error sending notification: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
29
lib/controller/firebase/local_notification.dart
Normal file
29
lib/controller/firebase/local_notification.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
// import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
// import 'package:get/get.dart';
|
||||
|
||||
// class NotificationController extends GetxController {
|
||||
// final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
|
||||
// FlutterLocalNotificationsPlugin();
|
||||
|
||||
// // Initializes the local notifications plugin
|
||||
// Future<void> initNotifications() async {
|
||||
// const AndroidInitializationSettings android =
|
||||
// AndroidInitializationSettings('@mipmap/launcher_icon');
|
||||
// const InitializationSettings initializationSettings =
|
||||
// InitializationSettings(android: android);
|
||||
// await _flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
||||
// }
|
||||
|
||||
// // Displays a notification with the given title and message
|
||||
// void showNotification(String title, String message, String tone) async {
|
||||
// AndroidNotificationDetails android = AndroidNotificationDetails(
|
||||
// 'your channel id', 'your channel name',
|
||||
// importance: Importance.max,
|
||||
// priority: Priority.high,
|
||||
// showWhen: false,
|
||||
// sound: RawResourceAndroidNotificationSound(tone));
|
||||
|
||||
// NotificationDetails details = NotificationDetails(android: android);
|
||||
// await _flutterLocalNotificationsPlugin.show(0, title, message, details);
|
||||
// }
|
||||
// }
|
||||
53
lib/controller/firebase/token_access.dart
Normal file
53
lib/controller/firebase/token_access.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
import 'dart:convert';
|
||||
import 'package:googleapis_auth/auth_io.dart';
|
||||
|
||||
import '../../print.dart';
|
||||
|
||||
class AccessTokenManager {
|
||||
static final AccessTokenManager _instance = AccessTokenManager._internal();
|
||||
late final String serviceAccountJsonKey;
|
||||
AccessToken? _accessToken;
|
||||
DateTime? _expiryDate;
|
||||
|
||||
AccessTokenManager._internal();
|
||||
|
||||
factory AccessTokenManager(String jsonKey) {
|
||||
if (_instance._isServiceAccountKeyInitialized()) {
|
||||
// Prevent re-initialization
|
||||
return _instance;
|
||||
}
|
||||
_instance.serviceAccountJsonKey = jsonKey;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
bool _isServiceAccountKeyInitialized() {
|
||||
try {
|
||||
serviceAccountJsonKey; // Access to check if initialized
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getAccessToken() async {
|
||||
if (_accessToken != null && DateTime.now().isBefore(_expiryDate!)) {
|
||||
return _accessToken!.data;
|
||||
}
|
||||
try {
|
||||
final serviceAccountCredentials = ServiceAccountCredentials.fromJson(
|
||||
json.decode(serviceAccountJsonKey));
|
||||
final client = await clientViaServiceAccount(
|
||||
serviceAccountCredentials,
|
||||
['https://www.googleapis.com/auth/firebase.messaging'],
|
||||
);
|
||||
|
||||
_accessToken = client.credentials.accessToken;
|
||||
_expiryDate = client.credentials.accessToken.expiry;
|
||||
client.close();
|
||||
Log.print('_accessToken!.data: ${_accessToken!.data}');
|
||||
return _accessToken!.data;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to obtain access token');
|
||||
}
|
||||
}
|
||||
}
|
||||
2093
lib/controller/functions/crud.dart
Normal file
2093
lib/controller/functions/crud.dart
Normal file
File diff suppressed because it is too large
Load Diff
26
lib/controller/functions/custom_pant.dart
Normal file
26
lib/controller/functions/custom_pant.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LineChartPainter extends CustomPainter {
|
||||
final List<double> data;
|
||||
|
||||
LineChartPainter(this.data);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
// Calculate the scale factor.
|
||||
final scaleFactor = size.height / 240;
|
||||
|
||||
// Draw the line chart.
|
||||
for (var i = 0; i < data.length - 1; i++) {
|
||||
final x1 = i * size.width / data.length;
|
||||
final y1 = data[i] * scaleFactor;
|
||||
final x2 = (i + 1) * size.width / data.length;
|
||||
final y2 = data[i + 1] * scaleFactor;
|
||||
|
||||
canvas.drawLine(Offset(x1, y1), Offset(x2, y2), Paint());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(LineChartPainter oldDelegate) => false;
|
||||
}
|
||||
295
lib/controller/functions/device_info.dart
Normal file
295
lib/controller/functions/device_info.dart
Normal file
@@ -0,0 +1,295 @@
|
||||
// import 'dart:io';
|
||||
|
||||
// import 'package:device_info_plus/device_info_plus.dart';
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import '../../main.dart';
|
||||
|
||||
class DeviceHelper {
|
||||
static Future<String> getDeviceFingerprint() async {
|
||||
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
|
||||
var deviceData;
|
||||
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
// Fetch Android-specific device information
|
||||
AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
|
||||
deviceData = androidInfo.toMap(); // Convert to a map for easier access
|
||||
// Log.print('deviceData: ${jsonEncode(deviceData)}');
|
||||
} else if (Platform.isIOS) {
|
||||
// Fetch iOS-specific device information
|
||||
IosDeviceInfo iosInfo = await deviceInfoPlugin.iosInfo;
|
||||
deviceData = iosInfo.toMap(); // Convert to a map for easier access
|
||||
} else {
|
||||
throw UnsupportedError('Unsupported platform');
|
||||
}
|
||||
|
||||
// Extract relevant device information
|
||||
final String deviceId = Platform.isAndroid
|
||||
? deviceData['androidId'] ?? deviceData['serialNumber'] ?? 'unknown'
|
||||
: deviceData['identifierForVendor'] ?? 'unknown';
|
||||
|
||||
final String deviceModel = deviceData['model'] ?? 'unknown';
|
||||
final String osVersion = Platform.isAndroid
|
||||
? deviceData['version']['release'] ?? 'unknown'
|
||||
: deviceData['systemVersion'] ?? 'unknown';
|
||||
|
||||
// Log the extracted information
|
||||
|
||||
// Generate and return the encrypted fingerprint
|
||||
final String fingerprint = '${deviceId}_${deviceModel}_$osVersion';
|
||||
// print(EncryptionHelper.instance.encryptData(fingerprint));
|
||||
return (fingerprint);
|
||||
} catch (e) {
|
||||
throw Exception('Failed to generate device fingerprint');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// class SecurityHelper {
|
||||
// /// Performs security checks and handles potential risks
|
||||
// static Future<void> performSecurityChecks() async {
|
||||
// bool isNotTrust = false;
|
||||
// bool isJailBroken = false;
|
||||
// bool isRealDevice = true;
|
||||
// bool isOnExternalStorage = false;
|
||||
// bool checkForIssues = false;
|
||||
// bool isDevMode = false;
|
||||
// bool isTampered = false;
|
||||
// String bundleId = "";
|
||||
|
||||
// try {
|
||||
// isNotTrust = await JailbreakRootDetection.instance.isNotTrust;
|
||||
// isJailBroken = await JailbreakRootDetection.instance.isJailBroken;
|
||||
// isRealDevice = await JailbreakRootDetection.instance.isRealDevice;
|
||||
// isOnExternalStorage =
|
||||
// await JailbreakRootDetection.instance.isOnExternalStorage;
|
||||
|
||||
// List<JailbreakIssue> issues =
|
||||
// await JailbreakRootDetection.instance.checkForIssues;
|
||||
// checkForIssues = issues.isNotEmpty;
|
||||
|
||||
// isDevMode = await JailbreakRootDetection.instance.isDevMode;
|
||||
|
||||
// // Get Bundle ID
|
||||
// PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
// bundleId = packageInfo.packageName;
|
||||
// if (bundleId.isNotEmpty) {
|
||||
// // Pass the CORRECT bundle ID to isTampered
|
||||
// isTampered = await JailbreakRootDetection.instance.isTampered(bundleId);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// debugPrint("Error during security checks: $e");
|
||||
// // Consider handling specific exceptions, not just general errors.
|
||||
// }
|
||||
|
||||
// // Save values to storage (using GetStorage)
|
||||
// await box.write('isNotTrust', isNotTrust); // Use await for write operations
|
||||
// await box.write('isTampered', isTampered); // Use await
|
||||
// await box.write('isJailBroken', isJailBroken); // Use await
|
||||
|
||||
// // debugPrint("Security Check Results:");
|
||||
// // debugPrint("isNotTrust: $isNotTrust");
|
||||
// // debugPrint("isJailBroken: $isJailBroken");
|
||||
// // debugPrint("isRealDevice: $isRealDevice");
|
||||
// // debugPrint("isOnExternalStorage: $isOnExternalStorage");
|
||||
// // debugPrint("checkForIssues: $checkForIssues");
|
||||
// // debugPrint("isDevMode: $isDevMode");
|
||||
// // debugPrint("isTampered: $isTampered");
|
||||
// // debugPrint("Bundle ID: $bundleId"); // Print the bundle ID
|
||||
|
||||
// // Check for security risks and potentially show a warning
|
||||
// if (isJailBroken || isRealDevice == false || isTampered) {
|
||||
// // print("security_warning".tr); //using easy_localization
|
||||
// // Use a more robust approach to show a warning, like a dialog:
|
||||
// _showSecurityWarning();
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Deletes all app data
|
||||
// static Future<void> clearAllData() async {
|
||||
// //await storage.deleteAll(); // What's 'storage'? Be specific. Likely GetStorage as well.
|
||||
// await box.erase(); // Clear GetStorage data
|
||||
// exit(0); // This will terminate the app. Be VERY careful with this.
|
||||
// }
|
||||
|
||||
// // static void _showSecurityWarning() {
|
||||
// // // Show a dialog, navigate to an error screen, etc.
|
||||
// // // Example using Get.dialog (if you use GetX):
|
||||
// //
|
||||
// // Get.dialog(
|
||||
// // AlertDialog(
|
||||
// // title: Text("Security Warning".tr), // Or use localized string
|
||||
// // content: Text(
|
||||
// // "Potential security risks detected. The application may not function correctly."
|
||||
// // .tr), //Or use localized string
|
||||
// // actions: [
|
||||
// // TextButton(
|
||||
// // onPressed: () async {
|
||||
// // await storage.deleteAll();
|
||||
// // await box.erase();
|
||||
// // Get.back(); // Close the dialog
|
||||
// // // Or, if you really must, exit the app (but give the user a chance!)
|
||||
// // exit(0);
|
||||
// // },
|
||||
// // child: Text("OK"), // Or use a localized string
|
||||
// // ),
|
||||
// // ],
|
||||
// // ),
|
||||
// // barrierDismissible: false, // Prevent closing by tapping outside
|
||||
// // );
|
||||
// // }
|
||||
// static void _showSecurityWarning() {
|
||||
// // Use an RxInt to track the remaining seconds. This is the KEY!
|
||||
// RxInt secondsRemaining = 10.obs;
|
||||
|
||||
// Get.dialog(
|
||||
// CupertinoAlertDialog(
|
||||
// title: Text("Security Warning".tr),
|
||||
// content: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Obx(() => Text(
|
||||
// "Potential security risks detected. The application will close in @seconds seconds."
|
||||
// .trParams({
|
||||
// // Use trParams for placeholders
|
||||
// 'seconds': secondsRemaining.value.toString(),
|
||||
// }),
|
||||
// // Wrap the Text widget in Obx
|
||||
// )),
|
||||
// SizedBox(height: 24), // More spacing before the progress bar
|
||||
// Obx(() => SizedBox(
|
||||
// width: double.infinity, // Make progress bar full width
|
||||
// child: CupertinoActivityIndicator(
|
||||
// // in case of loading
|
||||
// radius: 15,
|
||||
// animating: true,
|
||||
// ))),
|
||||
// SizedBox(height: 8),
|
||||
// Obx(() => ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(8), // Rounded corners
|
||||
// child: LinearProgressIndicator(
|
||||
// value: secondsRemaining.value / 10,
|
||||
// backgroundColor: Colors.grey.shade300, // Lighter background
|
||||
// valueColor: AlwaysStoppedAnimation<Color>(
|
||||
// CupertinoColors.systemRed), // iOS-style red
|
||||
// minHeight: 8, // Slightly thicker progress bar
|
||||
// ),
|
||||
// )),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// barrierDismissible: false,
|
||||
// );
|
||||
|
||||
// Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
// secondsRemaining.value--;
|
||||
// if (secondsRemaining.value <= 0) {
|
||||
// timer.cancel();
|
||||
// // Get.back();
|
||||
// _clearDataAndExit();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// static Future<void> _clearDataAndExit() async {
|
||||
// await storage.deleteAll();
|
||||
// await box.erase();
|
||||
// exit(0); // Exit the app
|
||||
// print('exit');
|
||||
// }
|
||||
// }
|
||||
|
||||
// class DeviceInfoPlus {
|
||||
// static List<Map<String, dynamic>> deviceDataList = [];
|
||||
|
||||
// static Future<List<Map<String, dynamic>>> getDeviceInfo() async {
|
||||
// final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
// try {
|
||||
// if (Platform.isAndroid) {
|
||||
// AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
|
||||
// Map<String, dynamic> deviceData = {
|
||||
// 'platform': 'Android',
|
||||
// 'brand': androidInfo.brand,
|
||||
// 'model': androidInfo.model,
|
||||
// 'androidId': androidInfo.device,
|
||||
// 'versionRelease': androidInfo.version.release,
|
||||
// 'sdkVersion': androidInfo.version.sdkInt,
|
||||
// 'manufacturer': androidInfo.manufacturer,
|
||||
// 'isPhysicalDevice': androidInfo.isPhysicalDevice,
|
||||
// 'serialNumber': androidInfo.serialNumber,
|
||||
// 'fingerprint': androidInfo.fingerprint,
|
||||
// 'type': androidInfo.type,
|
||||
// 'data': androidInfo.data,
|
||||
// 'version': androidInfo.version,
|
||||
// 'tags': androidInfo.tags,
|
||||
// 'display': androidInfo.display,
|
||||
// };
|
||||
// deviceDataList.add(deviceData);
|
||||
// } else if (Platform.isIOS) {
|
||||
// IosDeviceInfo iosInfo = await deviceInfoPlugin.iosInfo;
|
||||
// Map<String, dynamic> deviceData = {
|
||||
// 'brand': 'Apple',
|
||||
// 'model': iosInfo.model,
|
||||
// 'systemName': iosInfo.systemName,
|
||||
// 'systemVersion': iosInfo.systemVersion,
|
||||
// 'utsname': iosInfo.utsname,
|
||||
// 'isPhysicalDevice': iosInfo.isPhysicalDevice,
|
||||
// 'identifierForVendor': iosInfo.identifierForVendor,
|
||||
// 'name': iosInfo.name,
|
||||
// 'localizedModel': iosInfo.localizedModel,
|
||||
// };
|
||||
// deviceDataList.add(deviceData);
|
||||
// } else if (Platform.isMacOS) {
|
||||
// MacOsDeviceInfo macInfo = await deviceInfoPlugin.macOsInfo;
|
||||
// Map<String, dynamic> deviceData = {
|
||||
// 'platform': 'macOS',
|
||||
// 'model': macInfo.model,
|
||||
// 'version': macInfo.systemGUID,
|
||||
// };
|
||||
// deviceDataList.add(deviceData);
|
||||
// } else if (Platform.isWindows) {
|
||||
// WindowsDeviceInfo windowsInfo = await deviceInfoPlugin.windowsInfo;
|
||||
// Map<String, dynamic> deviceData = {
|
||||
// 'platform': 'Windows',
|
||||
// 'manufacturer': windowsInfo.computerName,
|
||||
// 'version': windowsInfo.majorVersion,
|
||||
// 'deviceId': windowsInfo.deviceId,
|
||||
// 'userName': windowsInfo.userName,
|
||||
// 'productName': windowsInfo.productName,
|
||||
// 'installDate': windowsInfo.installDate,
|
||||
// 'productId': windowsInfo.productId,
|
||||
// 'numberOfCores': windowsInfo.numberOfCores,
|
||||
// 'systemMemoryInMegabytes': windowsInfo.systemMemoryInMegabytes,
|
||||
// };
|
||||
// deviceDataList.add(deviceData);
|
||||
// } else if (Platform.isLinux) {
|
||||
// LinuxDeviceInfo linuxInfo = await deviceInfoPlugin.linuxInfo;
|
||||
// Map<String, dynamic> deviceData = {
|
||||
// 'platform': 'Linux',
|
||||
// 'manufacturer': linuxInfo.name,
|
||||
// 'version': linuxInfo.version,
|
||||
// };
|
||||
// deviceDataList.add(deviceData);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// }
|
||||
|
||||
// return deviceDataList;
|
||||
// }
|
||||
|
||||
// // Method to print all device data
|
||||
// static void printDeviceInfo() {
|
||||
// for (Map<String, dynamic> deviceData in deviceDataList) {
|
||||
// 'Version: ${deviceData['version'] ?? deviceData['versionRelease'] ?? 'N/A'}');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
42
lib/controller/functions/digit_obsecur_formate.dart
Normal file
42
lib/controller/functions/digit_obsecur_formate.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class DigitObscuringFormatter extends TextInputFormatter {
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(
|
||||
TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
final maskedText = maskDigits(newValue.text);
|
||||
return newValue.copyWith(
|
||||
text: maskedText,
|
||||
selection: updateCursorPosition(maskedText, newValue.selection));
|
||||
}
|
||||
|
||||
String maskDigits(String text) {
|
||||
final totalDigits = text.length;
|
||||
final visibleDigits = 4;
|
||||
final hiddenDigits = totalDigits - visibleDigits * 2;
|
||||
|
||||
final firstVisibleDigits = text.substring(0, visibleDigits);
|
||||
final lastVisibleDigits = text.substring(totalDigits - visibleDigits);
|
||||
|
||||
final maskedDigits = List.filled(hiddenDigits, '*').join();
|
||||
|
||||
return '$firstVisibleDigits$maskedDigits$lastVisibleDigits';
|
||||
}
|
||||
|
||||
TextSelection updateCursorPosition(
|
||||
String maskedText, TextSelection currentSelection) {
|
||||
final cursorPosition = currentSelection.baseOffset;
|
||||
final cursorOffset =
|
||||
currentSelection.extentOffset - currentSelection.baseOffset;
|
||||
final totalDigits = maskedText.length;
|
||||
const visibleDigits = 4;
|
||||
final hiddenDigits = totalDigits - visibleDigits * 2;
|
||||
|
||||
final updatedPosition = cursorPosition <= visibleDigits
|
||||
? cursorPosition
|
||||
: hiddenDigits + visibleDigits + (cursorPosition - visibleDigits);
|
||||
|
||||
return TextSelection.collapsed(
|
||||
offset: updatedPosition, affinity: currentSelection.affinity);
|
||||
}
|
||||
}
|
||||
41
lib/controller/functions/document_scanner.dart
Normal file
41
lib/controller/functions/document_scanner.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
// import 'dart:io';
|
||||
//
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:image_picker/image_picker.dart';
|
||||
// import 'package:google_ml_kit/google_ml_kit.dart';
|
||||
//
|
||||
// class ImagePickerController extends GetxController {
|
||||
// RxBool textScanning = false.obs;
|
||||
// RxString scannedText = ''.obs;
|
||||
//
|
||||
// Future<void> getImage(ImageSource source) async {
|
||||
// try {
|
||||
// final pickedImage = await ImagePicker().pickImage(source: source);
|
||||
// if (pickedImage != null) {
|
||||
// textScanning.value = true;
|
||||
// final imageFile = File(pickedImage.path);
|
||||
// getRecognisedText(imageFile);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// textScanning.value = false;
|
||||
// scannedText.value = "Error occurred while scanning";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future<void> getRecognisedText(File image) async {
|
||||
// final inputImage = InputImage.fromFilePath(image.path);
|
||||
// final textDetector = GoogleMlKit.vision.textRecognizer();
|
||||
// final RecognizedText recognisedText =
|
||||
// await textDetector.processImage(inputImage);
|
||||
// await textDetector.close();
|
||||
//
|
||||
// scannedText.value = '';
|
||||
// for (TextBlock block in recognisedText.blocks) {
|
||||
// for (TextLine line in block.lines) {
|
||||
// scannedText.value += line.text + '\n';
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// textScanning.value = false;
|
||||
// }
|
||||
// }
|
||||
79
lib/controller/functions/encrypt_decrypt.dart
Normal file
79
lib/controller/functions/encrypt_decrypt.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
||||
|
||||
import '../../constant/char_map.dart';
|
||||
import '../../env/env.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
|
||||
class EncryptionHelper {
|
||||
static EncryptionHelper? _instance;
|
||||
|
||||
late final encrypt.Key key;
|
||||
late final encrypt.IV iv;
|
||||
|
||||
EncryptionHelper._(this.key, this.iv);
|
||||
static EncryptionHelper get instance {
|
||||
if (_instance == null) {
|
||||
throw Exception(
|
||||
"EncryptionHelper is not initialized. Call `await EncryptionHelper.initialize()` in main.");
|
||||
}
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
/// Initializes and stores the instance globally
|
||||
static Future<void> initialize() async {
|
||||
if (_instance != null) {
|
||||
debugPrint("EncryptionHelper is already initialized.");
|
||||
return; // Prevent re-initialization
|
||||
}
|
||||
debugPrint("Initializing EncryptionHelper...");
|
||||
var keyOfApp = r(Env.keyOfApp).toString().split(Env.addd)[0];
|
||||
Log.print('keyOfApp: ${keyOfApp}');
|
||||
var initializationVector =
|
||||
r(Env.initializationVector).toString().split(Env.addd)[0];
|
||||
Log.print('initializationVector: ${initializationVector}');
|
||||
|
||||
// Set the global instance
|
||||
_instance = EncryptionHelper._(
|
||||
encrypt.Key.fromUtf8(keyOfApp),
|
||||
encrypt.IV.fromUtf8(initializationVector),
|
||||
);
|
||||
debugPrint("EncryptionHelper initialized successfully.");
|
||||
}
|
||||
|
||||
/// Encrypts a string
|
||||
String encryptData(String plainText) {
|
||||
try {
|
||||
final encrypter =
|
||||
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
|
||||
final encrypted = encrypter.encrypt(plainText, iv: iv);
|
||||
return encrypted.base64;
|
||||
} catch (e) {
|
||||
debugPrint('Encryption Error: $e');
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypts a string
|
||||
String decryptData(String encryptedText) {
|
||||
try {
|
||||
final encrypter =
|
||||
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
|
||||
final encrypted = encrypt.Encrypted.fromBase64(encryptedText);
|
||||
return encrypter.decrypt(encrypted, iv: iv);
|
||||
} catch (e) {
|
||||
debugPrint('Decryption Error: $e');
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r(String string) {
|
||||
return X.r(X.r(X.r(string, cn), cC), cs).toString();
|
||||
}
|
||||
|
||||
c(String string) {
|
||||
return X.c(X.c(X.c(string, cn), cC), cs).toString();
|
||||
}
|
||||
829
lib/controller/functions/gemeni.dart
Normal file
829
lib/controller/functions/gemeni.dart
Normal file
@@ -0,0 +1,829 @@
|
||||
// import 'dart:convert';
|
||||
// import 'dart:io';
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:image_cropper/image_cropper.dart';
|
||||
// import 'package:image_picker/image_picker.dart';
|
||||
// import 'package:http/http.dart' as http;
|
||||
// import 'package:image/image.dart' as img;
|
||||
// import 'package:path_provider/path_provider.dart';
|
||||
|
||||
// import '../../constant/api_key.dart';
|
||||
// import '../../constant/colors.dart';
|
||||
|
||||
// class AI extends GetxController {
|
||||
// final picker = ImagePicker();
|
||||
// Map<String, dynamic> responseMap = {};
|
||||
// Map<String, dynamic> responseCarLicenseMap = {};
|
||||
// Map<String, dynamic> responseBackCarLicenseMap = {};
|
||||
// Map<String, dynamic> responseIdCardeMap = {};
|
||||
// bool isloading = false;
|
||||
// var image;
|
||||
// CroppedFile? croppedFile;
|
||||
// DateTime now = DateTime.now();
|
||||
// Future<void> pickImage() async {
|
||||
// final pickedImage = await picker.pickImage(source: ImageSource.gallery);
|
||||
|
||||
// if (pickedImage != null) {
|
||||
// image = File(pickedImage.path);
|
||||
// // Crop the image
|
||||
// croppedFile = await ImageCropper().cropImage(
|
||||
// sourcePath: image!.path,
|
||||
// aspectRatioPresets: [
|
||||
// CropAspectRatioPreset.square,
|
||||
// CropAspectRatioPreset.ratio3x2,
|
||||
// CropAspectRatioPreset.original,
|
||||
// CropAspectRatioPreset.ratio4x3,
|
||||
// CropAspectRatioPreset.ratio16x9
|
||||
// ],
|
||||
// uiSettings: [
|
||||
// AndroidUiSettings(
|
||||
// toolbarTitle: 'Cropper'.tr,
|
||||
// toolbarColor: AppColor.blueColor,
|
||||
// toolbarWidgetColor: AppColor.yellowColor,
|
||||
// initAspectRatio: CropAspectRatioPreset.original,
|
||||
// lockAspectRatio: false),
|
||||
// IOSUiSettings(
|
||||
// title: 'Cropper'.tr,
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// // image = croppedFile;
|
||||
|
||||
// // Resize the image
|
||||
// final rawImage =
|
||||
// img.decodeImage(File(croppedFile!.path).readAsBytesSync());
|
||||
// final resizedImage =
|
||||
// img.copyResize(rawImage!, width: 800); // Adjust the width as needed
|
||||
|
||||
// final appDir = await getTemporaryDirectory();
|
||||
// final resizedImagePath = '${appDir.path}/resized_image.jpg';
|
||||
|
||||
// final resizedImageFile = File(resizedImagePath);
|
||||
// resizedImageFile.writeAsBytesSync(
|
||||
// img.encodeJpg(resizedImage)); // Save the resized image as JPEG
|
||||
|
||||
// image = resizedImageFile;
|
||||
// update();
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> generateContent() async {
|
||||
// await pickImage();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// 'write json for all data as first name ,last name,dob,licenseID,expiration date,issued date asdress class type ,output json type',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> geminiAiExtraction(String prompt, payload) async {
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// // {
|
||||
// // 'inlineData': {
|
||||
// // 'mimeType': 'image/jpeg',
|
||||
// // 'data': imageData,
|
||||
// // },
|
||||
// // },
|
||||
// {
|
||||
// 'text':
|
||||
// "Extract the desired information from the following passage as json decoded like $prompt .and look for this instruction first name in line 3or 2 ,fullname in line 4 from it written left to right but you modify it rtl,address in line 5 it written left to right but you modify it rtl and 6,dob,nationalid in the last line as just in this:\n\n$payload"
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safety_settings': [
|
||||
// {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
|
||||
// {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
|
||||
// {
|
||||
// "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
||||
// "threshold": "BLOCK_NONE"
|
||||
// },
|
||||
// {
|
||||
// "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
||||
// "threshold": "BLOCK_NONE"
|
||||
// },
|
||||
// ]
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// // 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?key=AIzaSyCyoLcSkDzK5_SMe00nhut56SSXWPR074w'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result = responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> getDriverLicenseJordanContent() async {
|
||||
// await pickImage();
|
||||
// isloading = true;
|
||||
// update();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// 'write json for all data as first name ,last name,dob,id ,expiration date,issued date asdress class type,age in years ,output json type in arabic value and stay engish key and make date format like YYYY-MM-DD , for name please extract name in arabic in Name in json plus first_name ',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
// isloading = false;
|
||||
// update();
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// responseMap = jsonDecode(jsonString);
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> getCarLicenseJordanContent() async {
|
||||
// await pickImage();
|
||||
// isloading = true;
|
||||
// update();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// '''Extract the following information from the front face of the Jordanian ID card:
|
||||
// Name
|
||||
// National ID number
|
||||
// Gender
|
||||
// Date of birth
|
||||
// Output the extracted information in the following JSON format''',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// // 'https://${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/${LOCATION_ID}/publishers/google/models/${MODEL_ID}:streamGenerateContent'),
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
// isloading = false;
|
||||
// update();
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// responseCarLicenseMap = jsonDecode(jsonString);
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> jordanID() async {
|
||||
// await pickImage();
|
||||
// isloading = true;
|
||||
// update();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// '''Extract the following information from the front face of the Jordanian ID card:
|
||||
// Name
|
||||
// National ID number
|
||||
// Gender
|
||||
// Date of birth
|
||||
// Output the extracted information in the following JSON format''',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
// isloading = false;
|
||||
// update();
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// responseCarLicenseMap = jsonDecode(jsonString);
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> carLicenseJordan() async {
|
||||
// await pickImage();
|
||||
// isloading = true;
|
||||
// update();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// '''Extract the following information from the front face of the car license card in Jordan:
|
||||
|
||||
// * name
|
||||
// * Address
|
||||
// * Vehicle type
|
||||
// * car_kind
|
||||
// * car_color
|
||||
// * Vehicle category
|
||||
// * car_year
|
||||
// * car_plate
|
||||
// * Registration type
|
||||
// * Usage type
|
||||
// * expire_date_of_license
|
||||
|
||||
// Output the extracted information in the following JSON formate and make date format like YYYY-MM-DD''',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro-vision-latest:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
// isloading = false;
|
||||
// update();
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// responseCarLicenseMap = jsonDecode(jsonString);
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future getTextFromCard(String prompt) async {
|
||||
// await pickImage();
|
||||
// isloading = true;
|
||||
// update();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text': prompt,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// "temperature": 1,
|
||||
// "topK": 32,
|
||||
// "topP": 0.1,
|
||||
// "maxOutputTokens": 4096,
|
||||
// "stopSequences": []
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro-vision-latest:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
// isloading = false;
|
||||
// update();
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// responseBackCarLicenseMap = jsonDecode(jsonString);
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> generateBackCarLicenseJordanContent() async {
|
||||
// await pickImage();
|
||||
// isloading = true;
|
||||
// update();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// 'write json output from extracting car license back face for these key ,vin,fuelType,passengerType,curbWeight,insuranceCompany,policyNumber,notes,insuranceType and output it json .dont add data else this image',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 343,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
// isloading = false;
|
||||
// update();
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// responseBackCarLicenseMap = jsonDecode(jsonString);
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> getFromCarRegistration() async {
|
||||
// await pickImage();
|
||||
// if (image != null) {
|
||||
// final imageBytes = await image.readAsBytes();
|
||||
// final imageData = base64Encode(imageBytes);
|
||||
|
||||
// var requestBody = jsonEncode({
|
||||
// 'contents': [
|
||||
// {
|
||||
// 'parts': [
|
||||
// {
|
||||
// 'inlineData': {
|
||||
// 'mimeType': 'image/jpeg',
|
||||
// 'data': imageData,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 'text':
|
||||
// 'write output json from image for[ vin, make, model, year, expiration_date, color, owner, registration_date ],output json type ',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// 'generationConfig': {
|
||||
// 'temperature': 0.4,
|
||||
// 'topK': 32,
|
||||
// 'topP': 1,
|
||||
// 'maxOutputTokens': 4096,
|
||||
// 'stopSequences': [],
|
||||
// },
|
||||
// 'safetySettings': [
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// {
|
||||
// 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'threshold': 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${AK.geminiApi}'),
|
||||
// headers: {'Content-Type': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
|
||||
// if (response.statusCode == 200) {
|
||||
// var responseData = jsonDecode(response.body);
|
||||
// // Process the responseData as needed
|
||||
// var result =
|
||||
// responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||
// RegExp regex = RegExp(r"```json([^`]*)```");
|
||||
// String? jsonString =
|
||||
// regex.firstMatch(responseData.toString())?.group(1)?.trim();
|
||||
|
||||
// if (jsonString != null) {
|
||||
// // Convert the JSON object to a String
|
||||
// jsonString = jsonEncode(json.decode(jsonString));
|
||||
// } else {
|
||||
// }
|
||||
|
||||
// // Rest of your code...
|
||||
// } else {
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
// }
|
||||
|
||||
// @override
|
||||
// void onInit() {
|
||||
// // generateContent();
|
||||
// super.onInit();
|
||||
// }
|
||||
// }
|
||||
71
lib/controller/functions/launch.dart
Normal file
71
lib/controller/functions/launch.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'dart:io';
|
||||
|
||||
void showInBrowser(String url) async {
|
||||
if (await canLaunchUrl(Uri.parse(url))) {
|
||||
launchUrl(Uri.parse(url));
|
||||
} else {}
|
||||
}
|
||||
|
||||
Future<void> makePhoneCall(String phoneNumber) async {
|
||||
final Uri launchUri = Uri(
|
||||
scheme: 'tel',
|
||||
path: phoneNumber,
|
||||
);
|
||||
await launchUrl(launchUri);
|
||||
}
|
||||
|
||||
void launchCommunication(
|
||||
String method, String contactInfo, String message) async {
|
||||
String url;
|
||||
|
||||
if (Platform.isIOS) {
|
||||
switch (method) {
|
||||
case 'phone':
|
||||
url = 'tel:$contactInfo';
|
||||
break;
|
||||
|
||||
case 'sms':
|
||||
url = 'sms:$contactInfo?body=$message';
|
||||
break;
|
||||
|
||||
case 'whatsapp':
|
||||
url = 'https://api.whatsapp.com/send?phone=$contactInfo&text=$message';
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
url = 'mailto:$contactInfo?subject=Subject&body=$message';
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} else if (Platform.isAndroid) {
|
||||
switch (method) {
|
||||
case 'phone':
|
||||
url = 'tel:$contactInfo';
|
||||
break;
|
||||
|
||||
case 'sms':
|
||||
url = 'sms:$contactInfo?body=$message';
|
||||
break;
|
||||
|
||||
case 'whatsapp':
|
||||
url = 'whatsapp://send?phone=$contactInfo&text=$message';
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
url = 'mailto:$contactInfo?subject=Subject&body=$message';
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (await canLaunchUrl(Uri.parse(url))) {
|
||||
launchUrl(Uri.parse(url));
|
||||
} else {}
|
||||
}
|
||||
36
lib/controller/functions/llama_ai.dart
Normal file
36
lib/controller/functions/llama_ai.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../constant/links.dart';
|
||||
import 'crud.dart';
|
||||
|
||||
class LlamaAi {
|
||||
Future<Map> getCarRegistrationData(String input, prompt) async {
|
||||
Map exrtatDataFinal = {};
|
||||
String oneLine = input.replaceAll('\n', ' ');
|
||||
// var res = await CRUD().getLlama(link: AppLink.gemini, payload: oneLine);
|
||||
var res = await CRUD()
|
||||
.getLlama(link: AppLink.llama, payload: oneLine, prompt: prompt);
|
||||
|
||||
var decod = jsonDecode(res.toString());
|
||||
// exrtatDataFinal = jsonDecode(extractDataFromJsonString(decod['choices']));
|
||||
extractDataFromJsonString(decod['choices'][0]['message']['content']);
|
||||
return exrtatDataFinal;
|
||||
}
|
||||
|
||||
String extractDataFromJsonString(String jsonString) {
|
||||
// Remove any leading or trailing whitespace from the string
|
||||
jsonString = jsonString.trim();
|
||||
|
||||
// Extract the JSON substring from the given string
|
||||
final startIndex = jsonString.indexOf('{');
|
||||
final endIndex = jsonString.lastIndexOf('}');
|
||||
final jsonSubstring = jsonString.substring(startIndex, endIndex + 1);
|
||||
|
||||
// Parse the JSON substring into a Map
|
||||
final jsonData = jsonDecode(jsonSubstring);
|
||||
|
||||
// Return the extracted data
|
||||
|
||||
return jsonEncode(jsonData);
|
||||
}
|
||||
}
|
||||
133
lib/controller/functions/location_controller.dart
Normal file
133
lib/controller/functions/location_controller.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
// import 'dart:async';
|
||||
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
// import 'package:location/location.dart';
|
||||
|
||||
// import '../../constant/box_name.dart';
|
||||
// import '../../constant/links.dart';
|
||||
// import '../../main.dart';
|
||||
// import 'crud.dart';
|
||||
|
||||
// // LocationController.dart
|
||||
// class LocationController extends GetxController {
|
||||
// LocationData? _currentLocation;
|
||||
// late Location location;
|
||||
// bool isLoading = false;
|
||||
// late double heading = 0;
|
||||
// late double accuracy = 0;
|
||||
// late double previousTime = 0;
|
||||
// late double latitude;
|
||||
// late double totalDistance = 0;
|
||||
// late double longitude;
|
||||
// late DateTime time;
|
||||
// late double speed = 0;
|
||||
// late double speedAccuracy = 0;
|
||||
// late double headingAccuracy = 0;
|
||||
// bool isActive = false;
|
||||
// late LatLng myLocation;
|
||||
// String totalPoints = '0';
|
||||
// LocationData? get currentLocation => _currentLocation;
|
||||
// Timer? _locationTimer;
|
||||
|
||||
// @override
|
||||
// void onInit() async {
|
||||
// super.onInit();
|
||||
// location = Location();
|
||||
// getLocation();
|
||||
// // startLocationUpdates();
|
||||
// }
|
||||
|
||||
// Future<void> startLocationUpdates() async {
|
||||
// if (box.read(BoxName.driverID) != null) {
|
||||
// _locationTimer =
|
||||
// Timer.periodic(const Duration(seconds: 5), (timer) async {
|
||||
// try {
|
||||
// // if (isActive) {
|
||||
// if (double.parse(totalPoints) > -300) {
|
||||
|
||||
// await getLocation();
|
||||
|
||||
// // if (box.read(BoxName.driverID) != null) {
|
||||
// await CRUD()
|
||||
// .post(link: AppLink.addCarsLocationByPassenger, payload: {
|
||||
// 'driver_id': box.read(BoxName.driverID).toString(),
|
||||
// 'latitude': myLocation.latitude.toString(),
|
||||
// 'longitude': myLocation.longitude.toString(),
|
||||
// 'heading': heading.toString(),
|
||||
// 'speed': (speed * 3.6).toStringAsFixed(1),
|
||||
// 'distance': totalDistance == 0
|
||||
// ? '0'
|
||||
// : totalDistance < 1
|
||||
// ? totalDistance.toStringAsFixed(3)
|
||||
// : totalDistance.toStringAsFixed(1),
|
||||
// 'status': box.read(BoxName.statusDriverLocation).toString()
|
||||
// });
|
||||
// }
|
||||
// } catch (e) {
|
||||
// // Handle the error gracefully
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// void stopLocationUpdates() {
|
||||
// _locationTimer?.cancel();
|
||||
// }
|
||||
|
||||
// Future<void> getLocation() async {
|
||||
// // isLoading = true;
|
||||
// // update();
|
||||
// bool serviceEnabled;
|
||||
// PermissionStatus permissionGranted;
|
||||
|
||||
// // Check if location services are enabled
|
||||
// serviceEnabled = await location.serviceEnabled();
|
||||
// if (!serviceEnabled) {
|
||||
// serviceEnabled = await location.requestService();
|
||||
// if (!serviceEnabled) {
|
||||
// // Location services are still not enabled, handle the error
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Check if the app has permission to access location
|
||||
// permissionGranted = await location.hasPermission();
|
||||
// if (permissionGranted == PermissionStatus.denied) {
|
||||
// permissionGranted = await location.requestPermission();
|
||||
// if (permissionGranted != PermissionStatus.granted) {
|
||||
// // Location permission is still not granted, handle the error
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Configure location accuracy
|
||||
// // LocationAccuracy desiredAccuracy = LocationAccuracy.high;
|
||||
|
||||
// // Get the current location
|
||||
// LocationData _locationData = await location.getLocation();
|
||||
// myLocation =
|
||||
// (_locationData.latitude != null && _locationData.longitude != null
|
||||
// ? LatLng(_locationData.latitude!, _locationData.longitude!)
|
||||
// : null)!;
|
||||
// speed = _locationData.speed!;
|
||||
// heading = _locationData.heading!;
|
||||
|
||||
// // isLoading = false;
|
||||
// update();
|
||||
// }
|
||||
|
||||
// double calculateDistanceInKmPerHour(
|
||||
// double? startTime, double? endTime, double speedInMetersPerSecond) {
|
||||
// // Calculate the time difference in hours
|
||||
// double timeDifferenceInHours = (endTime! - startTime!) / 1000 / 3600;
|
||||
|
||||
// // Convert speed to kilometers per hour
|
||||
// double speedInKmPerHour = speedInMetersPerSecond * 3.6;
|
||||
|
||||
// // Calculate the distance in kilometers
|
||||
// double distanceInKilometers = speedInKmPerHour * timeDifferenceInHours;
|
||||
|
||||
// return distanceInKilometers;
|
||||
// }
|
||||
// }
|
||||
16
lib/controller/functions/location_permission.dart
Normal file
16
lib/controller/functions/location_permission.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
// import 'package:location/location.dart';
|
||||
// import 'package:get/get.dart';
|
||||
|
||||
// class LocationPermissions {
|
||||
// late Location location;
|
||||
|
||||
// Future locationPermissions() async {
|
||||
// location = Location();
|
||||
// var permissionStatus = await location.requestPermission();
|
||||
// if (permissionStatus == PermissionStatus.denied) {
|
||||
// // The user denied the location permission.
|
||||
// Get.defaultDialog(title: 'GPS Required Allow !.'.tr, middleText: '');
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
181
lib/controller/functions/log_out.dart
Normal file
181
lib/controller/functions/log_out.dart
Normal file
@@ -0,0 +1,181 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../main.dart';
|
||||
import '../../views/widgets/elevated_btn.dart';
|
||||
import '../../views/widgets/my_textField.dart';
|
||||
import 'crud.dart';
|
||||
|
||||
class LogOutController extends GetxController {
|
||||
TextEditingController checkTxtController = TextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final formKey1 = GlobalKey<FormState>();
|
||||
final emailTextController = TextEditingController();
|
||||
|
||||
Future deleteMyAccountDriver(String id) async {
|
||||
await CRUD().post(link: AppLink.removeUser, payload: {'id': id}).then(
|
||||
(value) => Get.snackbar('Deleted'.tr, 'Your Account is Deleted',
|
||||
backgroundColor: AppColor.redColor));
|
||||
}
|
||||
|
||||
checkBeforeDelete() async {
|
||||
var res = await CRUD().post(
|
||||
link: AppLink.deletecaptainAccounr,
|
||||
payload: {'id': box.read(BoxName.driverID)}).then((value) => exit(0));
|
||||
}
|
||||
|
||||
deletecaptainAccount() {
|
||||
Get.defaultDialog(
|
||||
backgroundColor: AppColor.yellowColor,
|
||||
title: 'Are you sure to delete your account?'.tr,
|
||||
middleText:
|
||||
'Your data will be erased after 2 weeks\nAnd you will can\'t return to use app after 1 month ',
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: Get.width,
|
||||
decoration: AppStyle.boxDecoration,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Your data will be erased after 2 weeks\nAnd you will can\'t return to use app after 1 month'
|
||||
.tr,
|
||||
style: AppStyle.title.copyWith(color: AppColor.redColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Form(
|
||||
key: formKey,
|
||||
child: SizedBox(
|
||||
width: Get.width,
|
||||
child: MyTextForm(
|
||||
controller: checkTxtController,
|
||||
label: 'Enter Your First Name'.tr,
|
||||
hint: 'Enter Your First Name'.tr,
|
||||
type: TextInputType.name,
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Delete'.tr,
|
||||
onPressed: () {
|
||||
if (checkTxtController.text == box.read(BoxName.nameDriver)) {
|
||||
deletecaptainAccount();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Future logOutPassenger() async {
|
||||
Get.defaultDialog(
|
||||
title: 'Are you Sure to LogOut?'.tr,
|
||||
content: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'Cancel'.tr,
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(AppColor.redColor),
|
||||
),
|
||||
onPressed: () {
|
||||
// box.remove(BoxName.agreeTerms);
|
||||
box.remove(BoxName.driverID);
|
||||
box.remove(BoxName.email);
|
||||
box.remove(BoxName.lang);
|
||||
box.remove(BoxName.name);
|
||||
box.remove(BoxName.passengerID);
|
||||
box.remove(BoxName.phone);
|
||||
box.remove(BoxName.tokenFCM);
|
||||
box.remove(BoxName.tokens);
|
||||
box.remove(BoxName.addHome);
|
||||
box.remove(BoxName.addWork);
|
||||
box.remove(BoxName.agreeTerms);
|
||||
box.remove(BoxName.apiKeyRun);
|
||||
box.remove(BoxName.countryCode);
|
||||
box.remove(BoxName.accountIdStripeConnect);
|
||||
box.remove(BoxName.passengerWalletTotal);
|
||||
Get.offAll(const MainApp());
|
||||
},
|
||||
child: Text(
|
||||
'Sign Out'.tr,
|
||||
style:
|
||||
AppStyle.title.copyWith(color: AppColor.secondaryColor),
|
||||
))
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Future logOutCaptain() async {
|
||||
Get.defaultDialog(
|
||||
title: 'Are you Sure to LogOut?'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'Cancel'.tr,
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(AppColor.redColor),
|
||||
),
|
||||
onPressed: () {
|
||||
// box.remove(BoxName.agreeTerms);
|
||||
box.remove(BoxName.driverID);
|
||||
box.remove(BoxName.sexDriver);
|
||||
box.remove(BoxName.dobDriver);
|
||||
box.remove(BoxName.nameDriver);
|
||||
box.remove(BoxName.emailDriver);
|
||||
box.remove(BoxName.phoneDriver);
|
||||
box.remove(BoxName.statusDriverLocation);
|
||||
box.remove(BoxName.cvvCodeDriver);
|
||||
box.remove(BoxName.lastNameDriver);
|
||||
box.remove(BoxName.passwordDriver);
|
||||
box.remove(BoxName.cardNumberDriver);
|
||||
box.remove(BoxName.expiryDateDriver);
|
||||
box.remove(BoxName.cardHolderNameDriver);
|
||||
box.remove(BoxName.vin);
|
||||
box.remove(BoxName.make);
|
||||
box.remove(BoxName.year);
|
||||
box.remove(BoxName.owner);
|
||||
box.remove(BoxName.onBoarding);
|
||||
box.remove(BoxName.agreeTerms);
|
||||
Get.offAll(const MainApp());
|
||||
},
|
||||
child: Text(
|
||||
'Sign Out'.tr,
|
||||
style:
|
||||
AppStyle.title.copyWith(color: AppColor.secondaryColor),
|
||||
))
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
deletePassengerAccount() async {
|
||||
if (formKey1.currentState!.validate()) {
|
||||
if (box.read(BoxName.email).toString() == emailTextController.text) {
|
||||
await CRUD().post(link: AppLink.passengerRemovedAccountEmail, payload: {
|
||||
'email': box.read(BoxName.email),
|
||||
});
|
||||
} else {
|
||||
Get.snackbar('Email Wrong'.tr, 'Email you inserted is Wrong.'.tr,
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
lib/controller/functions/scan_id_card.dart
Normal file
25
lib/controller/functions/scan_id_card.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
// import 'package:credit_card_scanner/credit_card_scanner.dart';
|
||||
// import 'package:get/get.dart';
|
||||
//
|
||||
// class ScanIdCard extends GetxController {
|
||||
// CardDetails? _cardDetails;
|
||||
// CardScanOptions scanOptions = const CardScanOptions(
|
||||
// scanCardHolderName: true,
|
||||
// enableDebugLogs: true,
|
||||
// validCardsToScanBeforeFinishingScan: 5,
|
||||
// possibleCardHolderNamePositions: [
|
||||
// CardHolderNameScanPosition.aboveCardNumber,
|
||||
// ],
|
||||
// );
|
||||
//
|
||||
// Future<void> scanCard() async {
|
||||
// final CardDetails? cardDetails =
|
||||
// await CardScanner.scanCard(scanOptions: scanOptions);
|
||||
// if (cardDetails == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// _cardDetails = cardDetails;
|
||||
// update();
|
||||
// }
|
||||
// }
|
||||
14
lib/controller/functions/secure_storage.dart
Normal file
14
lib/controller/functions/secure_storage.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
class SecureStorage {
|
||||
final FlutterSecureStorage _storage = const FlutterSecureStorage();
|
||||
|
||||
void saveData(String key, value) async {
|
||||
await _storage.write(key: key, value: value);
|
||||
}
|
||||
|
||||
Future<String?> readData(String boxName) async {
|
||||
final String? value = await _storage.read(key: boxName);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
50
lib/controller/functions/security_checks.dart
Executable file
50
lib/controller/functions/security_checks.dart
Executable file
@@ -0,0 +1,50 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SecurityChecks {
|
||||
static const platform = MethodChannel(
|
||||
'com.intaleq.intaleq_admin/security'); // Choose a unique channel name
|
||||
|
||||
static Future<bool> isDeviceCompromised() async {
|
||||
try {
|
||||
final bool result = await platform
|
||||
.invokeMethod('isNativeRooted'); // Invoke the native method
|
||||
return result;
|
||||
} on PlatformException catch (e) {
|
||||
print("Failed to check security status: ${e.message}");
|
||||
return true; // Treat platform errors as a compromised device (for safety)
|
||||
}
|
||||
}
|
||||
|
||||
static isDeviceRootedFromNative(BuildContext context) async {
|
||||
bool compromised = await isDeviceCompromised();
|
||||
if (compromised) {
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text("Security Warning".tr),
|
||||
content: Text(
|
||||
"Your device appears to be compromised. The app will now close."
|
||||
.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
SystemNavigator.pop(); // Close the app
|
||||
},
|
||||
child: Text("OK"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Continue with normal app flow
|
||||
print("Device is secure.");
|
||||
}
|
||||
}
|
||||
}
|
||||
446
lib/controller/functions/upload_image copy.dart
Normal file
446
lib/controller/functions/upload_image copy.dart
Normal file
@@ -0,0 +1,446 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:image_cropper/image_cropper.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
|
||||
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
|
||||
class ImageController extends GetxController {
|
||||
File? myImage;
|
||||
bool isloading = false;
|
||||
CroppedFile? croppedFile;
|
||||
final picker = ImagePicker();
|
||||
var image;
|
||||
|
||||
Future<img.Image> detectAndCropDocument(File imageFile) async {
|
||||
img.Image? image = img.decodeImage(await imageFile.readAsBytes());
|
||||
if (image == null) throw Exception('Unable to decode image');
|
||||
|
||||
int left = image.width, top = image.height, right = 0, bottom = 0;
|
||||
|
||||
// Threshold for considering a pixel as part of the document (adjust as needed)
|
||||
const int threshold = 240;
|
||||
|
||||
for (int y = 0; y < image.height; y++) {
|
||||
for (int x = 0; x < image.width; x++) {
|
||||
final pixel = image.getPixel(x, y);
|
||||
final luminance = img.getLuminance(pixel);
|
||||
|
||||
if (luminance < threshold) {
|
||||
left = x < left ? x : left;
|
||||
top = y < top ? y : top;
|
||||
right = x > right ? x : right;
|
||||
bottom = y > bottom ? y : bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a small padding
|
||||
left = (left - 5).clamp(0, image.width);
|
||||
top = (top - 5).clamp(0, image.height);
|
||||
right = (right + 5).clamp(0, image.width);
|
||||
bottom = (bottom + 5).clamp(0, image.height);
|
||||
|
||||
return img.copyCrop(image,
|
||||
x: left, y: top, width: right - left, height: bottom - top);
|
||||
}
|
||||
|
||||
Future<File> rotateImageIfNeeded(File imageFile) async {
|
||||
img.Image croppedDoc = await detectAndCropDocument(imageFile);
|
||||
|
||||
// Check if the document is in portrait orientation
|
||||
bool isPortrait = croppedDoc.height > croppedDoc.width;
|
||||
|
||||
img.Image processedImage;
|
||||
if (isPortrait) {
|
||||
// Rotate the image by 90 degrees clockwise
|
||||
processedImage = img.copyRotate(croppedDoc, angle: 90);
|
||||
} else {
|
||||
processedImage = croppedDoc;
|
||||
}
|
||||
|
||||
// Get temporary directory
|
||||
final tempDir = await path_provider.getTemporaryDirectory();
|
||||
final tempPath = tempDir.path;
|
||||
|
||||
// Create the processed image file
|
||||
File processedFile = File('$tempPath/processed_image.jpg');
|
||||
await processedFile.writeAsBytes(img.encodeJpg(processedImage));
|
||||
|
||||
return processedFile;
|
||||
}
|
||||
|
||||
Future<File> rotateImage(File imageFile) async {
|
||||
// Read the image file
|
||||
img.Image? image = img.decodeImage(await imageFile.readAsBytes());
|
||||
|
||||
if (image == null) return imageFile;
|
||||
|
||||
// Rotate the image by 90 degrees clockwise
|
||||
img.Image rotatedImage = img.copyRotate(image, angle: 90);
|
||||
|
||||
// Get temporary directory
|
||||
final tempDir = await path_provider.getTemporaryDirectory();
|
||||
final tempPath = tempDir.path;
|
||||
|
||||
// Create the rotated image file
|
||||
File rotatedFile = File('$tempPath/rotated_image.jpg');
|
||||
await rotatedFile.writeAsBytes(img.encodeJpg(rotatedImage));
|
||||
|
||||
return rotatedFile;
|
||||
}
|
||||
|
||||
choosImage(String link, String imageType, String id) async {
|
||||
try {
|
||||
final pickedImage = await picker.pickImage(
|
||||
source: ImageSource.camera,
|
||||
preferredCameraDevice: CameraDevice.rear,
|
||||
);
|
||||
|
||||
if (pickedImage == null) return;
|
||||
|
||||
image = File(pickedImage.path);
|
||||
|
||||
croppedFile = await ImageCropper().cropImage(
|
||||
sourcePath: image!.path,
|
||||
uiSettings: [
|
||||
AndroidUiSettings(
|
||||
toolbarTitle: 'Cropper'.tr,
|
||||
toolbarColor: AppColor.blueColor,
|
||||
toolbarWidgetColor: AppColor.yellowColor,
|
||||
initAspectRatio: CropAspectRatioPreset.original,
|
||||
lockAspectRatio: false,
|
||||
),
|
||||
IOSUiSettings(
|
||||
title: 'Cropper'.tr,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
if (croppedFile == null) return;
|
||||
|
||||
myImage = File(croppedFile!.path);
|
||||
isloading = true;
|
||||
update();
|
||||
|
||||
// Rotate the compressed image
|
||||
File processedImage = await rotateImageIfNeeded(File(croppedFile!.path));
|
||||
File compressedImage = await compressImage(processedImage);
|
||||
|
||||
print('link =$link');
|
||||
Log.print('link: ${link}');
|
||||
|
||||
await uploadImage(
|
||||
compressedImage,
|
||||
{
|
||||
'driverID': id,
|
||||
'imageType': imageType,
|
||||
},
|
||||
link,
|
||||
);
|
||||
} catch (e) {
|
||||
print('Error in choosImage: $e');
|
||||
Get.snackbar('Image Upload Failed'.tr, e.toString(),
|
||||
backgroundColor: AppColor.primaryColor);
|
||||
} finally {
|
||||
isloading = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
// choosFaceFromDriverLicense(String link, String imageType) async {
|
||||
// final pickedImage = await picker.pickImage(
|
||||
// source: ImageSource.camera,
|
||||
// preferredCameraDevice: CameraDevice.rear,
|
||||
// );
|
||||
|
||||
// if (pickedImage == null) return;
|
||||
|
||||
// image = File(pickedImage.path);
|
||||
|
||||
// File? processedImage;
|
||||
|
||||
// // For face images, use face detection and cropping
|
||||
// processedImage = await detectAndCropFace(image!);
|
||||
// if (processedImage == null) {
|
||||
// Get.snackbar('Face Detection Failed', 'No face detected in the image.');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// isloading = true;
|
||||
// update();
|
||||
|
||||
// File compressedImage = await compressImage(processedImage);
|
||||
|
||||
// try {
|
||||
// await uploadImage(
|
||||
// compressedImage,
|
||||
// {
|
||||
// 'driverID': box.read(BoxName.driverID).toString(),
|
||||
// 'imageType': imageType
|
||||
// },
|
||||
// link,
|
||||
// );
|
||||
// } catch (e) {
|
||||
// Get.snackbar('Image Upload Failed'.tr, e.toString(),
|
||||
// backgroundColor: AppColor.redColor);
|
||||
// } finally {
|
||||
// isloading = false;
|
||||
// update();
|
||||
// }
|
||||
// }
|
||||
|
||||
choosFace(String link, String imageType) async {
|
||||
final pickedImage = await picker.pickImage(
|
||||
source: ImageSource.camera,
|
||||
preferredCameraDevice: CameraDevice.front,
|
||||
);
|
||||
if (pickedImage != null) {
|
||||
image = File(pickedImage.path);
|
||||
isloading = true;
|
||||
update();
|
||||
// Compress the image
|
||||
File compressedImage = await compressImage(File(pickedImage.path));
|
||||
|
||||
// Save the picked image directly
|
||||
// File savedImage = File(pickedImage.path);
|
||||
print('link =$link');
|
||||
try {
|
||||
await uploadImage(
|
||||
compressedImage,
|
||||
{
|
||||
'driverID':
|
||||
box.read(BoxName.driverID) ?? box.read(BoxName.passengerID),
|
||||
'imageType': imageType
|
||||
},
|
||||
link,
|
||||
);
|
||||
} catch (e) {
|
||||
Get.snackbar('Image Upload Failed'.tr, e.toString(),
|
||||
backgroundColor: AppColor.redColor);
|
||||
} finally {
|
||||
isloading = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uploadImage(File file, Map data, String link) async {
|
||||
var request = http.MultipartRequest(
|
||||
'POST',
|
||||
Uri.parse(link),
|
||||
);
|
||||
|
||||
var length = await file.length();
|
||||
var stream = http.ByteStream(file.openRead());
|
||||
var multipartFile = http.MultipartFile(
|
||||
'image',
|
||||
stream,
|
||||
length,
|
||||
filename: basename(file.path),
|
||||
);
|
||||
request.headers.addAll({
|
||||
'Authorization':
|
||||
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
|
||||
});
|
||||
// Set the file name to the driverID
|
||||
request.files.add(
|
||||
http.MultipartFile(
|
||||
'image',
|
||||
stream,
|
||||
length,
|
||||
filename: '${box.read(BoxName.driverID)}.jpg',
|
||||
),
|
||||
);
|
||||
data.forEach((key, value) {
|
||||
request.fields[key] = value;
|
||||
});
|
||||
var myrequest = await request.send();
|
||||
var res = await http.Response.fromStream(myrequest);
|
||||
if (res.statusCode == 200) {
|
||||
Log.print('jsonDecode(res.body): ${jsonDecode(res.body)}');
|
||||
|
||||
Get.snackbar('title', 'message', backgroundColor: AppColor.greenColor);
|
||||
return jsonDecode(res.body);
|
||||
} else {
|
||||
throw Exception(
|
||||
'Failed to upload image: ${res.statusCode} - ${res.body}');
|
||||
}
|
||||
}
|
||||
|
||||
choosImagePicture(String link, String imageType) async {
|
||||
final pickedImage = await picker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
// preferredCameraDevice: CameraDevice.rear,
|
||||
// maxHeight: Get.height * .3,
|
||||
// maxWidth: Get.width * .9,
|
||||
// imageQuality: 100,
|
||||
);
|
||||
image = File(pickedImage!.path);
|
||||
|
||||
croppedFile = await ImageCropper().cropImage(
|
||||
sourcePath: image!.path,
|
||||
uiSettings: [
|
||||
AndroidUiSettings(
|
||||
toolbarTitle: 'Cropper'.tr,
|
||||
toolbarColor: AppColor.blueColor,
|
||||
toolbarWidgetColor: AppColor.yellowColor,
|
||||
initAspectRatio: CropAspectRatioPreset.original,
|
||||
lockAspectRatio: false),
|
||||
IOSUiSettings(
|
||||
title: 'Cropper'.tr,
|
||||
),
|
||||
],
|
||||
);
|
||||
myImage = File(pickedImage.path);
|
||||
isloading = true;
|
||||
update();
|
||||
// Save the cropped image
|
||||
// File savedCroppedImage = File(croppedFile!.path);
|
||||
File compressedImage = await compressImage(File(croppedFile!.path));
|
||||
print('link =$link');
|
||||
try {
|
||||
await uploadImage(
|
||||
compressedImage,
|
||||
{
|
||||
'driverID':
|
||||
box.read(BoxName.driverID) ?? box.read(BoxName.passengerID),
|
||||
'imageType': imageType
|
||||
},
|
||||
link,
|
||||
);
|
||||
} catch (e) {
|
||||
Get.snackbar('Image Upload Failed'.tr, e.toString(),
|
||||
backgroundColor: AppColor.redColor);
|
||||
} finally {
|
||||
isloading = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
uploadImagePicture(File file, Map data, String link) async {
|
||||
var request = http.MultipartRequest(
|
||||
'POST',
|
||||
Uri.parse(link), //'https://ride.mobile-app.store/uploadImage1.php'
|
||||
);
|
||||
|
||||
var length = await file.length();
|
||||
var stream = http.ByteStream(file.openRead());
|
||||
var multipartFile = http.MultipartFile(
|
||||
'image',
|
||||
stream,
|
||||
length,
|
||||
filename: basename(file.path),
|
||||
);
|
||||
request.headers.addAll({
|
||||
'Authorization':
|
||||
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
|
||||
});
|
||||
// Set the file name to the driverID
|
||||
request.files.add(
|
||||
http.MultipartFile(
|
||||
'image',
|
||||
stream,
|
||||
length,
|
||||
filename: '${box.read(BoxName.driverID)}.jpg',
|
||||
),
|
||||
);
|
||||
data.forEach((key, value) {
|
||||
request.fields[key] = value;
|
||||
});
|
||||
var myrequest = await request.send();
|
||||
var res = await http.Response.fromStream(myrequest);
|
||||
if (res.statusCode == 200) {
|
||||
return jsonDecode(res.body);
|
||||
} else {
|
||||
throw Exception(
|
||||
'Failed to upload image: ${res.statusCode} - ${res.body}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<File> compressImage(File file) async {
|
||||
final dir = await path_provider.getTemporaryDirectory();
|
||||
final targetPath = "${dir.absolute.path}/temp.jpg";
|
||||
|
||||
var result = await FlutterImageCompress.compressAndGetFile(
|
||||
file.absolute.path,
|
||||
targetPath,
|
||||
quality: 70,
|
||||
minWidth: 1024,
|
||||
minHeight: 1024,
|
||||
);
|
||||
|
||||
return File(result!.path);
|
||||
}
|
||||
|
||||
// Future<File> detectAndCropFace(File imageFile) async {
|
||||
// final inputImage = InputImage.fromFilePath(imageFile.path);
|
||||
// final options = FaceDetectorOptions(
|
||||
// enableClassification: false,
|
||||
// enableLandmarks: false,
|
||||
// enableTracking: false,
|
||||
// minFaceSize: 0.15,
|
||||
// performanceMode: FaceDetectorMode.accurate,
|
||||
// );
|
||||
// final faceDetector = FaceDetector(options: options);
|
||||
|
||||
// try {
|
||||
// final List<Face> faces = await faceDetector.processImage(inputImage);
|
||||
// final image = img.decodeImage(await imageFile.readAsBytes());
|
||||
|
||||
// if (image == null) throw Exception('Unable to decode image');
|
||||
|
||||
// int left, top, width, height;
|
||||
|
||||
// if (faces.isNotEmpty) {
|
||||
// // Face detected, crop around the face
|
||||
// final face = faces[0];
|
||||
// double padding = 0.2; // 20% padding
|
||||
// int paddingX = (face.boundingBox.width * padding).round();
|
||||
// int paddingY = (face.boundingBox.height * padding).round();
|
||||
|
||||
// left = (face.boundingBox.left - paddingX).round();
|
||||
// top = (face.boundingBox.top - paddingY).round();
|
||||
// width = (face.boundingBox.width + 2 * paddingX).round();
|
||||
// height = (face.boundingBox.height + 2 * paddingY).round();
|
||||
// } else {
|
||||
// // No face detected, crop the center of the image
|
||||
// int size = min(image.width, image.height);
|
||||
// left = (image.width - size) ~/ 2;
|
||||
// top = (image.height - size) ~/ 2;
|
||||
// width = size;
|
||||
// height = size;
|
||||
// }
|
||||
|
||||
// // Ensure dimensions are within image bounds
|
||||
// left = left.clamp(0, image.width - 1);
|
||||
// top = top.clamp(0, image.height - 1);
|
||||
// width = width.clamp(1, image.width - left);
|
||||
// height = height.clamp(1, image.height - top);
|
||||
|
||||
// final croppedImage =
|
||||
// img.copyCrop(image, x: left, y: top, width: width, height: height);
|
||||
|
||||
// // Save the cropped image
|
||||
// final tempDir = await path_provider.getTemporaryDirectory();
|
||||
// final tempPath = tempDir.path;
|
||||
// final croppedFile = File('$tempPath/cropped_image.jpg');
|
||||
// await croppedFile.writeAsBytes(img.encodeJpg(croppedImage, quality: 100));
|
||||
|
||||
// return croppedFile;
|
||||
// } finally {
|
||||
// faceDetector.close();
|
||||
// }
|
||||
// }
|
||||
108
lib/controller/functions/upload_image.dart
Normal file
108
lib/controller/functions/upload_image.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
// import 'dart:convert';
|
||||
// import 'dart:io';
|
||||
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:http/http.dart' as http;
|
||||
// import 'package:image_cropper/image_cropper.dart';
|
||||
// import 'package:image_picker/image_picker.dart';
|
||||
// import 'package:path/path.dart';
|
||||
|
||||
// import '../../constant/api_key.dart';
|
||||
// import '../../constant/box_name.dart';
|
||||
// import '../../constant/colors.dart';
|
||||
// import '../../main.dart';
|
||||
|
||||
// class ImageController extends GetxController {
|
||||
// File? myImage;
|
||||
// bool isloading = false;
|
||||
// CroppedFile? croppedFile;
|
||||
// final picker = ImagePicker();
|
||||
// var image;
|
||||
// choosImage(String link, String imageType) async {
|
||||
// final pickedImage = await picker.pickImage(source: ImageSource.gallery);
|
||||
// image = File(pickedImage!.path);
|
||||
// croppedFile = await ImageCropper().cropImage(
|
||||
// sourcePath: image!.path,
|
||||
// aspectRatioPresets: [
|
||||
// CropAspectRatioPreset.square,
|
||||
// CropAspectRatioPreset.ratio3x2,
|
||||
// CropAspectRatioPreset.original,
|
||||
// CropAspectRatioPreset.ratio4x3,
|
||||
// CropAspectRatioPreset.ratio16x9
|
||||
// ],
|
||||
// uiSettings: [
|
||||
// AndroidUiSettings(
|
||||
// toolbarTitle: 'Cropper'.tr,
|
||||
// toolbarColor: AppColor.blueColor,
|
||||
// toolbarWidgetColor: AppColor.yellowColor,
|
||||
// initAspectRatio: CropAspectRatioPreset.original,
|
||||
// lockAspectRatio: false),
|
||||
// IOSUiSettings(
|
||||
// title: 'Cropper'.tr,
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// myImage = File(pickedImage.path);
|
||||
// isloading = true;
|
||||
// update();
|
||||
// // Save the cropped image
|
||||
// File savedCroppedImage = File(croppedFile!.path);
|
||||
// try {
|
||||
// await uploadImage(
|
||||
// savedCroppedImage,
|
||||
// {
|
||||
// 'driverID':
|
||||
// box.read(BoxName.driverID) ?? box.read(BoxName.passengerID),
|
||||
// 'imageType': imageType
|
||||
// },
|
||||
// link,
|
||||
// );
|
||||
// } catch (e) {
|
||||
// Get.snackbar('Image Upload Failed'.tr, e.toString(),
|
||||
// backgroundColor: AppColor.redColor);
|
||||
// } finally {
|
||||
// isloading = false;
|
||||
// update();
|
||||
// }
|
||||
// }
|
||||
|
||||
// uploadImage(File file, Map data, String link) async {
|
||||
// var request = http.MultipartRequest(
|
||||
// 'POST',
|
||||
// Uri.parse(link), //'https://ride.mobile-app.store/uploadImage1.php'
|
||||
// );
|
||||
|
||||
// var length = await file.length();
|
||||
// var stream = http.ByteStream(file.openRead());
|
||||
// var multipartFile = http.MultipartFile(
|
||||
// 'image',
|
||||
// stream,
|
||||
// length,
|
||||
// filename: basename(file.path),
|
||||
// );
|
||||
// request.headers.addAll({
|
||||
// 'Authorization':
|
||||
// 'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
|
||||
// });
|
||||
// // Set the file name to the driverID
|
||||
// request.files.add(
|
||||
// http.MultipartFile(
|
||||
// 'image',
|
||||
// stream,
|
||||
// length,
|
||||
// filename: '${box.read(BoxName.driverID)}.jpg',
|
||||
// ),
|
||||
// );
|
||||
// data.forEach((key, value) {
|
||||
// request.fields[key] = value;
|
||||
// });
|
||||
// var myrequest = await request.send();
|
||||
// var res = await http.Response.fromStream(myrequest);
|
||||
// if (res.statusCode == 200) {
|
||||
// return jsonDecode(res.body);
|
||||
// } else {
|
||||
// throw Exception(
|
||||
// 'Failed to upload image: ${res.statusCode} - ${res.body}');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
64
lib/controller/functions/wallet.dart
Normal file
64
lib/controller/functions/wallet.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/colors.dart';
|
||||
|
||||
import '../../constant/links.dart';
|
||||
import '../firebase/firbase_messge.dart';
|
||||
import 'crud.dart';
|
||||
|
||||
class WalletController extends GetxController {
|
||||
String paymentToken = '';
|
||||
Future<String> generateTokenDriver(String amount, driverID) async {
|
||||
var res = await CRUD().post(link: AppLink.addPaymentTokenDriver, payload: {
|
||||
'driverID': driverID.toString(),
|
||||
'amount': amount.toString(),
|
||||
});
|
||||
var d = jsonDecode(res);
|
||||
return d['message'];
|
||||
}
|
||||
|
||||
addPaymentToDriver(String amount, driverID, token) async {
|
||||
paymentToken = await generateTokenDriver(amount.toString(), driverID);
|
||||
var res = await CRUD().post(link: AppLink.addDrivePayment, payload: {
|
||||
'rideId': 'gift_$driverID _${DateTime.now().toIso8601String()}',
|
||||
'amount': amount,
|
||||
'payment_method': 'visaRide',
|
||||
'passengerID': 'gift',
|
||||
'token': paymentToken,
|
||||
'driverID': driverID.toString(),
|
||||
});
|
||||
if (res != 'failure') {
|
||||
FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
||||
"لديك هدية من سفَر".tr,
|
||||
'لقد حصلت على هدية من سفر بقيمة $amount ',
|
||||
token, // Access token correctly
|
||||
'ding.wav',
|
||||
);
|
||||
Get.snackbar('success', 'addPaymentToDriver',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
} else {
|
||||
Get.snackbar('error', 'addPaymentToDriver',
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
|
||||
Future addSeferWallet(String point, driverID) async {
|
||||
var amount = (int.parse(point) * -1).toStringAsFixed(0);
|
||||
var seferToken = await generateTokenDriver(amount, driverID);
|
||||
var res = await CRUD().post(link: AppLink.addSeferWallet, payload: {
|
||||
'amount': amount.toString(),
|
||||
'paymentMethod': 'visaRide',
|
||||
'passengerId': 'gift$driverID',
|
||||
'token': seferToken,
|
||||
'driverId': driverID.toString(),
|
||||
});
|
||||
if (res != 'failure') {
|
||||
Get.snackbar('success', 'addSeferWallet',
|
||||
backgroundColor: AppColor.greenColor);
|
||||
} else {
|
||||
Get.snackbar('error', 'addSeferWallet',
|
||||
backgroundColor: AppColor.redColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
220
lib/controller/notification_controller.dart
Normal file
220
lib/controller/notification_controller.dart
Normal file
@@ -0,0 +1,220 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/box_name.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/firebase/firbase_messge.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
import 'package:sefer_admin1/main.dart';
|
||||
import 'package:sefer_admin1/views/widgets/elevated_btn.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_textField.dart';
|
||||
|
||||
import '../constant/style.dart';
|
||||
import '../print.dart';
|
||||
|
||||
class NotificationController extends GetxController {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final title = TextEditingController();
|
||||
final body = TextEditingController();
|
||||
List<String> tokensDriver = [];
|
||||
List<String> tokensPassengers = [];
|
||||
|
||||
getTokensDrivers() async {
|
||||
await FirebaseMessagesController().loadAllPagesAndSendNotifications();
|
||||
}
|
||||
|
||||
getTokensPassengers() async {
|
||||
await FirebaseMessagesController()
|
||||
.loadAllPagesAndSendNotificationsPassengers();
|
||||
}
|
||||
|
||||
Future<dynamic> sendNotificationDrivers() {
|
||||
return Get.defaultDialog(
|
||||
title: 'send notification'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: title,
|
||||
label: 'title notification'.tr,
|
||||
hint: 'title notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: body,
|
||||
label: 'body notification'.tr,
|
||||
hint: 'body notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'send'.tr,
|
||||
onPressed: () async {
|
||||
// tokensDriver = box.read(BoxName.tokensDrivers)['message'];
|
||||
// Log.print('tokensDriver: ${tokensDriver}');
|
||||
// if (formKey.currentState!.validate()) {
|
||||
box.read(BoxName.tokensDrivers)['message'].length;
|
||||
for (var i = 0;
|
||||
i < box.read(BoxName.tokensDrivers)['message'].length;
|
||||
i++) {
|
||||
// for (var i = 0; i < 2; i++) {
|
||||
// print(i);
|
||||
var res = await CRUD()
|
||||
.post(link: AppLink.addNotificationCaptain, payload: {
|
||||
"driverID": box
|
||||
.read(BoxName.tokensDrivers)['message'][i]['id']
|
||||
.toString(),
|
||||
"title": title.text,
|
||||
"body": body.text,
|
||||
"isPin": 'unPin',
|
||||
});
|
||||
Log.print(
|
||||
'res: ${res}for ${box.read(BoxName.tokensDrivers)['message'][i]['id']}');
|
||||
// Log.print('tokensDriver[i]: ${tokensDriver[i]}');
|
||||
Future.delayed(const Duration(microseconds: 50));
|
||||
|
||||
FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
||||
title.text,
|
||||
body.text,
|
||||
box
|
||||
.read(BoxName.tokensDrivers)['message'][i]['token']
|
||||
.toString(),
|
||||
'tone2.wav');
|
||||
}
|
||||
Get.back();
|
||||
// }
|
||||
}),
|
||||
cancel: MyElevatedButton(
|
||||
title: 'cancel',
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
|
||||
Future<dynamic> sendNotificationPassengers() {
|
||||
return Get.defaultDialog(
|
||||
title: 'send notification'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: title,
|
||||
label: 'title notification'.tr,
|
||||
hint: 'title notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MyTextForm(
|
||||
controller: body,
|
||||
label: 'body notification'.tr,
|
||||
hint: 'body notification'.tr,
|
||||
type: TextInputType.name),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'send'.tr,
|
||||
onPressed: () async {
|
||||
// tokensPassengers = box.read(BoxName.tokensPassengers);
|
||||
var tokensPassengersData =
|
||||
box.read(BoxName.tokensPassengers)['data'];
|
||||
|
||||
// Debug print to check structure of the 'data' field
|
||||
print('Tokens Passengers Data: $tokensPassengersData');
|
||||
|
||||
if (tokensPassengersData is List) {
|
||||
for (var i = 0; i < tokensPassengersData.length; i++) {
|
||||
if (formKey.currentState!.validate()) {
|
||||
var res = await CRUD()
|
||||
.post(link: AppLink.addNotificationPassenger, payload: {
|
||||
"passenger_id":
|
||||
tokensPassengersData[i]['passengerID'].toString(),
|
||||
"title": title.text,
|
||||
"body": body.text,
|
||||
});
|
||||
Log.print('res: ${res}');
|
||||
FirebaseMessagesController()
|
||||
.sendNotificationToAnyWithoutData(
|
||||
title.text,
|
||||
body.text,
|
||||
tokensPassengersData[i]['token']
|
||||
.toString(), // Access token correctly
|
||||
'order.wav',
|
||||
);
|
||||
}
|
||||
}
|
||||
Get.back();
|
||||
} else {
|
||||
// Handle the case where 'data' is not a list
|
||||
print('Data is not a list: $tokensPassengersData');
|
||||
}
|
||||
}),
|
||||
cancel: MyElevatedButton(
|
||||
title: 'cancel',
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
}
|
||||
// يلا دلوقتي! تطبيق سفر جاهز عشان تبدأ تستقبل الطلبات
|
||||
// • افتح التطبيق دلوقتي، واستعد إنك تستقبل طلبات أكتر. كل ما تكون فاتح، فرصتك في الطلبات بتزيد!
|
||||
// 2. خليك فاتح واستقبل طلبات أكتر مع تطبيق سفر
|
||||
// • وجودك متصل في التطبيق هيخليك تستقبل طلبات أكتر. افتح التطبيق دلوقتي وما تفوتش الفرصة!
|
||||
// 3. فرصتك لزيادة دخلك مع تطبيق سفر تبدأ من دلوقتي!
|
||||
// • مجرد إنك تفتح التطبيق مش هيأثر عليك، بالعكس، هيزود فرصتك في طلبات أكتر. افتح التطبيق واشترك دلوقتي!
|
||||
|
||||
//sms
|
||||
// link sefer driver is https://shorturl.at/IHJcm1.
|
||||
// // ميزات الأمان بعد 500 رحلة:
|
||||
// • “بعد 500 رحلة مع سفر، تحصل على مميزات أمان إضافية لضمان راحتك.”
|
||||
// • “نوفر لك ميزات أمان متقدمة بعد 500 رحلة لتجربة قيادة أكثر أمانًا.”
|
||||
// • “مع 500 رحلة، تحصل على دعم أمني متقدم لتوفير أفضل تجربة قيادة.”
|
||||
// 2. ميزات الصيانة:
|
||||
// • “احصل على خدمات صيانة مجانية بعد عدد معين من الرحلات مع سفر.”
|
||||
// • “استمتع بخدمات صيانة حصرية عند الوصول إلى عدد محدد من الرحلات.”
|
||||
// • “مع سفر، نقدم لك عروض صيانة مميزة لتحافظ على سيارتك في أفضل حال.”
|
||||
// 3. ميزات فتح حسابات البنوك:
|
||||
// • “مع سفر، يمكنك فتح حساب بنكي بسهولة واستفادة من عروض مميزة.”
|
||||
// • “افتح حساب بنكي مع تطبيق سفر واستفد من خدمات مالية حصرية.”
|
||||
// • “نساعدك على فتح حساب بنكي بأفضل العروض بالتعاون مع البنوك المحلية.”
|
||||
// 4. ميزات ورود السيارات ومعارض السيارات الخاصة بنا:
|
||||
// • “استمتع بعروض مميزة لشراء السيارات من معارض سفر الحصرية.”
|
||||
// • “اختر سيارتك المثالية من معارض سفر بأسعار تنافسية وخدمات مميزة.”
|
||||
// • “نقدم لك أفضل عروض السيارات من معارضنا لتسهيل امتلاك سيارتك الجديدة.”
|
||||
// 5. ميزات أوفر كار:
|
||||
// • “أوفر كار من سفر توفر لك سيارات اقتصادية لزيادة دخلك بكفاءة.”
|
||||
// • “مع أوفر كار، يمكنك العمل بسيارات اقتصادية وتحقيق أرباح أكبر.”
|
||||
// • “تطبيق سفر يقدم لك أوفر كار، الخيار الاقتصادي المثالي لزيادة دخلك.”
|
||||
// 6. مستوى الدخل المحدود والطلبات الاقتصادية:
|
||||
// • “لأصحاب الدخل المحدود، وفرنا طلبات اقتصادية تضمن لك زيادة دخلك.”
|
||||
// • “الطلبات الاقتصادية من سفر تساعدك على زيادة دخلك بسهولة وفعالية.”
|
||||
// • “استفد من طلبات اقتصادية تناسب أصحاب الدخل المحدود لزيادة أرباحك.”
|
||||
// 7. طلبات الليل:
|
||||
// • “مع طلبات الليل من سفر، زود دخلك واستفد من فرص إضافية في المساء.”
|
||||
// • “لا تفوت فرصة طلبات الليل مع سفر، زود دخلك في أي وقت.”
|
||||
// • “طلبات الليل من سفر توفر لك فرصًا إضافية لتحقيق دخل أعلى.”
|
||||
// 8. طلبات الكمفورت الأكثر راحة والسيارات المكيفة:
|
||||
// • “قدّم خدمة مريحة مع طلبات الكمفورت من سفر والسيارات المكيفة.”
|
||||
// • “طلبات الكمفورت توفر تجربة راقية للركاب بسيارات مكيفة ومريحة.”
|
||||
// • “مع سفر، سيارات الكمفورت المكيفة تضمن راحة الركاب وزيادة الطلبات.”
|
||||
// 9. طلبات السبيد:
|
||||
// • “استقبل طلبات السبيد مع سفر لتقديم رحلات أسرع وزيادة دخلك.”
|
||||
// • “طلبات السبيد توفر لك فرصة إكمال المزيد من الرحلات في وقت أقل.”
|
||||
// • “مع طلبات السبيد من سفر، تقدم خدمة سريعة وفعالة لزيادة الأرباح.”
|
||||
// 10. الطلبات الثابتة والمعتدلة السعر والنسبة الثابتة 8%:
|
||||
// • “مع نسبة ثابتة 8%، تحصل على أفضل عروض الأسعار مع سفر.”
|
||||
// • “استمتع بنسبة ثابتة 8%، أقل نسبة بين المنافسين لزيادة دخلك.”
|
||||
// • “طلبات سفر الثابتة تضمن لك دخلاً مستقراً بنسبة أقل من 8%.”
|
||||
328
lib/env/env.dart
vendored
Normal file
328
lib/env/env.dart
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
import 'package:envied/envied.dart';
|
||||
|
||||
part 'env.g.dart';
|
||||
|
||||
@Envied()
|
||||
abstract class Env {
|
||||
@EnviedField(varName: 'addd', obfuscate: true)
|
||||
static final String addd = _Env.addd;
|
||||
|
||||
@EnviedField(varName: 'initializationVector', obfuscate: true)
|
||||
static final String initializationVector = _Env.initializationVector;
|
||||
@EnviedField(varName: 'ALLOWED_ADMIN_PHONES', obfuscate: true)
|
||||
static final String ALLOWED_ADMIN_PHONES = _Env.ALLOWED_ADMIN_PHONES;
|
||||
|
||||
@EnviedField(varName: 'privateKeyFCM', obfuscate: true)
|
||||
static final String privateKeyFCM = _Env.privateKeyFCM;
|
||||
|
||||
@EnviedField(varName: 'passnpassenger', obfuscate: true)
|
||||
static final String passnpassenger = _Env.passnpassenger;
|
||||
|
||||
@EnviedField(varName: 'newId', obfuscate: true)
|
||||
static final String newId = _Env.newId;
|
||||
|
||||
@EnviedField(varName: 'allowed', obfuscate: true)
|
||||
static final String allowed = _Env.allowed;
|
||||
|
||||
@EnviedField(varName: 'basicAuthCredentials', obfuscate: true)
|
||||
static final String basicAuthCredentials = _Env.basicAuthCredentials;
|
||||
|
||||
@EnviedField(varName: 'basicCompareFaces', obfuscate: true)
|
||||
static final String basicCompareFaces = _Env.basicCompareFaces;
|
||||
|
||||
@EnviedField(varName: 'basicCompareFacesURL', obfuscate: true)
|
||||
static final String basicCompareFacesURL = _Env.basicCompareFacesURL;
|
||||
|
||||
@EnviedField(varName: 'accountSIDTwillo', obfuscate: true)
|
||||
static final String accountSIDTwillo = _Env.accountSIDTwillo;
|
||||
|
||||
@EnviedField(varName: 'serverAPI', obfuscate: true)
|
||||
static final String serverAPI = _Env.serverAPI;
|
||||
|
||||
@EnviedField(varName: 'mapAPIKEY', obfuscate: true)
|
||||
static final String mapAPIKEY = _Env.mapAPIKEY;
|
||||
|
||||
@EnviedField(varName: 'twilloRecoveryCode', obfuscate: true)
|
||||
static final String twilloRecoveryCode = _Env.twilloRecoveryCode;
|
||||
|
||||
@EnviedField(varName: 'authTokenTwillo', obfuscate: true)
|
||||
static final String authTokenTwillo = _Env.authTokenTwillo;
|
||||
|
||||
@EnviedField(varName: 'chatGPTkey', obfuscate: true)
|
||||
static final String chatGPTkey = _Env.chatGPTkey;
|
||||
|
||||
@EnviedField(varName: 'transactionCloude', obfuscate: true)
|
||||
static final String transactionCloude = _Env.transactionCloude;
|
||||
|
||||
@EnviedField(varName: 'visionApi', obfuscate: true)
|
||||
static final String visionApi = _Env.visionApi;
|
||||
|
||||
@EnviedField(varName: 'secretKey', obfuscate: true)
|
||||
static final String secretKey = _Env.secretKey;
|
||||
|
||||
@EnviedField(varName: 'stripe_publishableKe', obfuscate: true)
|
||||
static final String stripePublishableKe = _Env.stripePublishableKe;
|
||||
|
||||
@EnviedField(varName: 'chatGPTkeySefer', obfuscate: true)
|
||||
static final String chatGPTkeySefer = _Env.chatGPTkeySefer;
|
||||
|
||||
@EnviedField(varName: 'llamaKey', obfuscate: true)
|
||||
static final String llamaKey = _Env.llamaKey;
|
||||
|
||||
@EnviedField(varName: 'serverPHP', obfuscate: true)
|
||||
static final String serverPHP = _Env.serverPHP;
|
||||
|
||||
@EnviedField(varName: 'seferAlexandriaServer', obfuscate: true)
|
||||
static final String seferAlexandriaServer = _Env.seferAlexandriaServer;
|
||||
|
||||
@EnviedField(varName: 'whatsapp', obfuscate: true)
|
||||
static final String whatsapp = _Env.whatsapp;
|
||||
|
||||
@EnviedField(varName: 'whatappID', obfuscate: true)
|
||||
static final String whatappID = _Env.whatappID;
|
||||
|
||||
@EnviedField(varName: 'seferPaymentServer', obfuscate: true)
|
||||
static final String seferPaymentServer = _Env.seferPaymentServer;
|
||||
|
||||
@EnviedField(varName: 'seferCairoServer', obfuscate: true)
|
||||
static final String seferCairoServer = _Env.seferCairoServer;
|
||||
|
||||
@EnviedField(varName: 'seferGizaServer', obfuscate: true)
|
||||
static final String seferGizaServer = _Env.seferGizaServer;
|
||||
|
||||
@EnviedField(varName: 'chatGPTkeySeferNew', obfuscate: true)
|
||||
static final String chatGPTkeySeferNew = _Env.chatGPTkeySeferNew;
|
||||
|
||||
@EnviedField(varName: 'cohere', obfuscate: true)
|
||||
static final String cohere = _Env.cohere;
|
||||
|
||||
@EnviedField(varName: 'claudeAiAPI', obfuscate: true)
|
||||
static final String claudeAiAPI = _Env.claudeAiAPI;
|
||||
|
||||
@EnviedField(varName: 'payPalClientId', obfuscate: true)
|
||||
static final String payPalClientId = _Env.payPalClientId;
|
||||
|
||||
@EnviedField(varName: 'payPalSecret', obfuscate: true)
|
||||
static final String payPalSecret = _Env.payPalSecret;
|
||||
|
||||
@EnviedField(varName: 'geminiApi', obfuscate: true)
|
||||
static final String geminiApi = _Env.geminiApi;
|
||||
|
||||
@EnviedField(varName: 'geminiApiMasa', obfuscate: true)
|
||||
static final String geminiApiMasa = _Env.geminiApiMasa;
|
||||
|
||||
@EnviedField(varName: 'agoraAppId', obfuscate: true)
|
||||
static final String agoraAppId = _Env.agoraAppId;
|
||||
|
||||
@EnviedField(varName: 'agoraAppCertificate', obfuscate: true)
|
||||
static final String agoraAppCertificate = _Env.agoraAppCertificate;
|
||||
|
||||
@EnviedField(varName: 'payPalClientIdLive', obfuscate: true)
|
||||
static final String payPalClientIdLive = _Env.payPalClientIdLive;
|
||||
|
||||
@EnviedField(varName: 'payPalSecretLive', obfuscate: true)
|
||||
static final String payPalSecretLive = _Env.payPalSecretLive;
|
||||
|
||||
@EnviedField(varName: 'integrationIdPayMob', obfuscate: true)
|
||||
static final String integrationIdPayMob = _Env.integrationIdPayMob;
|
||||
|
||||
@EnviedField(varName: 'passwordPayMob', obfuscate: true)
|
||||
static final String passwordPayMob = _Env.passwordPayMob;
|
||||
|
||||
@EnviedField(varName: 'usernamePayMob', obfuscate: true)
|
||||
static final String usernamePayMob = _Env.usernamePayMob;
|
||||
|
||||
@EnviedField(varName: 'payMobApikey', obfuscate: true)
|
||||
static final String payMobApikey = _Env.payMobApikey;
|
||||
|
||||
@EnviedField(varName: 'integrationIdPayMobWallet', obfuscate: true)
|
||||
static final String integrationIdPayMobWallet =
|
||||
_Env.integrationIdPayMobWallet;
|
||||
|
||||
@EnviedField(varName: 'smsPasswordEgypt', obfuscate: true)
|
||||
static final String smsPasswordEgypt = _Env.smsPasswordEgypt;
|
||||
|
||||
@EnviedField(varName: 'ocpApimSubscriptionKey', obfuscate: true)
|
||||
static final String ocpApimSubscriptionKey = _Env.ocpApimSubscriptionKey;
|
||||
|
||||
@EnviedField(varName: 'chatGPTkeySeferNew4', obfuscate: true)
|
||||
static final String chatGPTkeySeferNew4 = _Env.chatGPTkeySeferNew4;
|
||||
|
||||
@EnviedField(varName: 'anthropicAIkeySeferNew', obfuscate: true)
|
||||
static final String anthropicAIkeySeferNew = _Env.anthropicAIkeySeferNew;
|
||||
|
||||
@EnviedField(varName: 'llama3Key', obfuscate: true)
|
||||
static final String llama3Key = _Env.llama3Key;
|
||||
|
||||
@EnviedField(varName: 'payMobOutClientSecrret', obfuscate: true)
|
||||
static final String payMobOutClientSecrret = _Env.payMobOutClientSecrret;
|
||||
|
||||
@EnviedField(varName: 'allowedWallet', obfuscate: true)
|
||||
static final String allowedWallet = _Env.allowedWallet;
|
||||
@EnviedField(varName: 'payMobOutClient_id', obfuscate: true)
|
||||
static final String payMobOutClient_id = _Env.payMobOutClient_id;
|
||||
|
||||
@EnviedField(varName: 'payMobOutPassword', obfuscate: true)
|
||||
static final String payMobOutPassword = _Env.payMobOutPassword;
|
||||
|
||||
@EnviedField(varName: 'payMobOutUserName', obfuscate: true)
|
||||
static final String payMobOutUserName = _Env.payMobOutUserName;
|
||||
|
||||
@EnviedField(varName: 'A', obfuscate: true)
|
||||
static final String A = _Env.A;
|
||||
|
||||
@EnviedField(varName: 'B', obfuscate: true)
|
||||
static final String B = _Env.B;
|
||||
|
||||
@EnviedField(varName: 'C', obfuscate: true)
|
||||
static final String C = _Env.C;
|
||||
|
||||
@EnviedField(varName: 'D', obfuscate: true)
|
||||
static final String D = _Env.D;
|
||||
|
||||
@EnviedField(varName: 'E', obfuscate: true)
|
||||
static final String E = _Env.E;
|
||||
|
||||
@EnviedField(varName: 'F', obfuscate: true)
|
||||
static final String F = _Env.F;
|
||||
|
||||
@EnviedField(varName: 'G', obfuscate: true)
|
||||
static final String G = _Env.G;
|
||||
|
||||
@EnviedField(varName: 'H', obfuscate: true)
|
||||
static final String H = _Env.H;
|
||||
|
||||
@EnviedField(varName: 'I', obfuscate: true)
|
||||
static final String I = _Env.I;
|
||||
|
||||
@EnviedField(varName: 'J', obfuscate: true)
|
||||
static final String J = _Env.J;
|
||||
|
||||
@EnviedField(varName: 'K', obfuscate: true)
|
||||
static final String K = _Env.K;
|
||||
|
||||
@EnviedField(varName: 'L', obfuscate: true)
|
||||
static final String L = _Env.L;
|
||||
|
||||
@EnviedField(varName: 'M', obfuscate: true)
|
||||
static final String M = _Env.M;
|
||||
|
||||
@EnviedField(varName: 'N', obfuscate: true)
|
||||
static final String N = _Env.N;
|
||||
|
||||
@EnviedField(varName: 'O', obfuscate: true)
|
||||
static final String O = _Env.O;
|
||||
|
||||
@EnviedField(varName: 'P', obfuscate: true)
|
||||
static final String P = _Env.P;
|
||||
|
||||
@EnviedField(varName: 'Q', obfuscate: true)
|
||||
static final String Q = _Env.Q;
|
||||
|
||||
@EnviedField(varName: 'R', obfuscate: true)
|
||||
static final String R = _Env.R;
|
||||
|
||||
@EnviedField(varName: 'S', obfuscate: true)
|
||||
static final String S = _Env.S;
|
||||
|
||||
@EnviedField(varName: 'T', obfuscate: true)
|
||||
static final String T = _Env.T;
|
||||
|
||||
@EnviedField(varName: 'U', obfuscate: true)
|
||||
static final String U = _Env.U;
|
||||
|
||||
@EnviedField(varName: 'V', obfuscate: true)
|
||||
static final String V = _Env.V;
|
||||
|
||||
@EnviedField(varName: 'W', obfuscate: true)
|
||||
static final String W = _Env.W;
|
||||
|
||||
@EnviedField(varName: 'X', obfuscate: true)
|
||||
static final String X = _Env.X;
|
||||
|
||||
@EnviedField(varName: 'Y', obfuscate: true)
|
||||
static final String Y = _Env.Y;
|
||||
|
||||
@EnviedField(varName: 'Z', obfuscate: true)
|
||||
static final String Z = _Env.Z;
|
||||
@EnviedField(varName: 'a', obfuscate: true)
|
||||
static final String a = _Env.a;
|
||||
|
||||
@EnviedField(varName: 'b', obfuscate: true)
|
||||
static final String b = _Env.b;
|
||||
|
||||
@EnviedField(varName: 'c', obfuscate: true)
|
||||
static final String c = _Env.c;
|
||||
|
||||
@EnviedField(varName: 'd', obfuscate: true)
|
||||
static final String d = _Env.d;
|
||||
|
||||
@EnviedField(varName: 'e', obfuscate: true)
|
||||
static final String e = _Env.e;
|
||||
|
||||
@EnviedField(varName: 'f', obfuscate: true)
|
||||
static final String f = _Env.f;
|
||||
|
||||
@EnviedField(varName: 'g', obfuscate: true)
|
||||
static final String g = _Env.g;
|
||||
|
||||
@EnviedField(varName: 'h', obfuscate: true)
|
||||
static final String h = _Env.h;
|
||||
|
||||
@EnviedField(varName: 'i', obfuscate: true)
|
||||
static final String i = _Env.i;
|
||||
|
||||
@EnviedField(varName: 'j', obfuscate: true)
|
||||
static final String j = _Env.j;
|
||||
|
||||
@EnviedField(varName: 'k', obfuscate: true)
|
||||
static final String k = _Env.k;
|
||||
|
||||
@EnviedField(varName: 'l', obfuscate: true)
|
||||
static final String l = _Env.l;
|
||||
|
||||
@EnviedField(varName: 'm', obfuscate: true)
|
||||
static final String m = _Env.m;
|
||||
|
||||
@EnviedField(varName: 'n', obfuscate: true)
|
||||
static final String n = _Env.n;
|
||||
|
||||
@EnviedField(varName: 'o', obfuscate: true)
|
||||
static final String o = _Env.o;
|
||||
|
||||
@EnviedField(varName: 'p', obfuscate: true)
|
||||
static final String p = _Env.p;
|
||||
|
||||
@EnviedField(varName: 'q', obfuscate: true)
|
||||
static final String q = _Env.q;
|
||||
|
||||
@EnviedField(varName: 'r', obfuscate: true)
|
||||
static final String r = _Env.r;
|
||||
|
||||
@EnviedField(varName: 's', obfuscate: true)
|
||||
static final String s = _Env.s;
|
||||
|
||||
@EnviedField(varName: 't', obfuscate: true)
|
||||
static final String t = _Env.t;
|
||||
|
||||
@EnviedField(varName: 'u', obfuscate: true)
|
||||
static final String u = _Env.u;
|
||||
|
||||
@EnviedField(varName: 'v', obfuscate: true)
|
||||
static final String v = _Env.v;
|
||||
|
||||
@EnviedField(varName: 'w', obfuscate: true)
|
||||
static final String w = _Env.w;
|
||||
|
||||
@EnviedField(varName: 'x', obfuscate: true)
|
||||
static final String x = _Env.x;
|
||||
|
||||
@EnviedField(varName: 'y', obfuscate: true)
|
||||
static final String y = _Env.y;
|
||||
|
||||
@EnviedField(varName: 'z', obfuscate: true)
|
||||
static final String z = _Env.z;
|
||||
|
||||
@EnviedField(varName: 'keyOfApp', obfuscate: true)
|
||||
static final String keyOfApp = _Env.keyOfApp;
|
||||
}
|
||||
13808
lib/env/env.g.dart
vendored
Normal file
13808
lib/env/env.g.dart
vendored
Normal file
File diff suppressed because it is too large
Load Diff
70
lib/firebase_options.dart
Normal file
70
lib/firebase_options.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for web - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyCFsWBqvkXzk1Gb-bCGxwqTwJQKIeHjH64',
|
||||
appId: '1:1086900987150:android:7f0b54792b737a3d77a35f',
|
||||
messagingSenderId: '1086900987150',
|
||||
projectId: 'intaleq-d48a7',
|
||||
storageBucket: 'intaleq-d48a7.firebasestorage.app',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyAwG09AeehwBfktpKKJwCKQOtEUpHtr-p0',
|
||||
appId: '1:1086900987150:ios:db95474c7ff8899a77a35f',
|
||||
messagingSenderId: '1086900987150',
|
||||
projectId: 'intaleq-d48a7',
|
||||
storageBucket: 'intaleq-d48a7.firebasestorage.app',
|
||||
androidClientId: '1086900987150-060srlmdjocdcav377rbur4ka14m90b7.apps.googleusercontent.com',
|
||||
iosClientId: '1086900987150-n48ncfe3ud1khvncsgcmdbtpkhg2jfce.apps.googleusercontent.com',
|
||||
iosBundleId: 'com.intaleq.intaleqAdmin',
|
||||
);
|
||||
}
|
||||
69
lib/main.dart
Normal file
69
lib/main.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:sefer_admin1/views/auth/login_page.dart';
|
||||
|
||||
import 'controller/firebase/firbase_messge.dart';
|
||||
import 'controller/functions/encrypt_decrypt.dart';
|
||||
import 'firebase_options.dart';
|
||||
import 'models/db_sql.dart';
|
||||
import 'views/admin/admin_home_page.dart';
|
||||
|
||||
final box = GetStorage();
|
||||
const storage = FlutterSecureStorage();
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> backgroundMessageHandler(RemoteMessage message) async {
|
||||
await Firebase.initializeApp();
|
||||
if (message.data.isNotEmpty && message.notification != null) {
|
||||
FirebaseMessagesController().fireBaseTitles(message);
|
||||
}
|
||||
}
|
||||
|
||||
DbSql sql = DbSql.instance;
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await GetStorage.init();
|
||||
await EncryptionHelper.initialize();
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
await FirebaseMessagesController().requestFirebaseMessagingPermission();
|
||||
|
||||
FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
|
||||
|
||||
List<Future> initializationTasks = [
|
||||
FirebaseMessagesController().getNotificationSettings(),
|
||||
FirebaseMessagesController().getToken(),
|
||||
];
|
||||
|
||||
await Future.wait(initializationTasks);
|
||||
SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
} // Enable Crashlytics collection
|
||||
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError;
|
||||
|
||||
runApp(const MainApp());
|
||||
}
|
||||
|
||||
class MainApp extends StatelessWidget {
|
||||
const MainApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: AdminLoginPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
116
lib/models/db_sql.dart
Normal file
116
lib/models/db_sql.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
import '../constant/table_names.dart';
|
||||
|
||||
class DbSql {
|
||||
static final DbSql instance = DbSql._();
|
||||
|
||||
static Database? _database;
|
||||
|
||||
DbSql._();
|
||||
|
||||
Future<Database> get database async {
|
||||
if (_database != null) return _database!;
|
||||
_database = await _initDatabase();
|
||||
return _database!;
|
||||
}
|
||||
|
||||
Future<Database> _initDatabase() async {
|
||||
String path = join(await getDatabasesPath(), 'my_database.db');
|
||||
return await openDatabase(
|
||||
path,
|
||||
version: 1,
|
||||
onCreate: (db, version) async {
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.carLocations}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
driver_id TEXT,
|
||||
latitude REAL,
|
||||
longitude REAL,
|
||||
created_at TEXT,
|
||||
updated_at TEXT
|
||||
)
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.placesFavorite}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
latitude REAL,
|
||||
longitude REAL,
|
||||
name TEXT UNIQUE,
|
||||
rate TEXT
|
||||
)
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.recentLocations}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
latitude REAL,
|
||||
longitude REAL,
|
||||
name TEXT ,
|
||||
rate TEXT
|
||||
)
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.driverOrdersRefuse}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
order_id TEXT UNIQUE,
|
||||
created_at TEXT,
|
||||
driver_id TEXT
|
||||
)
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.rideLocation}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
order_id TEXT ,
|
||||
created_at TEXT,
|
||||
lat TEXT,
|
||||
lng TEXT
|
||||
)
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.faceDetectTimes}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
faceDetectTimes INTEGER
|
||||
)
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS ${TableName.captainNotification}(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
faceDetectTimes INTEGER
|
||||
)
|
||||
''');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> getAllData(String table) async {
|
||||
Database db = await instance.database;
|
||||
return await db.query(table);
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> getCustomQuery(String query) async {
|
||||
Database db = await instance.database;
|
||||
return await db.rawQuery(query);
|
||||
}
|
||||
|
||||
Future<int> insertData(Map<String, dynamic> map, String table) async {
|
||||
Database db = await instance.database;
|
||||
return await db.insert(table, map);
|
||||
}
|
||||
|
||||
Future<int> updateData(Map<String, dynamic> map, String table, int id) async {
|
||||
Database db = await instance.database;
|
||||
|
||||
return await db.update(table, map, where: 'id = ?', whereArgs: [id]);
|
||||
}
|
||||
|
||||
Future<int> deleteData(String table, int id) async {
|
||||
Database db = await instance.database;
|
||||
return await db.delete(table, where: 'id = ?', whereArgs: [id]);
|
||||
}
|
||||
|
||||
Future<int> deleteAllData(String table) async {
|
||||
Database db = await instance.database;
|
||||
return await db.delete(table);
|
||||
}
|
||||
}
|
||||
40
lib/models/feedback_qury.sql
Normal file
40
lib/models/feedback_qury.sql
Normal file
@@ -0,0 +1,40 @@
|
||||
-- Frequent Complaint Passengers
|
||||
SELECT
|
||||
passengers.id AS passenger_id,
|
||||
passengers.first_name,
|
||||
passengers.last_name,
|
||||
passengers.phone,
|
||||
COUNT(`feedBack`.id) AS complaint_count
|
||||
FROM
|
||||
passengers
|
||||
JOIN `feedBack` ON passengers.id = `feedBack`.`passengerId`
|
||||
GROUP BY
|
||||
passengers.id
|
||||
ORDER BY
|
||||
complaint_count
|
||||
DESC
|
||||
LIMIT 10;
|
||||
--==========
|
||||
-- to get all driver payment to pay to them
|
||||
SELECT
|
||||
p.driverID,
|
||||
COALESCE(SUM(p.amount), 0) AS total_amount,
|
||||
COALESCE(SUM(p.amount), 0) + COALESCE(pd.total_points, 0) AS diff
|
||||
FROM
|
||||
payments p
|
||||
JOIN (
|
||||
SELECT
|
||||
driverID,
|
||||
SUM(amount) AS total_points
|
||||
FROM
|
||||
paymentsDriverPoints
|
||||
WHERE
|
||||
payment_method = 'fromBudgetToPoints'
|
||||
GROUP BY
|
||||
driverID
|
||||
) pd ON p.driverID = pd.driverID
|
||||
WHERE
|
||||
p.isGiven = 'waiting'
|
||||
AND p.payment_method IN ('visa-in', 'visa', 'visaRide', 'TransferFrom', 'payout', 'TransferTo')
|
||||
GROUP BY
|
||||
p.driverID;
|
||||
21
lib/models/model/admin/monthly_ride.dart
Normal file
21
lib/models/model/admin/monthly_ride.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
class MonthlyDataModel {
|
||||
final int year;
|
||||
final int month;
|
||||
final int day;
|
||||
final int ridesCount;
|
||||
|
||||
MonthlyDataModel({
|
||||
required this.year,
|
||||
required this.month,
|
||||
required this.day,
|
||||
required this.ridesCount,
|
||||
});
|
||||
|
||||
factory MonthlyDataModel.fromJson(Map<String, dynamic> json) =>
|
||||
MonthlyDataModel(
|
||||
year: json['year'] as int,
|
||||
month: json['month'] as int,
|
||||
day: json['day'] as int,
|
||||
ridesCount: json['rides_count'] as int,
|
||||
);
|
||||
}
|
||||
79
lib/models/model/admin/passenger_model.dart
Normal file
79
lib/models/model/admin/passenger_model.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
class Passenger {
|
||||
String id;
|
||||
String phone;
|
||||
String email;
|
||||
String gender;
|
||||
String status;
|
||||
String birthdate;
|
||||
String site;
|
||||
String firstName;
|
||||
String lastName;
|
||||
String sosPhone;
|
||||
String education;
|
||||
String employmentType;
|
||||
String maritalStatus;
|
||||
String createdAt;
|
||||
String updatedAt;
|
||||
int countPassenger;
|
||||
int countFeedback;
|
||||
double ratingPassenger;
|
||||
int countDriverRate;
|
||||
int countPassengerCancel;
|
||||
double passengerAverageRating;
|
||||
int countPassengerRate;
|
||||
int countPassengerRide;
|
||||
|
||||
Passenger({
|
||||
required this.id,
|
||||
required this.phone,
|
||||
required this.email,
|
||||
required this.gender,
|
||||
required this.status,
|
||||
required this.birthdate,
|
||||
required this.site,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.sosPhone,
|
||||
required this.education,
|
||||
required this.employmentType,
|
||||
required this.maritalStatus,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.countPassenger,
|
||||
required this.countFeedback,
|
||||
required this.ratingPassenger,
|
||||
required this.countDriverRate,
|
||||
required this.countPassengerCancel,
|
||||
required this.passengerAverageRating,
|
||||
required this.countPassengerRate,
|
||||
required this.countPassengerRide,
|
||||
});
|
||||
|
||||
factory Passenger.fromJson(Map<String, dynamic> json) {
|
||||
return Passenger(
|
||||
id: json['id'],
|
||||
phone: json['phone'],
|
||||
email: json['email'],
|
||||
gender: json['gender'],
|
||||
status: json['status'],
|
||||
birthdate: json['birthdate'],
|
||||
site: json['site'],
|
||||
firstName: json['first_name'],
|
||||
lastName: json['last_name'],
|
||||
sosPhone: json['sosPhone'],
|
||||
education: json['education'],
|
||||
employmentType: json['employmentType'],
|
||||
maritalStatus: json['maritalStatus'],
|
||||
createdAt: json['created_at'],
|
||||
updatedAt: json['updated_at'],
|
||||
countPassenger: json['countPassenger'],
|
||||
countFeedback: json['countFeedback'],
|
||||
ratingPassenger: json['ratingPassenger'].toDouble(),
|
||||
countDriverRate: json['countDriverRate'],
|
||||
countPassengerCancel: json['countPassengerCancel'],
|
||||
passengerAverageRating: json['passengerAverageRating'].toDouble(),
|
||||
countPassengerRate: json['countPassengerRate'],
|
||||
countPassengerRide: json['countPassengerRide'],
|
||||
);
|
||||
}
|
||||
}
|
||||
12
lib/models/model/admin/rides_summary_model.dart
Normal file
12
lib/models/model/admin/rides_summary_model.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
class MonthlyDataModel {
|
||||
int day;
|
||||
int totalDuration;
|
||||
|
||||
MonthlyDataModel({required this.day, required this.totalDuration});
|
||||
|
||||
factory MonthlyDataModel.fromJson(Map<String, dynamic> json) =>
|
||||
MonthlyDataModel(
|
||||
day: int.parse(json['day'].toString().split('-')[2]),
|
||||
totalDuration:
|
||||
int.parse(json['total_duration'].toString().split(':')[0]));
|
||||
}
|
||||
34
lib/models/model/locations.dart
Normal file
34
lib/models/model/locations.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
class CarLocationModel {
|
||||
String id;
|
||||
String driverId;
|
||||
double latitude;
|
||||
double heading;
|
||||
double speed;
|
||||
double longitude;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
|
||||
CarLocationModel({
|
||||
required this.id,
|
||||
required this.driverId,
|
||||
required this.latitude,
|
||||
required this.longitude,
|
||||
required this.heading,
|
||||
required this.speed,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
factory CarLocationModel.fromJson(Map<String, dynamic> json) {
|
||||
return CarLocationModel(
|
||||
id: json['id'],
|
||||
driverId: json['driver_id'],
|
||||
latitude: double.parse(json['latitude'].toString()),
|
||||
longitude: double.parse(json['longitude'].toString()),
|
||||
heading: double.parse(json['heading'].toString()),
|
||||
speed: double.parse(json['speed'].toString()),
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
);
|
||||
}
|
||||
}
|
||||
30
lib/models/model/onboarding_model.dart
Normal file
30
lib/models/model/onboarding_model.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
List<OnBoardingModel> onBoardingList = [
|
||||
OnBoardingModel(
|
||||
title: 'Welcome to Sefer!'.tr,
|
||||
image: 'assets/images/on1.png',
|
||||
body:
|
||||
'Sefer is the ride-hailing app that is safe, reliable, and accessible.'
|
||||
.tr,
|
||||
),
|
||||
OnBoardingModel(
|
||||
title: 'Get to your destination quickly and easily.'.tr,
|
||||
image: 'assets/images/on2.png',
|
||||
body: 'With Sefer, you can get a ride to your destination in minutes.'.tr,
|
||||
),
|
||||
OnBoardingModel(
|
||||
title: 'Enjoy a safe and comfortable ride.'.tr,
|
||||
image: 'assets/images/on3.png',
|
||||
body:
|
||||
'Sefer is committed to safety, and all of our captains are carefully screened and background checked.'
|
||||
.tr,
|
||||
),
|
||||
];
|
||||
|
||||
class OnBoardingModel {
|
||||
final String? title;
|
||||
final String? image;
|
||||
final String? body;
|
||||
OnBoardingModel({this.body, this.title, this.image});
|
||||
}
|
||||
77
lib/models/model/passengers_model.dart
Normal file
77
lib/models/model/passengers_model.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
class MonthlyPassengerInstall {
|
||||
int day;
|
||||
int totalPassengers;
|
||||
|
||||
MonthlyPassengerInstall({required this.day, required this.totalPassengers});
|
||||
|
||||
factory MonthlyPassengerInstall.fromJson(Map<String, dynamic> json) =>
|
||||
MonthlyPassengerInstall(
|
||||
day: int.parse(json['day'].toString().split('-')[2]),
|
||||
totalPassengers:
|
||||
int.parse(json['totalPassengers'].toString().split(':')[0]));
|
||||
}
|
||||
|
||||
class MonthlyRidesInstall {
|
||||
int day;
|
||||
int totalRides;
|
||||
|
||||
MonthlyRidesInstall({required this.day, required this.totalRides});
|
||||
|
||||
factory MonthlyRidesInstall.fromJson(Map<String, dynamic> json) =>
|
||||
MonthlyRidesInstall(
|
||||
day: int.parse(json['day'].toString().split('-')[2]),
|
||||
totalRides: int.parse(json['totalRides'].toString().split(':')[0]));
|
||||
}
|
||||
|
||||
class MonthlyEmployeeData {
|
||||
int day;
|
||||
int totalEmployees;
|
||||
String name;
|
||||
|
||||
MonthlyEmployeeData(
|
||||
{required this.day, required this.totalEmployees, required this.name});
|
||||
|
||||
factory MonthlyEmployeeData.fromJson(Map<String, dynamic> json) =>
|
||||
MonthlyEmployeeData(
|
||||
day: int.parse(json['date'].toString().split('-')[2]), // Extract day
|
||||
totalEmployees: json['count'],
|
||||
name: json['NAME'],
|
||||
);
|
||||
}
|
||||
|
||||
class MonthlyDriverInstall {
|
||||
int day;
|
||||
int totalDrivers;
|
||||
int dailyTotalDrivers;
|
||||
int dailyTotalCallingDrivers;
|
||||
int dailyMatchingNotes;
|
||||
int totalMonthlyDrivers;
|
||||
int totalMonthlyCallingDrivers;
|
||||
int totalMonthlyMatchingNotes;
|
||||
|
||||
MonthlyDriverInstall({
|
||||
required this.day,
|
||||
required this.totalDrivers,
|
||||
required this.dailyTotalDrivers,
|
||||
required this.dailyTotalCallingDrivers,
|
||||
required this.dailyMatchingNotes,
|
||||
required this.totalMonthlyDrivers,
|
||||
required this.totalMonthlyCallingDrivers,
|
||||
required this.totalMonthlyMatchingNotes,
|
||||
});
|
||||
|
||||
factory MonthlyDriverInstall.fromJson(Map<String, dynamic> json) =>
|
||||
MonthlyDriverInstall(
|
||||
day: int.parse(json['day'].toString().split('-')[2]),
|
||||
totalDrivers: int.parse(json['totalDrivers'].toString()),
|
||||
dailyTotalDrivers: int.parse(json['dailyTotalDrivers'].toString()),
|
||||
dailyTotalCallingDrivers:
|
||||
int.parse(json['dailyTotalCallingDrivers'].toString()),
|
||||
dailyMatchingNotes: int.parse(json['dailyMatchingNotes'].toString()),
|
||||
totalMonthlyDrivers: int.parse(json['totalMonthlyDrivers'].toString()),
|
||||
totalMonthlyCallingDrivers:
|
||||
int.parse(json['totalMonthlyCallingDrivers'].toString()),
|
||||
totalMonthlyMatchingNotes:
|
||||
int.parse(json['totalMonthlyMatchingNotes'].toString()),
|
||||
);
|
||||
}
|
||||
13
lib/print.dart
Normal file
13
lib/print.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'dart:developer' as developer;
|
||||
|
||||
class Log {
|
||||
Log._();
|
||||
|
||||
static void print(String value, {StackTrace? stackTrace}) {
|
||||
developer.log(value, name: 'LOG', stackTrace: stackTrace);
|
||||
}
|
||||
|
||||
static Object? inspect(Object? object) {
|
||||
return developer.inspect(object);
|
||||
}
|
||||
}
|
||||
475
lib/views/admin/admin_home_page.dart
Normal file
475
lib/views/admin/admin_home_page.dart
Normal file
@@ -0,0 +1,475 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/colors.dart';
|
||||
import 'package:sefer_admin1/controller/admin/dashboard_controller.dart';
|
||||
import 'package:sefer_admin1/controller/admin/register_captain_controller.dart';
|
||||
import 'package:sefer_admin1/controller/admin/static_controller.dart';
|
||||
import 'package:sefer_admin1/controller/notification_controller.dart';
|
||||
import 'package:sefer_admin1/main.dart';
|
||||
import 'package:sefer_admin1/views/admin/captain/drivers_cant_registe.dart';
|
||||
import 'package:sefer_admin1/views/widgets/mycircular.dart';
|
||||
|
||||
// Please make sure all these imports are correct for your project structure
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../controller/functions/crud.dart';
|
||||
import '../invoice/invoice_list_page.dart';
|
||||
import '../widgets/my_scafold.dart';
|
||||
import '../widgets/my_textField.dart';
|
||||
import '../invoice/add_invoice_page.dart';
|
||||
import 'captain/captain.dart';
|
||||
import 'dashboard_widget.dart'; // Assuming DashboardStatCard is here
|
||||
import 'drivers/driver_the_best.dart';
|
||||
import 'employee/employee_page.dart';
|
||||
import 'packages.dart';
|
||||
import 'passenger/passenger.dart';
|
||||
import 'rides/rides.dart';
|
||||
import 'static/static.dart';
|
||||
import 'wallet/wallet.dart';
|
||||
|
||||
class AdminHomePage extends StatelessWidget {
|
||||
AdminHomePage({super.key});
|
||||
|
||||
// Responsive grid column calculation
|
||||
int _calculateCrossAxisCount(BuildContext context) {
|
||||
double screenWidth = MediaQuery.of(context).size.width;
|
||||
if (screenWidth > 1200) return 5; // Large desktops
|
||||
if (screenWidth > 900) return 4; // Desktops
|
||||
if (screenWidth > 600) return 3; // Tablets
|
||||
return 2; // Phones
|
||||
}
|
||||
|
||||
// Helper to format currency
|
||||
String _formatCurrency(dynamic value) {
|
||||
if (value == null) return '\$0.00';
|
||||
final number = double.tryParse(value.toString());
|
||||
if (number != null) return '\$${number.toStringAsFixed(2)}';
|
||||
return '\$0.00';
|
||||
}
|
||||
|
||||
final TextEditingController _messageController = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Make sure DashboardController is initialized
|
||||
final DashboardController dashboardController =
|
||||
Get.put(DashboardController());
|
||||
|
||||
// Action items list with Arabic titles
|
||||
final List<Map<String, dynamic>> actionItems = [
|
||||
{
|
||||
'title': 'الركاب',
|
||||
'icon': Icons.people_alt_outlined,
|
||||
'onPressed': () => Get.to(() => Passengrs(),
|
||||
transition: Transition.rightToLeftWithFade)
|
||||
},
|
||||
{
|
||||
'title': 'الكباتن',
|
||||
'icon': Icons.sports_motorsports_outlined,
|
||||
'onPressed': () =>
|
||||
Get.to(() => Captain(), transition: Transition.rightToLeftWithFade)
|
||||
},
|
||||
{
|
||||
'title': 'المحفظة',
|
||||
'icon': Icons.account_balance_wallet_outlined,
|
||||
'onPressed': () =>
|
||||
Get.to(() => Wallet(), transition: Transition.rightToLeftWithFade)
|
||||
},
|
||||
{
|
||||
'title': 'الرحلات',
|
||||
'icon': Icons.directions_car_filled_outlined,
|
||||
'onPressed': () =>
|
||||
Get.to(() => Rides(), transition: Transition.rightToLeftWithFade)
|
||||
},
|
||||
{
|
||||
'title': 'الإحصائيات',
|
||||
'icon': Icons.bar_chart_outlined,
|
||||
'onPressed': () async {
|
||||
await Get.put(StaticController()).getAll();
|
||||
Get.to(() => const StaticDash());
|
||||
}
|
||||
},
|
||||
{
|
||||
'title': 'إرسال واتساب للسائقين',
|
||||
'icon': Icons.message_outlined,
|
||||
'iconColor': Colors.green.shade600,
|
||||
'onPressed': () => _showWhatsAppDialog(context)
|
||||
},
|
||||
{
|
||||
'title': 'إرسال إشعار للسائقين',
|
||||
'icon': Icons.notifications_active_outlined,
|
||||
'onPressed': () async =>
|
||||
await Get.put(NotificationController()).getTokensDrivers()
|
||||
},
|
||||
{
|
||||
'title': 'إرسال إشعار للركاب',
|
||||
'icon': Icons.notification_important_outlined,
|
||||
'onPressed': () async =>
|
||||
await Get.put(NotificationController()).getTokensPassengers()
|
||||
},
|
||||
{
|
||||
'title': 'تسجيل كابتن جديد',
|
||||
'icon': Icons.person_add_alt_1_outlined,
|
||||
'onPressed': () async {
|
||||
await Get.put(RegisterCaptainController())
|
||||
.getDriverNotCompleteRegistration();
|
||||
Get.to(() => const DriversCantRegister());
|
||||
}
|
||||
},
|
||||
{
|
||||
'title': 'تحديث الباقات',
|
||||
'icon': Icons.inventory_2_outlined,
|
||||
'onPressed': () => Get.to(() => PackageUpdateScreen())
|
||||
},
|
||||
{
|
||||
'title': 'الموظفون',
|
||||
'icon': Icons.badge_outlined,
|
||||
'onPressed': () => Get.to(() => EmployeePage())
|
||||
},
|
||||
{
|
||||
'title': 'أفضل السائقين',
|
||||
'icon': Icons.star_border_purple500_outlined,
|
||||
'onPressed': () => Get.to(() => DriverTheBest())
|
||||
},
|
||||
{
|
||||
'title': 'إضافة فاتورة',
|
||||
'icon': Icons.post_add_outlined,
|
||||
// 'onPressed': () => Get.to(() => AddInvoicePage())
|
||||
'onPressed': () => Get.to(() => InvoiceListPage())
|
||||
},
|
||||
{
|
||||
'title': 'إضافة جهاز كمسؤول',
|
||||
'icon': Icons.admin_panel_settings_outlined,
|
||||
'onPressed': () async => await CRUD()
|
||||
.post(link: AppLink.addAdminUser, payload: {'name': 'b'})
|
||||
},
|
||||
];
|
||||
|
||||
return MyScafolld(
|
||||
title: 'لوحة التحكم الرئيسية',
|
||||
action: IconButton(
|
||||
onPressed: () async {
|
||||
await dashboardController.getDashBoard();
|
||||
},
|
||||
icon: const Icon(Icons.refresh, color: AppColor.primaryColor, size: 28),
|
||||
tooltip: 'تحديث',
|
||||
),
|
||||
body: [
|
||||
GetBuilder<DashboardController>(builder: (controller) {
|
||||
if (controller.dashbord.isEmpty) {
|
||||
return const MyCircularProgressIndicator();
|
||||
}
|
||||
|
||||
// Main data map for easier access
|
||||
final data = controller.dashbord[0];
|
||||
|
||||
// Stat cards list with Arabic titles
|
||||
final List<Map<String, dynamic>> statCards = [
|
||||
{
|
||||
'title': 'رصيد الرسائل',
|
||||
'value': controller.creditSMS.toString(),
|
||||
'icon': Icons.sms_outlined,
|
||||
'color': Colors.lightBlue
|
||||
},
|
||||
{
|
||||
'title': 'الركاب',
|
||||
'value': data['countPassengers'].toString(),
|
||||
'icon': Icons.people_alt_outlined,
|
||||
'color': Colors.teal
|
||||
},
|
||||
{
|
||||
'title': 'السائقون',
|
||||
'value': data['countDriver'].toString(),
|
||||
'icon': Icons.sports_motorsports_outlined,
|
||||
'color': Colors.orange
|
||||
},
|
||||
{
|
||||
'title': 'رحلات الشهر',
|
||||
'value': data['countRideThisMonth'].toString(),
|
||||
'icon': Icons.calendar_month_outlined,
|
||||
'color': Colors.purple
|
||||
},
|
||||
{
|
||||
'title': 'متوسط التكلفة',
|
||||
'value': _formatCurrency(data['avg_passenger_price']),
|
||||
'icon': Icons.monetization_on_outlined,
|
||||
'color': Colors.green
|
||||
},
|
||||
{
|
||||
'title': 'الرحلات المكتملة',
|
||||
'value': data['completed_rides'].toString(),
|
||||
'icon': Icons.check_circle_outline,
|
||||
'color': AppColor.greenColor
|
||||
},
|
||||
{
|
||||
'title': 'الرحلات الملغاة',
|
||||
'value': data['cancelled_rides'].toString(),
|
||||
'icon': Icons.cancel_outlined,
|
||||
'color': AppColor.redColor
|
||||
},
|
||||
{
|
||||
'title': 'مدفوعات السائقين',
|
||||
'value': _formatCurrency(data['payments']),
|
||||
'icon': Icons.payments_outlined,
|
||||
'color': Colors.indigo
|
||||
},
|
||||
{
|
||||
'title': 'محفظة انطلق',
|
||||
'value': _formatCurrency(data['seferWallet']),
|
||||
'icon': Icons.account_balance_wallet_outlined,
|
||||
'color': Colors.deepOrange
|
||||
},
|
||||
{
|
||||
'title': 'عدد التحويلات',
|
||||
'value': data['transfer_from_count'].toString(),
|
||||
'icon': Icons.swap_horiz_outlined,
|
||||
'color': Colors.brown
|
||||
},
|
||||
{
|
||||
'title': 'رحلات الصباح',
|
||||
'value': data['morning_ride_count'].toString(),
|
||||
'icon': Icons.wb_sunny_outlined,
|
||||
'color': Colors.amber.shade700
|
||||
},
|
||||
{
|
||||
'title': 'رحلات المساء',
|
||||
'value': data['evening_ride_count'].toString(),
|
||||
'icon': Icons.brightness_4_outlined,
|
||||
'color': Colors.blueGrey
|
||||
},
|
||||
{
|
||||
'title': 'رحلات الليل',
|
||||
'value': data['night_ride_count'].toString(),
|
||||
'icon': Icons.nightlight_round_outlined,
|
||||
'color': Colors.black87
|
||||
},
|
||||
{
|
||||
'title': 'نوع كومفورت',
|
||||
'value': data['comfort'].toString(),
|
||||
'icon': Icons.event_seat_outlined,
|
||||
'color': Colors.cyan
|
||||
},
|
||||
{
|
||||
'title': 'نوع سبيد',
|
||||
'value': data['speed'].toString(),
|
||||
'icon': Icons.speed_outlined,
|
||||
'color': Colors.red.shade700
|
||||
},
|
||||
{
|
||||
'title': 'نوع ليدي',
|
||||
'value': data['lady'].toString(),
|
||||
'icon': Icons.woman_2_outlined,
|
||||
'color': Colors.pink
|
||||
},
|
||||
];
|
||||
|
||||
return AnimationLimiter(
|
||||
child: ListView(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0),
|
||||
children: [
|
||||
// --- Statistics Grid Section ---
|
||||
AnimationLimiter(
|
||||
child: GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: _calculateCrossAxisCount(context),
|
||||
mainAxisSpacing: 12.0,
|
||||
crossAxisSpacing: 12.0,
|
||||
childAspectRatio: 1.8,
|
||||
),
|
||||
itemCount: statCards.length,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
final card = statCards[index];
|
||||
return AnimationConfiguration.staggeredGrid(
|
||||
position: index,
|
||||
duration: const Duration(milliseconds: 375),
|
||||
columnCount: _calculateCrossAxisCount(context),
|
||||
child: ScaleAnimation(
|
||||
child: FadeInAnimation(
|
||||
child: DashboardStatCard(
|
||||
title: card['title'] as String,
|
||||
value: card['value'].toString(),
|
||||
icon: card['icon'] as IconData,
|
||||
iconColor: card['color'] as Color,
|
||||
valueColor: (card['color'] as Color),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
Text("الإجراءات السريعة",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleLarge
|
||||
?.copyWith(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// --- Admin Actions List Section ---
|
||||
AnimationLimiter(
|
||||
child: ListView.builder(
|
||||
itemCount: actionItems.length,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
final item = actionItems[index];
|
||||
return AnimationConfiguration.staggeredList(
|
||||
position: index,
|
||||
duration: const Duration(milliseconds: 375),
|
||||
child: SlideAnimation(
|
||||
verticalOffset: 50.0,
|
||||
child: FadeInAnimation(
|
||||
child: AdminActionTile(
|
||||
title: item['title'] as String,
|
||||
icon: item['icon'] as IconData,
|
||||
onPressed: item['onPressed'] as void Function(),
|
||||
iconColor: item['iconColor'] as Color?,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
isleading: false,
|
||||
);
|
||||
}
|
||||
|
||||
void _showWhatsAppDialog(BuildContext context) {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||
title: Text('تأكيد إرسال الرسائل؟'),
|
||||
content: MyTextForm(
|
||||
controller: _messageController,
|
||||
label: 'الرسالة',
|
||||
hint: 'أدخل نص الرسالة هنا',
|
||||
type: TextInputType.text,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_messageController.clear();
|
||||
Get.back();
|
||||
},
|
||||
child: Text('إلغاء'),
|
||||
),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColor.primaryColor),
|
||||
onPressed: () async {
|
||||
if (_messageController.text.isNotEmpty) {
|
||||
Get.back(); // Close dialog first
|
||||
var driverPhones =
|
||||
box.read(BoxName.tokensDrivers)['message'] as List?;
|
||||
if (driverPhones == null || driverPhones.isEmpty) {
|
||||
Get.snackbar('خطأ', 'لم يتم العثور على أرقام هواتف للسائقين.',
|
||||
snackPosition: SnackPosition.BOTTOM);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var driverData in driverPhones) {
|
||||
if (driverData['phone'] != null) {
|
||||
await CRUD().sendWhatsAppAuth(
|
||||
driverData['phone'].toString(),
|
||||
_messageController.text,
|
||||
);
|
||||
// Random delay to avoid being flagged as spam
|
||||
await Future.delayed(
|
||||
Duration(seconds: Random().nextInt(5) + 2));
|
||||
}
|
||||
}
|
||||
_messageController.clear();
|
||||
Get.snackbar(
|
||||
'نجاح',
|
||||
'تم إرسال الرسائل بنجاح',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.green.shade100,
|
||||
colorText: Colors.black,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text('إرسال', style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
],
|
||||
),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Renamed for clarity and improved design
|
||||
class AdminActionTile extends StatelessWidget {
|
||||
const AdminActionTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.onPressed,
|
||||
required this.icon,
|
||||
this.iconColor,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final VoidCallback onPressed;
|
||||
final IconData icon;
|
||||
final Color? iconColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6.0),
|
||||
child: Material(
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: InkWell(
|
||||
onTap: onPressed,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 18.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
border: Border.all(color: Colors.grey.withOpacity(0.2))),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 26,
|
||||
color: iconColor ?? AppColor.primaryColor,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
223
lib/views/admin/captain/captain.dart
Normal file
223
lib/views/admin/captain/captain.dart
Normal file
@@ -0,0 +1,223 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/captain_admin_controller.dart';
|
||||
import '../../../controller/functions/encrypt_decrypt.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
import '../../widgets/my_textField.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
import 'captain_details.dart';
|
||||
import 'form_captain.dart';
|
||||
|
||||
class Captain extends StatelessWidget {
|
||||
Captain({super.key});
|
||||
final CaptainAdminController captainAdminController =
|
||||
Get.put(CaptainAdminController());
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(
|
||||
title: 'Captain'.tr,
|
||||
body: [
|
||||
GetBuilder<CaptainAdminController>(
|
||||
builder: (captainAdminController) => Column(
|
||||
children: [
|
||||
captainAdminController.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
captainAdmin(
|
||||
captainAdminController,
|
||||
'Captains Count',
|
||||
'countPassenger',
|
||||
),
|
||||
MyElevatedButton(
|
||||
title: 'Add Prize to Gold Captains',
|
||||
onPressed: () {
|
||||
var date = DateTime.now();
|
||||
var day = date.weekday;
|
||||
|
||||
if (day == 6) {
|
||||
// Saturday is 6
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'Add Prize to Gold Captains',
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Add Points to their wallet as prize'
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Form(
|
||||
key: captainAdminController
|
||||
.formCaptainPrizeKey,
|
||||
child: MyTextForm(
|
||||
controller:
|
||||
captainAdminController
|
||||
.captainPrizeController,
|
||||
label:
|
||||
'Count of prize'
|
||||
.tr,
|
||||
hint: 'Count of prize'
|
||||
.tr,
|
||||
type: TextInputType
|
||||
.number))
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Add',
|
||||
onPressed: () async {
|
||||
if (captainAdminController
|
||||
.formCaptainPrizeKey
|
||||
.currentState!
|
||||
.validate()) {
|
||||
captainAdminController
|
||||
.addCaptainsPrizeToWalletSecure();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'This day is not allowed',
|
||||
titleStyle: AppStyle.title,
|
||||
middleText:
|
||||
'Saturday only Allowed day',
|
||||
middleTextStyle: AppStyle.title,
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
//todo search
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Container(
|
||||
width: Get.width,
|
||||
height: 110,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2,
|
||||
color: AppColor.greenColor)),
|
||||
child: formSearchCaptain()
|
||||
// ],
|
||||
// ),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Get.height * .5,
|
||||
child: ListView.builder(
|
||||
itemCount: captainAdminController
|
||||
.captainData['message'].length,
|
||||
itemBuilder: (context, index) {
|
||||
final user = captainAdminController
|
||||
.captainData['message'][index];
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Get.to(const CaptainsDetailsPage(),
|
||||
arguments: {
|
||||
'data': user,
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 2)),
|
||||
child: ListTile(
|
||||
title: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Name : ${(user['first_name'])} ${(user['last_name'])}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Rating : ${user['ratingPassenger']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Count Trip : ${user['countPassengerRide']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Count Driver Rate : ${user['countDriverRate']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
))
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
|
||||
Container captainAdmin(CaptainAdminController captainAdminController,
|
||||
String title, String jsonField) {
|
||||
return Container(
|
||||
height: Get.height * .1,
|
||||
decoration: BoxDecoration(border: Border.all(width: 2)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
title.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
captainAdminController.captainData['message'][0][jsonField]
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
167
lib/views/admin/captain/captain_details.dart
Normal file
167
lib/views/admin/captain/captain_details.dart
Normal file
@@ -0,0 +1,167 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/captain_admin_controller.dart';
|
||||
import '../../../controller/firebase/firbase_messge.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
import '../../widgets/my_textField.dart';
|
||||
|
||||
class CaptainsDetailsPage extends StatelessWidget {
|
||||
const CaptainsDetailsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final arguments = Get.arguments;
|
||||
final Map<String, dynamic> data = arguments['data'];
|
||||
var key = Get.find<CaptainAdminController>().formCaptainPrizeKey;
|
||||
var titleNotify = Get.find<CaptainAdminController>().titleNotify;
|
||||
var bodyNotify = Get.find<CaptainAdminController>().bodyNotify;
|
||||
return MyScafolld(
|
||||
title: data['first_name'] + ' ' + data['last_name'],
|
||||
body: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Email is ${data['email']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Phone is ${data['phone']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'gender is ${data['gender']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'status is ${data['status']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'birthdate is ${data['birthdate']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'site is ${data['site']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
// Text(
|
||||
// 'sosPhone is ${data['sosPhone']}',
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Count Feedback is ${data['countFeedback']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Count Driver Rate is ${data['countDriverRate']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Count Cancel is ${data['countPassengerCancel']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Count Ride is ${data['countPassengerRide']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Rating Captain Avarage is ${data['passengerAverageRating']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Rating is ${data['ratingPassenger']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 3, color: AppColor.yellowColor)),
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
Get.defaultDialog(
|
||||
title: 'Send Notification'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Form(
|
||||
key: key,
|
||||
child: Column(
|
||||
children: [
|
||||
MyTextForm(
|
||||
controller: titleNotify,
|
||||
label: 'title'.tr,
|
||||
hint: 'title notificaton'.tr,
|
||||
type: TextInputType.name),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
MyTextForm(
|
||||
controller: bodyNotify,
|
||||
label: 'body'.tr,
|
||||
hint: 'body notificaton'.tr,
|
||||
type: TextInputType.name)
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Send',
|
||||
onPressed: () {
|
||||
if (key.currentState!.validate()) {
|
||||
FirebaseMessagesController()
|
||||
.sendNotificationToAnyWithoutData(
|
||||
titleNotify.text,
|
||||
bodyNotify.text,
|
||||
data['passengerToken'],
|
||||
'order.wav');
|
||||
Get.back();
|
||||
}
|
||||
}));
|
||||
},
|
||||
child: Text(
|
||||
"Send Notificaion to Captains ".tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
54
lib/views/admin/captain/drivers_cant_registe.dart
Normal file
54
lib/views/admin/captain/drivers_cant_registe.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/views/admin/captain/register_captain.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../controller/admin/register_captain_controller.dart';
|
||||
|
||||
class DriversCantRegister extends StatelessWidget {
|
||||
const DriversCantRegister({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(RegisterCaptainController());
|
||||
return MyScafolld(
|
||||
title: 'drivers cant register'.tr,
|
||||
body: [
|
||||
GetBuilder<RegisterCaptainController>(builder: (mainController) {
|
||||
return ListView.builder(
|
||||
itemCount: mainController.driverNotCompleteRegistration.length,
|
||||
itemBuilder: (context, index) {
|
||||
final driver =
|
||||
mainController.driverNotCompleteRegistration[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Get.to(() => RegisterCaptain(), arguments: {
|
||||
"phone_number": driver['phone_number'].toString(),
|
||||
'driverId': driver['driverId'].toString(),
|
||||
'email': driver['email'].toString(),
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
color: driver['note'] == null
|
||||
? AppColor.greenColor
|
||||
: AppColor.accentColor,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(driver['phone_number'].toString()),
|
||||
Text(driver['driverId'].toString()),
|
||||
Text(driver['email'].toString()),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
isleading: true);
|
||||
}
|
||||
}
|
||||
84
lib/views/admin/captain/form_captain.dart
Normal file
84
lib/views/admin/captain/form_captain.dart
Normal file
@@ -0,0 +1,84 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/captain_admin_controller.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import 'captain_details.dart';
|
||||
|
||||
GetBuilder<CaptainAdminController> formSearchCaptain() {
|
||||
// DbSql sql = DbSql.instance;
|
||||
return GetBuilder<CaptainAdminController>(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Container(
|
||||
decoration:
|
||||
const BoxDecoration(color: AppColor.secondaryColor),
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.only(),
|
||||
gapPadding: 4,
|
||||
borderSide: BorderSide(
|
||||
color: AppColor.redColor,
|
||||
width: 2,
|
||||
)),
|
||||
suffixIcon: InkWell(
|
||||
onTap: () async {
|
||||
if (controller.captainController.text.length > 4) {
|
||||
await controller.getCaptains();
|
||||
|
||||
Get.defaultDialog(
|
||||
title: controller.captain['message'][0]
|
||||
['email'],
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Name is ${controller.captain['message'][0]['first_name']} ${controller.captain['message'][0]['last_name']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'phone is ${controller.captain['message'][0]['phone']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Go To Details'.tr,
|
||||
onPressed: () {
|
||||
Get.to(
|
||||
() => const CaptainsDetailsPage(),
|
||||
arguments: {
|
||||
'data': controller
|
||||
.captain['message'][0],
|
||||
});
|
||||
}));
|
||||
}
|
||||
},
|
||||
child: const Icon(Icons.search)),
|
||||
hintText: 'Search for Passenger'.tr,
|
||||
hintStyle: AppStyle.title,
|
||||
hintMaxLines: 1,
|
||||
prefixIcon: IconButton(
|
||||
onPressed: () async {
|
||||
controller.captainController.clear();
|
||||
// controller.clearPlaces();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.clear,
|
||||
color: Colors.red[300],
|
||||
),
|
||||
),
|
||||
),
|
||||
controller: controller.captainController,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
982
lib/views/admin/captain/register_captain.dart
Normal file
982
lib/views/admin/captain/register_captain.dart
Normal file
@@ -0,0 +1,982 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/controller/admin/register_captain_controller.dart';
|
||||
import '../../../../constant/colors.dart';
|
||||
import '../../../../constant/links.dart';
|
||||
import '../../../../constant/style.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
|
||||
class RegisterCaptain extends StatelessWidget {
|
||||
RegisterCaptain({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = Get.put(RegisterCaptainController());
|
||||
// String text = '';
|
||||
controller.driveInit();
|
||||
return MyScafolld(
|
||||
title: 'Documents check'.tr,
|
||||
action: GetBuilder<RegisterCaptainController>(builder: (controller) {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
controller.isLoading = false;
|
||||
controller.update();
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
);
|
||||
}),
|
||||
body: [
|
||||
GetBuilder<RegisterCaptainController>(builder: (controller) {
|
||||
return controller.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
(controller.responseIdCardDriverEgyptBack.isNotEmpty &&
|
||||
controller.responseIdCardDriverEgyptFront
|
||||
.isNotEmpty &&
|
||||
controller.responseIdEgyptFront.isNotEmpty &&
|
||||
controller.responseIdEgyptBack.isNotEmpty &&
|
||||
controller
|
||||
.responseIdEgyptDriverLicense.isNotEmpty
|
||||
// &&
|
||||
// controller
|
||||
// .responseCriminalRecordEgypt.isNotEmpty
|
||||
)
|
||||
? MyElevatedButton(
|
||||
title: 'Next'.tr,
|
||||
onPressed: () {
|
||||
controller.addDriverAndCarEgypt();
|
||||
})
|
||||
: const SizedBox(),
|
||||
SizedBox(
|
||||
height:
|
||||
(controller.responseIdCardDriverEgyptBack
|
||||
.isNotEmpty &&
|
||||
controller.responseIdCardDriverEgyptFront
|
||||
.isNotEmpty &&
|
||||
controller
|
||||
.responseIdEgyptFront.isNotEmpty &&
|
||||
controller
|
||||
.responseIdEgyptBack.isNotEmpty &&
|
||||
controller.responseIdEgyptDriverLicense
|
||||
.isNotEmpty
|
||||
// &&
|
||||
// controller.responseCriminalRecordEgypt
|
||||
// .isNotEmpty
|
||||
)
|
||||
? Get.height * .7
|
||||
: Get.height * .85,
|
||||
child: ListView(
|
||||
children: [
|
||||
egyptDriverLicense(),
|
||||
egyptCarLicenceFront(),
|
||||
egyptCarLicenceBack(),
|
||||
egyptDriverIDFront(),
|
||||
egyptDriverIDBack(),
|
||||
// egyptCriminalRecord(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
isleading: true);
|
||||
}
|
||||
|
||||
GetBuilder<RegisterCaptainController> egyptDriverLicense() {
|
||||
return GetBuilder<RegisterCaptainController>(
|
||||
builder: (ai) {
|
||||
if (ai.responseIdEgyptDriverLicense.isNotEmpty) {
|
||||
final expiryDate = ai.responseIdEgyptDriverLicense['expiry_date'];
|
||||
|
||||
// Check if the expiry date is before today
|
||||
final today = DateTime.now();
|
||||
|
||||
// Try parsing the expiry date. If it fails, set it to null.
|
||||
final expiryDateTime = DateTime.tryParse(expiryDate);
|
||||
final isExpired =
|
||||
expiryDateTime != null && expiryDateTime.isBefore(today);
|
||||
|
||||
return Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Driver\'s License'.tr, style: AppStyle.headTitle2),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await ai.allMethodForAI("""
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"license_type": "",
|
||||
"national_number": "",
|
||||
"name_arabic": "",
|
||||
"name_english": "",
|
||||
"firstName": "",
|
||||
"lastName": "",
|
||||
"address": "",
|
||||
"issue_date": "", // Format: YYYY-MM-DD using Latin numerals (0-9)
|
||||
"expiry_date": "", // Format: YYYY-MM-DD using Latin numerals (0-9)
|
||||
"employmentType": "",
|
||||
"license_categories": []
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. Ensure all dates are in the format YYYY-MM-DD using Latin (Western) numerals (0-9), not Arabic numerals.
|
||||
2. The 'license_categories' should be an array, even if there's only one category.
|
||||
3. Fill in all fields based on the information provided in the Arabic text.
|
||||
4. If any information is missing, leave the field as an empty string or empty array as appropriate.
|
||||
""", 'driver_license', ai.driverId); //egypt
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
const Divider(color: AppColor.accentColor),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'License Type'.tr}: ${ai.responseIdEgyptDriverLicense['license_type']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'National Number'.tr}: ${ai.responseIdEgyptDriverLicense['national_number']}',
|
||||
style: AppStyle.title.copyWith(
|
||||
color: ai.responseIdEgyptDriverLicense[
|
||||
'national_number'] ==
|
||||
ai.responseIdEgyptBack['nationalID']
|
||||
? AppColor.greenColor
|
||||
: AppColor.redColor),
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Name (Arabic)'.tr}: ${ai.responseIdEgyptDriverLicense['name_arabic']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Name (English)'.tr}: ${ai.responseIdEgyptDriverLicense['name_english']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Address'.tr}: ${ai.responseIdEgyptDriverLicense['address']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Issue Date'.tr}: ${ai.responseIdEgyptDriverLicense['issue_date']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Expiry Date'.tr}: ${ai.responseIdEgyptDriverLicense['expiry_date']}',
|
||||
style: AppStyle.title.copyWith(
|
||||
color:
|
||||
!isExpired ? AppColor.greenColor : AppColor.redColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'License Categories'.tr}: ${ai.responseIdEgyptDriverLicense['license_categories']}',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await ai.allMethodForAI("""
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"license_type": "",
|
||||
"national_number": "",
|
||||
"name_arabic": "",
|
||||
"name_english": "",
|
||||
"firstName": "",
|
||||
"lastName": "",
|
||||
"address": "",
|
||||
"issue_date": "", // Format: YYYY-MM-DD using Latin numerals (0-9)
|
||||
"expiry_date": "", // Format: YYYY-MM-DD using Latin numerals (0-9)
|
||||
"employmentType": "",
|
||||
"license_categories": []
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. Ensure all dates are in the format YYYY-MM-DD using Latin (Western) numerals (0-9), not Arabic numerals.
|
||||
2. The 'license_categories' should be an array, even if there's only one category.
|
||||
3. Fill in all fields based on the information provided in the Arabic text.
|
||||
4. If any information is missing, leave the field as an empty string or empty array as appropriate.
|
||||
""", 'driver_license', ai.driverId); //egypt
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Image.network(
|
||||
'${AppLink.server}/card_image/driver_license-${ai.driverId}.jpg',
|
||||
height: Get.height * .25,
|
||||
width: double.maxFinite,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
Text(
|
||||
'Capture an Image of Your Driver License'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GetBuilder<RegisterCaptainController> egyptDriverIDBack() {
|
||||
return GetBuilder<RegisterCaptainController>(
|
||||
builder: (ai) {
|
||||
if (ai.responseIdEgyptBack.isNotEmpty) {
|
||||
final taxExpiryDate = ai.responseIdEgyptBack['expirationDate'];
|
||||
|
||||
// Check if the tax expiry date is before today
|
||||
final today = DateTime.now();
|
||||
|
||||
// Try parsing the tax expiry date. If it fails, set it to null.
|
||||
final taxExpiryDateTime = DateTime.tryParse(taxExpiryDate);
|
||||
final isExpired =
|
||||
taxExpiryDateTime != null && taxExpiryDateTime.isBefore(today);
|
||||
|
||||
return Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('ID Documents Back'.tr, style: AppStyle.headTitle2),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await ai.allMethodForAI("""
|
||||
Write a JSON from the following information extracted from the provided Arabic text:
|
||||
- nationalID(in Latin numerals)
|
||||
- issueDate (in format YYYY-MM-DD using Latin numerals)
|
||||
- occupation
|
||||
- gender
|
||||
- religion
|
||||
- maritalStatus
|
||||
- fullNameMarital (if maritalStatus is "أعزب", set this to "none")
|
||||
- expirationDate (in format YYYY-MM-DD using Latin numerals)
|
||||
|
||||
Please ensure all date fields use Latin (Western) numerals (0-9) instead of Arabic numerals. For example, use "2023-04-03" instead of "٢٠٢٣-٠٤-٠٣".
|
||||
""", 'id_back', ai.driverId); //egypt
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
const Divider(color: AppColor.accentColor),
|
||||
const SizedBox(height: 8.0),
|
||||
// Assuming these keys exist in ai.responseIdEgyptFront
|
||||
Text(
|
||||
'${'National ID'.tr}: ${ai.responseIdEgyptBack['nationalID']}',
|
||||
style: AppStyle.title.copyWith(
|
||||
color: ai.responseIdEgyptDriverLicense[
|
||||
'national_number'] ==
|
||||
ai.responseIdEgyptBack['nationalID']
|
||||
? AppColor.greenColor
|
||||
: AppColor.redColor),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Occupation'.tr}: ${ai.responseIdEgyptBack['occupation']}', // Assuming 'occupation' exists
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Issue Date'.tr}: ${ai.responseIdEgyptBack['issueDate']}', // Assuming 'issueDate' exists
|
||||
),
|
||||
Text(
|
||||
'${'Gender'.tr}: ${ai.responseIdEgyptBack['gender']}', // Assuming 'gender' exists
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// '${'Religion'.tr}: ${ai.responseIdEgyptBack['religion']}', // Assuming 'religion' exists
|
||||
// ),
|
||||
// Text(
|
||||
// '${'Marital Status'.tr}: ${ai.responseIdEgyptBack['maritalStatus']}', // Assuming 'maritalStatus' exists
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 8.0),
|
||||
// Text(
|
||||
// '${'Full Name (Marital)'.tr}: ${ai.responseIdEgyptBack['fullNameMaritial']}', // Assuming 'fullNameMaritial' exists
|
||||
// ),
|
||||
// const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Expiration Date'.tr}: ${ai.responseIdEgyptBack['expirationDate']}', // Assuming 'expirationDate' exists
|
||||
style: AppStyle.title.copyWith(
|
||||
color: !isExpired
|
||||
? AppColor.greenColor
|
||||
: AppColor.redColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await ai.allMethodForAI('''
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"nationalID": "",//(in Latin numerals)
|
||||
"issueDate": "", // Format: YYYY-MM-DD using Latin numerals (0-9)
|
||||
"occupation": "",
|
||||
"gender": "",
|
||||
"religion": "",
|
||||
"maritalStatus": "",
|
||||
"fullNameMaritial": "", // Set to "none" if maritalStatus is "أعزب"
|
||||
"expirationDate": "" // Format: YYYY-MM-DD using Latin numerals (0-9)
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. Ensure all dates (issueDate and expirationDate) are in the format YYYY-MM-DD using Latin (Western) numerals (0-9), not Arabic numerals.
|
||||
2. If maritalStatus is "أعزب" (single), set fullNameMaritial to "none".
|
||||
3. Fill in all fields based on the information provided in the Arabic text.
|
||||
4. If any information is missing, leave the field as an empty string.
|
||||
''', 'id_back', ai.driverId); //egypt
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Image.network(
|
||||
'${AppLink.server}/card_image/id_back-${ai.driverId}.jpg',
|
||||
height: Get.height * .25,
|
||||
width: double.maxFinite,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
Text(
|
||||
'Capture an Image of Your ID Document Back'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GetBuilder<RegisterCaptainController> egyptDriverIDFront() {
|
||||
return GetBuilder<RegisterCaptainController>(
|
||||
builder: (ai) {
|
||||
if (ai.responseIdEgyptFront.isNotEmpty) {
|
||||
return Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('ID Documents Front'.tr, style: AppStyle.headTitle2),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await ai.allMethodForAI('''
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"first_name": "", // The word next to "بطاقة تحقيق الشخصية" (National Identification Card)
|
||||
"full_name": "", // The full name on the next line after the first name
|
||||
"address": "", // The complete address spanning the next two lines
|
||||
"national_number": "", // The National ID number before the last line (convert Arabic numerals to Latin)
|
||||
"card_id": "", // The card ID in English on the last line
|
||||
"dob": "" // Year of birth only, in Latin numerals (YYYY format)
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For 'first_name', extract the word immediately following "بطاقة تحقيق الشخصية".
|
||||
2. 'full_name' should be the complete name found on the line after the first name.
|
||||
3. 'address' should combine information from two consecutive lines.
|
||||
4. Convert the 'national_number' from Arabic numerals to Latin numerals (0-9).
|
||||
5. 'card_id' should be extracted as-is from the last line (it's already in English).
|
||||
6. For 'dob', include only the year of birth in YYYY format using Latin numerals.
|
||||
7. If any information is missing, leave the field as an empty string.
|
||||
''', 'id_front', ai.driverId); //egypt
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
const Divider(color: AppColor.accentColor),
|
||||
const SizedBox(height: 8.0),
|
||||
// Removed Make, Model, etc. as they are not available
|
||||
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'First Name'.tr}: ${ai.responseIdEgyptFront['first_name']}',
|
||||
),
|
||||
Text(
|
||||
'${'CardID'.tr}: ${ai.responseIdEgyptFront['card_id']}',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Full Name'.tr}: ${ai.responseIdEgyptFront['full_name']}',
|
||||
),
|
||||
Text(
|
||||
'${'DOB'.tr}: ${ai.responseIdEgyptFront['dob']}',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Address'.tr}: ${ai.responseIdEgyptFront['address']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
// Text(
|
||||
// '${'National Number'.tr}: ${ai.responseIdEgyptFront['national_number']}',
|
||||
// ),
|
||||
// const SizedBox(height: 8.0),
|
||||
|
||||
// Removed Inspection Date as it's not available
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await ai.allMethodForAI(""""
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"first_name": "", // The word next to "بطاقة تحقيق الشخصية" (National Identification Card)
|
||||
"full_name": "", // The full name on the next line after the first name
|
||||
"address": "", // The complete address spanning the next two lines
|
||||
"national_number": "", // The National ID number before the last line (convert Arabic numerals to Latin)
|
||||
"card_id": "", // The card ID in English on the last line
|
||||
"dob": "" // Year of birth only, in Latin numerals (YYYY format)
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For 'first_name', extract the word immediately following "بطاقة تحقيق الشخصية".
|
||||
2. 'full_name' should be the complete name found on the line after the first name.
|
||||
3. 'address' should combine information from two consecutive lines.
|
||||
4. Convert the 'national_number' from Arabic numerals to Latin numerals (0-9).
|
||||
5. 'card_id' should be extracted as-is from the last line (it's already in English).
|
||||
6. For 'dob', include only the year of birth in YYYY format using Latin numerals.
|
||||
7. If any information is missing, leave the field as an empty string.
|
||||
""", 'id_front', ai.driverId); //egypt
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Image.network(
|
||||
'${AppLink.server}/card_image/id_front-${ai.driverId}.png',
|
||||
height: Get.height * .25,
|
||||
width: double.maxFinite,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
Text(
|
||||
'Capture an Image of Your ID Document front'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GetBuilder<RegisterCaptainController> egyptCarLicenceFront() {
|
||||
return GetBuilder<RegisterCaptainController>(
|
||||
builder: (ai) {
|
||||
if (ai.responseIdCardDriverEgyptFront.isNotEmpty) {
|
||||
// No need to access ai.responseIdCardDriverEgyptBack anymore
|
||||
final licenseExpiryDate = DateTime.parse(
|
||||
ai.responseIdCardDriverEgyptFront['LicenseExpirationDate']);
|
||||
|
||||
// Check if license has expired
|
||||
final today = DateTime.now();
|
||||
final isLicenseExpired = licenseExpiryDate.isBefore(today);
|
||||
|
||||
return Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text('Vehicle Details Front'.tr,
|
||||
style: AppStyle.headTitle2),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
ai.allMethodForAI("""
|
||||
Extract the following details from the provided car license data and format them into a JSON object:
|
||||
|
||||
|
||||
License Expiration Date
|
||||
Car Plate
|
||||
Owner
|
||||
Address
|
||||
|
||||
Car License Data:
|
||||
|
||||
|
||||
JSON Format:
|
||||
{
|
||||
"LicenseExpirationDate": "YYYY-MM-DD",
|
||||
"car_plate": "[Car plate number]",//the car plate is line next to line contain 'ادارة مرور' for bot numbers and letters in arabic with partition like| but you remove |
|
||||
"owner": "[Owner's full name]",
|
||||
"address": "[Address if available, otherwise 'Not provided']"
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For the LicenseExpirationDate, ensure the date is in YYYY-MM-DD format using Latin numerals (0-9).
|
||||
2. Replace all occurrences of '|' (pipe character) with a space in all fields.
|
||||
3. If any information is missing, leave the corresponding field as an empty string.
|
||||
4. Ensure all text is properly formatted and spaces are used correctly.
|
||||
|
||||
Please fill in the JSON object with the extracted information, following these guidelines.
|
||||
""", 'car_front', ai.driverId);
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
const Divider(color: AppColor.accentColor),
|
||||
const SizedBox(height: 8.0),
|
||||
// Removed Make, Model, etc. as they are not available
|
||||
|
||||
Text(
|
||||
'${'Plate Number'.tr}: ${ai.responseIdCardDriverEgyptFront['car_plate']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Owner Name'.tr}: ${ai.responseIdCardDriverEgyptFront['owner']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Address'.tr}: ${ai.responseIdCardDriverEgyptFront['address']}',
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'License Expiry Date'.tr}: ${licenseExpiryDate.toString().substring(0, 10)}',
|
||||
style: TextStyle(
|
||||
color: isLicenseExpired ? Colors.red : Colors.green,
|
||||
),
|
||||
),
|
||||
// Removed Fuel as it's not available
|
||||
],
|
||||
),
|
||||
// Removed Inspection Date as it's not available
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
ai.allMethodForAI("""
|
||||
Extract the following details from the provided car license data and format them into a JSON object:
|
||||
|
||||
|
||||
License Expiration Date
|
||||
Car Plate
|
||||
Owner
|
||||
Address
|
||||
|
||||
Car License Data:
|
||||
|
||||
|
||||
JSON Format:
|
||||
{
|
||||
"LicenseExpirationDate": "YYYY-MM-DD",
|
||||
"car_plate": "[Car plate number]",//the car plate is line next to line contain 'ادارة مرور' for bot numbers and letters in arabic with partition like| but you remove |
|
||||
"owner": "[Owner's full name]",
|
||||
"address": "[Address if available, otherwise 'Not provided']"
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For the LicenseExpirationDate, ensure the date is in YYYY-MM-DD format using Latin numerals (0-9).
|
||||
2. Replace all occurrences of '|' (pipe character) with a space in all fields.
|
||||
3. If any information is missing, leave the corresponding field as an empty string.
|
||||
4. Ensure all text is properly formatted and spaces are used correctly.
|
||||
|
||||
Please fill in the JSON object with the extracted information, following these guidelines.
|
||||
""", 'car_front', ai.driverId);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Image.network(
|
||||
'${AppLink.server}/card_image/car_front-${ai.driverId}.jpg',
|
||||
height: Get.height * .25,
|
||||
width: double.maxFinite,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
Text(
|
||||
'Capture an Image of Your car license front '.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GetBuilder<RegisterCaptainController> egyptCarLicenceBack() {
|
||||
return GetBuilder<RegisterCaptainController>(
|
||||
builder: (ai) {
|
||||
if (ai.responseIdCardDriverEgyptBack.isNotEmpty) {
|
||||
// Get the tax expiry date from the response
|
||||
final taxExpiryDate = ai.responseIdCardDriverEgyptBack['tax_expiry'];
|
||||
// final displacement = ai.responseIdCardDriverEgyptBack['displacement'];
|
||||
// if (int.parse(displacement) < 1000) {}
|
||||
// Get the inspection date from the response
|
||||
final inspectionDate =
|
||||
ai.responseIdCardDriverEgyptBack['inspection_date'];
|
||||
final year = int.parse(inspectionDate.split('-')[0]);
|
||||
|
||||
// Set inspectionDateTime to December 31st of the given year
|
||||
final inspectionDateTime = DateTime(year, 12, 31);
|
||||
String carBackLicenseExpired =
|
||||
inspectionDateTime.toString().split(' ')[0];
|
||||
// Get the current date
|
||||
final today = DateTime.now();
|
||||
|
||||
// Try parsing the tax expiry date. If it fails, set it to null.
|
||||
final taxExpiryDateTime = DateTime.tryParse(taxExpiryDate ?? '');
|
||||
final isExpired =
|
||||
taxExpiryDateTime != null && taxExpiryDateTime.isBefore(today);
|
||||
// Check if the inspection date is before today
|
||||
bool isInspectionExpired = inspectionDateTime.isBefore(today);
|
||||
|
||||
return Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Vehicle Details Back'.tr,
|
||||
style: AppStyle.headTitle2),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
ai.allMethodForAI("""
|
||||
Analyze the extracted car license information and create a JSON object with the following keys:
|
||||
|
||||
{
|
||||
"make": "",
|
||||
"year": "",
|
||||
"chassis": "",
|
||||
"model": "",
|
||||
"engine": "",
|
||||
"displacement": "",
|
||||
"cylinders": "",
|
||||
"fuel": "",
|
||||
"color": "",
|
||||
"color_hex": "",
|
||||
"inspection_date": "",
|
||||
"assuranceNumber": "",
|
||||
"tax_expiry": ""
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For dates (inspection_date and tax_expiry), use the format YYYY-MM-DD with Latin numerals (0-9).
|
||||
2. Convert the color name to its corresponding hex color code for the 'color_hex' field.
|
||||
3. Ensure all numeric values (year, displacement, cylinders) are in Latin numerals.
|
||||
4. If any information is missing, leave the corresponding field as an empty string.
|
||||
5. Do not include any explanatory text in the JSON fields, only the extracted values.
|
||||
displacement in the line contain (سم٣ )
|
||||
Please fill in the JSON object with the extracted information, following these guidelines.
|
||||
""", 'car_back', ai.driverId);
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
const Divider(color: AppColor.accentColor),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Make'.tr}: ${ai.responseIdCardDriverEgyptBack['make']}'),
|
||||
Text(
|
||||
'${'Model'.tr}: ${ai.responseIdCardDriverEgyptBack['model']}'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Year'.tr}: ${ai.responseIdCardDriverEgyptBack['year']}'),
|
||||
Text(
|
||||
'${'Chassis'.tr}: ${ai.responseIdCardDriverEgyptBack['chassis']}'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Color'.tr}: ${ai.responseIdCardDriverEgyptBack['color']}'),
|
||||
Text(
|
||||
'${'Displacement'.tr}: ${ai.responseIdCardDriverEgyptBack['displacement']} cc'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'Fuel'.tr}: ${ai.responseIdCardDriverEgyptBack['fuel']}'),
|
||||
const SizedBox(height: 8.0),
|
||||
if (taxExpiryDateTime != null)
|
||||
Text(
|
||||
'${'Tax Expiry Date'.tr}: $taxExpiryDate',
|
||||
style: TextStyle(
|
||||
color: isExpired ? Colors.red : Colors.green,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${'Inspection Date'.tr}: $carBackLicenseExpired',
|
||||
style: TextStyle(
|
||||
color:
|
||||
isInspectionExpired ? Colors.red : Colors.green,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
ai.allMethodForAI("""
|
||||
Analyze the extracted car license information and create a JSON object with the following keys:
|
||||
|
||||
{
|
||||
"make": "",
|
||||
"year": "",
|
||||
"chassis": "",
|
||||
"model": "",
|
||||
"engine": "",
|
||||
"displacement": "",
|
||||
"cylinders": "",
|
||||
"fuel": "",
|
||||
"color": "",
|
||||
"color_hex": "",
|
||||
"inspection_date": "",
|
||||
"assuranceNumber": "",
|
||||
"tax_expiry": ""
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For dates (inspection_date and tax_expiry), use the format YYYY-MM-DD with Latin numerals (0-9).
|
||||
2. Convert the color name to its corresponding hex color code for the 'color_hex' field.
|
||||
3. Ensure all numeric values (year, displacement, cylinders) are in Latin numerals.
|
||||
4. If any information is missing, leave the corresponding field as an empty string.
|
||||
5. Do not include any explanatory text in the JSON fields, only the extracted values.
|
||||
|
||||
Please fill in the JSON object with the extracted information, following these guidelines.
|
||||
""", 'car_back', ai.driverId);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Image.network(
|
||||
'${AppLink.server}/card_image/car_back-${ai.driverId}.jpg',
|
||||
height: Get.height * .25,
|
||||
width: double.maxFinite,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
Text(
|
||||
'Capture an Image of Your car license back'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GetBuilder<RegisterCaptainController> egyptCriminalRecord() {
|
||||
return GetBuilder<RegisterCaptainController>(
|
||||
builder: (ai) {
|
||||
if (ai.responseCriminalRecordEgypt.isNotEmpty) {
|
||||
return Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Criminal Record'.tr, style: AppStyle.headTitle2),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await ai.allMethodForAI("""
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"InspectionResult": "",
|
||||
"NationalID": "",
|
||||
"FullName": "",
|
||||
"IssueDate": "" // Format: YYYY-MM-DD
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For the IssueDate, ensure the date is in YYYY-MM-DD format using Latin numerals (0-9).
|
||||
2. Add appropriate spaces in all text fields to ensure readability.
|
||||
3. If any information is missing, leave the corresponding field as an empty string.
|
||||
4. Ensure all text is properly formatted and spaces are used correctly.
|
||||
5. Convert any Arabic numerals to Latin numerals (0-9) where applicable.
|
||||
|
||||
Please fill in the JSON object with the extracted information, following these guidelines.
|
||||
""", 'criminalRecord', ai.driverId);
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
const Divider(color: AppColor.accentColor),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'InspectionResult'.tr}: ${ai.responseCriminalRecordEgypt['InspectionResult']}'),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'FullName'.tr}: ${ai.responseCriminalRecordEgypt['FullName']}',
|
||||
style: AppStyle.title.copyWith(
|
||||
color: ai.responseCriminalRecordEgypt['FullName'] ==
|
||||
ai.responseIdEgyptDriverLicense['name_arabic']
|
||||
? AppColor.greenColor
|
||||
: AppColor.redColor),
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'NationalID'.tr}: ${ai.responseCriminalRecordEgypt['NationalID']}'),
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'${'IssueDate'.tr}: ${ai.responseCriminalRecordEgypt['IssueDate']}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await ai.allMethodForAI("""
|
||||
Write a JSON object from the following information extracted from the provided Arabic text:
|
||||
|
||||
{
|
||||
"InspectionResult": "",
|
||||
"NationalID": "",
|
||||
"FullName": "",
|
||||
"IssueDate": "" // Format: YYYY-MM-DD
|
||||
}
|
||||
|
||||
Important notes:
|
||||
1. For the IssueDate, ensure the date is in YYYY-MM-DD format using Latin numerals (0-9).
|
||||
2. Add appropriate spaces in all text fields to ensure readability.
|
||||
3. If any information is missing, leave the corresponding field as an empty string.
|
||||
4. Ensure all text is properly formatted and spaces are used correctly.
|
||||
5. Convert any Arabic numerals to Latin numerals (0-9) where applicable.
|
||||
|
||||
Please fill in the JSON object with the extracted information, following these guidelines.
|
||||
""", 'criminalRecord', ai.driverId);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Image.network(
|
||||
'${AppLink.server}/card_image/6.png',
|
||||
height: Get.height * .25,
|
||||
width: double.maxFinite,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
Text(
|
||||
'Capture an Image of Your Criminal Record'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
94
lib/views/admin/dashboard_widget.dart
Normal file
94
lib/views/admin/dashboard_widget.dart
Normal file
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart'; // For Get.width if needed, and .tr
|
||||
import 'package:sefer_admin1/constant/colors.dart'; // Assuming AppColor is here
|
||||
import 'package:sefer_admin1/constant/style.dart'; // Assuming AppStyle is here
|
||||
|
||||
class DashboardStatCard extends StatelessWidget {
|
||||
final String title;
|
||||
final String value;
|
||||
final IconData? icon;
|
||||
final Color? iconColor;
|
||||
final Color? backgroundColor;
|
||||
final Color? valueColor;
|
||||
|
||||
const DashboardStatCard({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
this.icon,
|
||||
this.iconColor,
|
||||
this.backgroundColor,
|
||||
this.valueColor,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Attempt to use AppStyle.boxDecoration1 properties if it's a BoxDecoration
|
||||
BoxDecoration? baseDecoration = AppStyle.boxDecoration1;
|
||||
Color? finalBackgroundColor =
|
||||
backgroundColor ?? baseDecoration?.color ?? Theme.of(context).cardColor;
|
||||
BorderRadius? finalBorderRadius =
|
||||
baseDecoration?.borderRadius?.resolve(Directionality.of(context)) ??
|
||||
BorderRadius.circular(12.0);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14.0, vertical: 12.0),
|
||||
decoration: BoxDecoration(
|
||||
color: finalBackgroundColor,
|
||||
borderRadius: finalBorderRadius,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.1),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 6,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
// If AppStyle.boxDecoration1 includes a border, you might want to add it here too
|
||||
// border: baseDecoration?.border,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center, // Center content vertically
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
title.tr,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (icon != null)
|
||||
Icon(
|
||||
icon,
|
||||
size: 24,
|
||||
color: iconColor ?? AppColor.primaryColor.withOpacity(0.7),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: valueColor ?? AppColor.primaryColor,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
69
lib/views/admin/drivers/alexandria.dart
Normal file
69
lib/views/admin/drivers/alexandria.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
import 'package:sefer_admin1/controller/functions/wallet.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
||||
|
||||
import '../../../controller/drivers/driverthebest.dart';
|
||||
|
||||
class DriverTheBestAlexandria extends StatelessWidget {
|
||||
const DriverTheBestAlexandria({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(DriverTheBestAlexandriaController(), permanent: true);
|
||||
return MyScafolld(
|
||||
title: 'Alexandria'.tr,
|
||||
body: [
|
||||
GetBuilder<DriverTheBestAlexandriaController>(builder: (driverthebest) {
|
||||
return driverthebest.driver.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: driverthebest.driver.length,
|
||||
itemBuilder: (context, index) {
|
||||
final driver = driverthebest.driver[index];
|
||||
return ListTile(
|
||||
leading: CircleAvatar(
|
||||
child: Text(
|
||||
((driver['driver_count'] * 5) / 3600)
|
||||
.toStringAsFixed(0),
|
||||
),
|
||||
),
|
||||
title: Text(driver['name_arabic'] ?? 'Unknown Name'),
|
||||
subtitle: Text('Phone: ${driver['phone'] ?? 'N/A'}'),
|
||||
trailing: IconButton(
|
||||
onPressed: () async {
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'are you sure to pay to this driver gift'.tr,
|
||||
middleText: '',
|
||||
onConfirm: () async {
|
||||
final wallet = Get.put(WalletController());
|
||||
await wallet.addPaymentToDriver('100',
|
||||
driver['id'].toString(), driver['token']);
|
||||
await wallet.addSeferWallet(
|
||||
'100', driver['id'].toString());
|
||||
await CRUD().post(
|
||||
link: AppLink.deleteRecord,
|
||||
payload: {
|
||||
'driver_id': driver['id'].toString()
|
||||
});
|
||||
driverthebest.driver.removeAt(index);
|
||||
driverthebest.update();
|
||||
},
|
||||
onCancel: () => Get.back());
|
||||
},
|
||||
icon: const Icon(Icons.wallet_giftcard_rounded),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: const Center(
|
||||
child: Text('No drivers available.'),
|
||||
);
|
||||
})
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
103
lib/views/admin/drivers/driver_the_best.dart
Normal file
103
lib/views/admin/drivers/driver_the_best.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
import 'package:sefer_admin1/controller/functions/encrypt_decrypt.dart';
|
||||
import 'package:sefer_admin1/controller/functions/wallet.dart';
|
||||
import 'package:sefer_admin1/views/widgets/elevated_btn.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
||||
|
||||
import '../../../controller/drivers/driverthebest.dart';
|
||||
import 'alexandria.dart';
|
||||
import 'giza.dart';
|
||||
|
||||
class DriverTheBest extends StatelessWidget {
|
||||
const DriverTheBest({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(Driverthebest(), permanent: true);
|
||||
return MyScafolld(
|
||||
title: 'Best Drivers'.tr,
|
||||
body: [
|
||||
GetBuilder<Driverthebest>(builder: (driverthebest) {
|
||||
return driverthebest.driver.isNotEmpty
|
||||
? Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'Giza',
|
||||
onPressed: () {
|
||||
Get.to(() => DriverTheBestGiza());
|
||||
}),
|
||||
MyElevatedButton(
|
||||
title: 'Alexandria',
|
||||
onPressed: () {
|
||||
Get.to(() => DriverTheBestAlexandria());
|
||||
}),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: Get.height * .7,
|
||||
child: ListView.builder(
|
||||
itemCount: driverthebest.driver.length,
|
||||
itemBuilder: (context, index) {
|
||||
final driver = driverthebest.driver[index];
|
||||
return ListTile(
|
||||
leading: CircleAvatar(
|
||||
child: Text(
|
||||
(int.parse(driver['driver_count']) * 5 / 3600)
|
||||
.toStringAsFixed(
|
||||
0), // Perform division first, then convert to string
|
||||
),
|
||||
),
|
||||
title:
|
||||
Text((driver['name_arabic']) ?? 'Unknown Name'),
|
||||
subtitle:
|
||||
Text('Phone: ${(driver['phone']) ?? 'N/A'}'),
|
||||
trailing: IconButton(
|
||||
onPressed: () async {
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'are you sure to pay to this driver gift'
|
||||
.tr,
|
||||
middleText: '',
|
||||
onConfirm: () async {
|
||||
final wallet =
|
||||
Get.put(WalletController());
|
||||
await wallet.addPaymentToDriver(
|
||||
'200',
|
||||
driver['id'].toString(),
|
||||
driver['token']);
|
||||
await wallet.addSeferWallet(
|
||||
'200', driver['id'].toString());
|
||||
await CRUD().post(
|
||||
link: AppLink.deleteRecord,
|
||||
payload: {
|
||||
'driver_id': driver['id'].toString()
|
||||
});
|
||||
driverthebest.driver.removeAt(index);
|
||||
driverthebest.update();
|
||||
Get.back();
|
||||
},
|
||||
onCancel: () => Get.back());
|
||||
},
|
||||
icon: const Icon(Icons.wallet_giftcard_rounded),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const Center(
|
||||
child: Text('No drivers available.'),
|
||||
);
|
||||
})
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
69
lib/views/admin/drivers/giza.dart
Normal file
69
lib/views/admin/drivers/giza.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
import 'package:sefer_admin1/controller/functions/wallet.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
||||
|
||||
import '../../../controller/drivers/driverthebest.dart';
|
||||
|
||||
class DriverTheBestGiza extends StatelessWidget {
|
||||
const DriverTheBestGiza({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(DriverTheBestGizaController(), permanent: true);
|
||||
return MyScafolld(
|
||||
title: 'Giza'.tr,
|
||||
body: [
|
||||
GetBuilder<DriverTheBestGizaController>(builder: (driverthebest) {
|
||||
return driverthebest.driver.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: driverthebest.driver.length,
|
||||
itemBuilder: (context, index) {
|
||||
final driver = driverthebest.driver[index];
|
||||
return ListTile(
|
||||
leading: CircleAvatar(
|
||||
child: Text(
|
||||
((driver['driver_count'] * 5) / 3600)
|
||||
.toStringAsFixed(0),
|
||||
),
|
||||
),
|
||||
title: Text(driver['name_arabic'] ?? 'Unknown Name'),
|
||||
subtitle: Text('Phone: ${driver['phone'] ?? 'N/A'}'),
|
||||
trailing: IconButton(
|
||||
onPressed: () async {
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'are you sure to pay to this driver gift'.tr,
|
||||
middleText: '',
|
||||
onConfirm: () async {
|
||||
final wallet = Get.put(WalletController());
|
||||
await wallet.addPaymentToDriver('100',
|
||||
driver['id'].toString(), driver['token']);
|
||||
await wallet.addSeferWallet(
|
||||
'100', driver['id'].toString());
|
||||
await CRUD().post(
|
||||
link: AppLink.deleteRecord,
|
||||
payload: {
|
||||
'driver_id': driver['id'].toString()
|
||||
});
|
||||
driverthebest.driver.removeAt(index);
|
||||
driverthebest.update();
|
||||
},
|
||||
onCancel: () => Get.back());
|
||||
},
|
||||
icon: const Icon(Icons.wallet_giftcard_rounded),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: const Center(
|
||||
child: Text('No drivers available.'),
|
||||
);
|
||||
})
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
186
lib/views/admin/employee/employee_page.dart
Normal file
186
lib/views/admin/employee/employee_page.dart
Normal file
@@ -0,0 +1,186 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/colors.dart';
|
||||
import 'package:sefer_admin1/constant/style.dart';
|
||||
import 'package:sefer_admin1/controller/employee_controller/employee_controller.dart';
|
||||
import 'package:sefer_admin1/controller/functions/launch.dart';
|
||||
import 'package:sefer_admin1/views/widgets/elevated_btn.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_textField.dart';
|
||||
|
||||
import '../../../constant/links.dart';
|
||||
import '../../../controller/functions/upload_image copy.dart';
|
||||
|
||||
class EmployeePage extends StatelessWidget {
|
||||
const EmployeePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(EmployeeController());
|
||||
return GetBuilder<EmployeeController>(builder: (employeeController) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Employee Page'.tr),
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemCount: employeeController
|
||||
.employee.length, // Set the item count based on the employee list
|
||||
itemBuilder: (context, index) {
|
||||
// Get the employee data for the current index
|
||||
var employee = employeeController.employee[index];
|
||||
|
||||
// Return a widget to display the employee information
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: ListTile(
|
||||
trailing: IconButton(
|
||||
onPressed: () {
|
||||
Get.to(() => EmployeeDetails(
|
||||
index: index,
|
||||
));
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.shop_two,
|
||||
color: employee['status'].toString().contains('ممتاز')
|
||||
? AppColor.greenColor
|
||||
: AppColor.accentColor,
|
||||
),
|
||||
),
|
||||
title: Column(
|
||||
children: [
|
||||
Text(employee['name']),
|
||||
Text(
|
||||
'Phone: ${employee['phone']}\nEducation: ${employee['education']}'),
|
||||
Text('Status: ${employee['status']}'),
|
||||
],
|
||||
), // Display employee name
|
||||
onTap: () {
|
||||
// Add any action you want when the employee is tapped
|
||||
},
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
makePhoneCall(employee['phone'].toString());
|
||||
// launchCommunication(
|
||||
// 'phone', employee['phone'].toString(), '');
|
||||
},
|
||||
icon: const Icon(Icons.phone),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
employeeController.id = employeeController.generateRandomId(8);
|
||||
Get.to(
|
||||
employeeFields(employeeController),
|
||||
);
|
||||
}, // Icon to display
|
||||
backgroundColor: Colors.blue, // Button color (optional)
|
||||
tooltip: 'Add Employee',
|
||||
child: const Icon(Icons.add), // Tooltip text when long-pressed
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Scaffold employeeFields(EmployeeController employeeController) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: Form(
|
||||
key: employeeController.formKey,
|
||||
child: SizedBox(
|
||||
height: 500,
|
||||
child: ListView(
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'front id',
|
||||
onPressed: () async {
|
||||
await ImageController().choosImage(AppLink.uploadEgypt,
|
||||
'idFrontEmployee', employeeController.id);
|
||||
}),
|
||||
MyElevatedButton(
|
||||
title: 'back id',
|
||||
onPressed: () async {
|
||||
await ImageController().choosImage(AppLink.uploadEgypt,
|
||||
'idbackEmployee', employeeController.id);
|
||||
}),
|
||||
MyTextForm(
|
||||
controller: employeeController.name,
|
||||
label: 'name',
|
||||
hint: 'name',
|
||||
type: TextInputType.name),
|
||||
MyTextForm(
|
||||
controller: employeeController.education,
|
||||
label: 'education',
|
||||
hint: 'education',
|
||||
type: TextInputType.name),
|
||||
MyTextForm(
|
||||
controller: employeeController.site,
|
||||
label: 'site',
|
||||
hint: 'site',
|
||||
type: TextInputType.name),
|
||||
MyTextForm(
|
||||
controller: employeeController.phone,
|
||||
label: 'phone',
|
||||
hint: 'phone',
|
||||
type: TextInputType.phone),
|
||||
MyTextForm(
|
||||
controller: employeeController.status,
|
||||
label: 'status',
|
||||
hint: 'status',
|
||||
type: TextInputType.name),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: MyElevatedButton(
|
||||
title: 'upload',
|
||||
onPressed: () async {
|
||||
if (employeeController.formKey.currentState!.validate()) {
|
||||
await employeeController.addEmployee();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EmployeeDetails extends StatelessWidget {
|
||||
const EmployeeDetails({super.key, required this.index});
|
||||
final int index;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(
|
||||
title: 'Details',
|
||||
isleading: true,
|
||||
body: [
|
||||
GetBuilder<EmployeeController>(builder: (employeeController) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: 400,
|
||||
child: Image.network(
|
||||
// https: //server.sefer.click/sefer.click/sefer/card_image/idFrontEmployee-GC15188P.jpg
|
||||
'https://server.sefer.click/sefer.click/sefer/card_image/idFrontEmployee-${employeeController.employee[index]['id']}.jpg'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: 400,
|
||||
child: Image.network(
|
||||
'https://server.sefer.click/sefer.click/sefer/card_image/idFrontEmployee-${employeeController.employee[index]['id']}.jpg'),
|
||||
)
|
||||
],
|
||||
);
|
||||
})
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
107
lib/views/admin/packages.dart
Normal file
107
lib/views/admin/packages.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/controller/functions/crud.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_textField.dart';
|
||||
|
||||
import '../../print.dart';
|
||||
|
||||
class PackageUpdateScreen extends StatelessWidget {
|
||||
final PackageController packageController = Get.put(PackageController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Package Update'),
|
||||
),
|
||||
body: GetBuilder<PackageController>(builder: (packageController) {
|
||||
return Center(
|
||||
child: ListView.builder(
|
||||
itemCount: packageController.packages.length,
|
||||
itemBuilder: (context, index) {
|
||||
var package = packageController.packages[index];
|
||||
return ListTile(
|
||||
title: Text(package['appName']),
|
||||
subtitle: Text(
|
||||
'Platform: ${package['platform']} \nVersion: ${package['version']}'),
|
||||
trailing: const Icon(Icons.update),
|
||||
onTap: () {
|
||||
Get.defaultDialog(
|
||||
title: 'Update',
|
||||
middleText: '',
|
||||
content: Column(
|
||||
children: [
|
||||
Text(package['appName']),
|
||||
Text(package['platform']),
|
||||
Text(package['version']),
|
||||
MyTextForm(
|
||||
controller: packageController.versionController,
|
||||
label: package['version'].toString(),
|
||||
hint: package['version'].toString(),
|
||||
type: const TextInputType.numberWithOptions(
|
||||
decimal: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
onConfirm: () async {
|
||||
await packageController.updatePackages(
|
||||
package['id'].toString(),
|
||||
packageController.versionController.text.toString(),
|
||||
);
|
||||
},
|
||||
onCancel: () {},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PackageController extends GetxController {
|
||||
List packages = []; // Observable list to hold package info
|
||||
var isLoading = false.obs;
|
||||
final versionController = TextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
fetchPackages();
|
||||
}
|
||||
|
||||
// Method to fetch package data from API
|
||||
fetchPackages() async {
|
||||
var response = await CRUD().get(link: AppLink.getPackages, payload: {});
|
||||
|
||||
if (response != 'failure') {
|
||||
var jsonData = jsonDecode(response);
|
||||
packages = jsonData['message'];
|
||||
update();
|
||||
Log.print('jsonData: ${jsonData}');
|
||||
}
|
||||
}
|
||||
|
||||
updatePackages(String id, version) async {
|
||||
var response = await CRUD().post(
|
||||
link: AppLink.updatePackages,
|
||||
payload: {
|
||||
"id": id,
|
||||
"version": version,
|
||||
},
|
||||
);
|
||||
Log.print('response: ${response}');
|
||||
if (response != 'failure') {
|
||||
Get.back();
|
||||
fetchPackages();
|
||||
} else {
|
||||
Get.snackbar('error', 'message');
|
||||
}
|
||||
}
|
||||
}
|
||||
86
lib/views/admin/passenger/form_passenger.dart
Normal file
86
lib/views/admin/passenger/form_passenger.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/passenger_admin_controller.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import 'passenger_details_page.dart';
|
||||
|
||||
GetBuilder<PassengerAdminController> formSearchPassengers() {
|
||||
// DbSql sql = DbSql.instance;
|
||||
return GetBuilder<PassengerAdminController>(
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Container(
|
||||
decoration:
|
||||
const BoxDecoration(color: AppColor.secondaryColor),
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.only(),
|
||||
gapPadding: 4,
|
||||
borderSide: BorderSide(
|
||||
color: AppColor.redColor,
|
||||
width: 2,
|
||||
)),
|
||||
suffixIcon: InkWell(
|
||||
onTap: () async {
|
||||
if (controller.passengerController.text.length >
|
||||
4) {
|
||||
await controller.getPassengers();
|
||||
|
||||
Get.defaultDialog(
|
||||
title: controller.passengers['message'][0]
|
||||
['email'],
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Name is ${controller.passengers['message'][0]['first_name']} ${controller.passengers['message'][0]['last_name']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'phone is ${controller.passengers['message'][0]['phone']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Go To Details'.tr,
|
||||
onPressed: () {
|
||||
Get.to(
|
||||
() => const PassengerDetailsPage(),
|
||||
arguments: {
|
||||
'data': controller
|
||||
.passengers['message'][0],
|
||||
});
|
||||
}));
|
||||
}
|
||||
},
|
||||
child: const Icon(Icons.search)),
|
||||
hintText: 'Search for Passenger'.tr,
|
||||
hintStyle: AppStyle.title,
|
||||
hintMaxLines: 1,
|
||||
prefixIcon: IconButton(
|
||||
onPressed: () async {
|
||||
controller.passengerController.clear();
|
||||
controller.clearPlaces();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.clear,
|
||||
color: Colors.red[300],
|
||||
),
|
||||
),
|
||||
),
|
||||
controller: controller.passengerController,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
205
lib/views/admin/passenger/passenger.dart
Normal file
205
lib/views/admin/passenger/passenger.dart
Normal file
@@ -0,0 +1,205 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/controller/functions/encrypt_decrypt.dart';
|
||||
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/passenger_admin_controller.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
import '../../widgets/my_textField.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
import 'form_passenger.dart';
|
||||
import 'passenger_details_page.dart';
|
||||
|
||||
class Passengrs extends StatelessWidget {
|
||||
Passengrs({super.key});
|
||||
final PassengerAdminController passengerAdminController =
|
||||
Get.put(PassengerAdminController());
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(
|
||||
title: 'Passengrs'.tr,
|
||||
isleading: true,
|
||||
body: [
|
||||
GetBuilder<PassengerAdminController>(
|
||||
builder: (passengerAdminController) => Column(
|
||||
children: [
|
||||
passengerAdminController.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
passengerAdmin(
|
||||
passengerAdminController,
|
||||
'Passengers Count',
|
||||
'countPassenger',
|
||||
),
|
||||
MyElevatedButton(
|
||||
title: 'Add Prize to Gold Passengers',
|
||||
onPressed: () {
|
||||
var date = DateTime.now();
|
||||
var day = date.weekday;
|
||||
|
||||
if (day == 6) {
|
||||
// Saturday is 6
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'Add Prize to Gold Passengers',
|
||||
titleStyle: AppStyle.title,
|
||||
content: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Add Points to their wallet as prize'
|
||||
.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Form(
|
||||
key:
|
||||
passengerAdminController
|
||||
.formPrizeKey,
|
||||
child: MyTextForm(
|
||||
controller:
|
||||
passengerAdminController
|
||||
.passengerPrizeController,
|
||||
label:
|
||||
'Count of prize'
|
||||
.tr,
|
||||
hint: 'Count of prize'
|
||||
.tr,
|
||||
type: TextInputType
|
||||
.number))
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Add',
|
||||
onPressed: () async {
|
||||
if (passengerAdminController
|
||||
.formPrizeKey
|
||||
.currentState!
|
||||
.validate()) {
|
||||
passengerAdminController
|
||||
.addPassengerPrizeToWalletSecure();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Get.defaultDialog(
|
||||
title:
|
||||
'This day is not allowed',
|
||||
titleStyle: AppStyle.title,
|
||||
middleText:
|
||||
'Saturday only Allowed day',
|
||||
middleTextStyle: AppStyle.title,
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
}));
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
formSearchPassengers(),
|
||||
SizedBox(
|
||||
height: Get.height * .5,
|
||||
child: ListView.builder(
|
||||
itemCount: passengerAdminController
|
||||
.passengersData['message'].length,
|
||||
itemBuilder: (context, index) {
|
||||
final user = passengerAdminController
|
||||
.passengersData['message'][index];
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Get.to(const PassengerDetailsPage(),
|
||||
arguments: {
|
||||
'data': user,
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 2)),
|
||||
child: ListTile(
|
||||
title: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Name : ${(user['first_name'])} ${(user['last_name'])}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Rating : ${user['ratingPassenger']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Count Trip : ${user['countPassengerRide']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Count Driver Rate : ${user['countDriverRate']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Container passengerAdmin(PassengerAdminController passengerAdminController,
|
||||
String title, String jsonField) {
|
||||
return Container(
|
||||
height: Get.height * .1,
|
||||
decoration: BoxDecoration(border: Border.all(width: 2)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
title.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
passengerAdminController.passengersData['message'][0][jsonField]
|
||||
.toString(),
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
167
lib/views/admin/passenger/passenger_details_page.dart
Normal file
167
lib/views/admin/passenger/passenger_details_page.dart
Normal file
@@ -0,0 +1,167 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/passenger_admin_controller.dart';
|
||||
import '../../../controller/firebase/firbase_messge.dart';
|
||||
import '../../widgets/elevated_btn.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
import '../../widgets/my_textField.dart';
|
||||
|
||||
class PassengerDetailsPage extends StatelessWidget {
|
||||
const PassengerDetailsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final arguments = Get.arguments;
|
||||
final Map<String, dynamic> data = arguments['data'];
|
||||
var key = Get.find<PassengerAdminController>().formPrizeKey;
|
||||
var titleNotify = Get.find<PassengerAdminController>().titleNotify;
|
||||
var bodyNotify = Get.find<PassengerAdminController>().bodyNotify;
|
||||
return MyScafolld(
|
||||
title: data['first_name'],
|
||||
body: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Email is ${data['email']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Phone is ${data['phone']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'gender is ${data['gender']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'status is ${data['status']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'birthdate is ${data['birthdate']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'site is ${data['site']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'sosPhone is ${data['sosPhone']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Count Feedback is ${data['countFeedback']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Count Driver Rate is ${data['countDriverRate']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Count Cancel is ${data['countPassengerCancel']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Count Ride is ${data['countPassengerRide']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Rating Captain Avarage is ${data['passengerAverageRating']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
Text(
|
||||
'Rating is ${data['ratingPassenger']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 3, color: AppColor.yellowColor)),
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
Get.defaultDialog(
|
||||
title: 'Send Notification'.tr,
|
||||
titleStyle: AppStyle.title,
|
||||
content: Form(
|
||||
key: key,
|
||||
child: Column(
|
||||
children: [
|
||||
MyTextForm(
|
||||
controller: titleNotify,
|
||||
label: 'title'.tr,
|
||||
hint: 'title notificaton'.tr,
|
||||
type: TextInputType.name),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
MyTextForm(
|
||||
controller: bodyNotify,
|
||||
label: 'body'.tr,
|
||||
hint: 'body notificaton'.tr,
|
||||
type: TextInputType.name)
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Send',
|
||||
onPressed: () {
|
||||
if (key.currentState!.validate()) {
|
||||
FirebaseMessagesController()
|
||||
.sendNotificationToAnyWithoutData(
|
||||
titleNotify.text,
|
||||
bodyNotify.text,
|
||||
data['passengerToken'],
|
||||
'order.wav');
|
||||
Get.back();
|
||||
}
|
||||
}));
|
||||
},
|
||||
child: Text(
|
||||
"Send Notificaion to Passenger ".tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
236
lib/views/admin/rides/rides.dart
Normal file
236
lib/views/admin/rides/rides.dart
Normal file
@@ -0,0 +1,236 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/admin/ride_admin_controller.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
|
||||
class Rides extends StatelessWidget {
|
||||
Rides({super.key});
|
||||
RideAdminController rideAdminController = Get.put(RideAdminController());
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(title: 'Rides'.tr, isleading: true, body: [
|
||||
GetBuilder<RideAdminController>(
|
||||
builder: (rideAdminController) => rideAdminController.isLoading
|
||||
? const Center(child: MyCircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Get.height * .4,
|
||||
child: LineChart(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
curve: Curves.ease,
|
||||
LineChartData(
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
spots: rideAdminController.chartData,
|
||||
isCurved: true,
|
||||
color: Colors.deepPurpleAccent, // Custom color
|
||||
barWidth: 3, // Thinner line
|
||||
dotData: const FlDotData(
|
||||
show: true), // Show dots on each point
|
||||
belowBarData: BarAreaData(
|
||||
// Add gradient fill below the line
|
||||
show: true,
|
||||
color: AppColor.deepPurpleAccent,
|
||||
),
|
||||
isStrokeJoinRound: true,
|
||||
shadow: const BoxShadow(
|
||||
color: AppColor.yellowColor,
|
||||
blurRadius: 4,
|
||||
offset: Offset(2, 2),
|
||||
),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: const [],
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
topTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Days',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30, showTitles: true)),
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Total Trips on month'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30, showTitles: true)),
|
||||
leftTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Counts of Trips on month'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30, showTitles: true)),
|
||||
),
|
||||
gridData: const FlGridData(
|
||||
show: true,
|
||||
),
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: const Border(
|
||||
bottom: BorderSide(color: AppColor.accentColor),
|
||||
left: BorderSide(color: AppColor.accentColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// SizedBox(
|
||||
// height: Get.height * .4,
|
||||
// child: PieChart(
|
||||
// PieChartData(
|
||||
// sectionsSpace: 4, // Adjust spacing between sections
|
||||
// centerSpaceRadius:
|
||||
// 40, // Adjust radius of center space
|
||||
// sections: [
|
||||
// for (final rideData in rideAdminController.rideData)
|
||||
// PieChartSectionData(
|
||||
// value: rideData.ridesCount.toDouble(),
|
||||
// title: '${rideData.day}', showTitle: true,
|
||||
// titleStyle:
|
||||
// AppStyle.subtitle, // Display day as title
|
||||
// radius: 60, // Adjust radius of each section
|
||||
// color:
|
||||
// AppColor.deepPurpleAccent, // Custom color
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
|
||||
// SizedBox(
|
||||
// // height: 400,
|
||||
// child: SfCartesianChart(
|
||||
// legend: const Legend(
|
||||
// isVisible: true,
|
||||
// position: LegendPosition.bottom,
|
||||
// overflowMode: LegendItemOverflowMode.wrap,
|
||||
// textStyle: TextStyle(
|
||||
// color: Colors.white,
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// borderWidth: 2,
|
||||
// borderColor: AppColor.blueColor,
|
||||
// plotAreaBorderColor: AppColor.deepPurpleAccent,
|
||||
// enableAxisAnimation: true,
|
||||
// primaryXAxis: CategoryAxis(
|
||||
// borderColor: AppColor.accentColor, borderWidth: 2,
|
||||
// title: AxisTitle(
|
||||
// text: 'Total Trips on month'.tr,
|
||||
// textStyle: AppStyle.title,
|
||||
// ),
|
||||
// // labelRotation: 45,
|
||||
// majorGridLines: const MajorGridLines(width: 0),
|
||||
// ),
|
||||
// primaryYAxis: const NumericAxis(isVisible: false),
|
||||
// series: <LineSeries<ChartDataS, String>>[
|
||||
// LineSeries<ChartDataS, String>(
|
||||
// dataSource: rideAdminController.chartDatasync,
|
||||
// xValueMapper: (ChartDataS data, _) => '${data.day}',
|
||||
// yValueMapper: (ChartDataS data, _) =>
|
||||
// data.ridesCount,
|
||||
// dataLabelSettings:
|
||||
// const DataLabelSettings(isVisible: true),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Card(
|
||||
elevation: 4,
|
||||
color: AppColor.deepPurpleAccent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Total Trips on this Month is ${rideAdminController.jsonResponse['message'][0]['current_month_rides_count']}',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Card(
|
||||
elevation: 4,
|
||||
color: AppColor.yellowColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'Driver Average Duration: ${rideAdminController.ridesDetails[0]['driver_avg_duration']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Number of Drivers: ${rideAdminController.ridesDetails[0]['num_Driver']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Total Rides: ${rideAdminController.ridesDetails[0]['total_rides']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Ongoing Rides: ${rideAdminController.ridesDetails[0]['ongoing_rides']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Completed Rides: ${rideAdminController.ridesDetails[0]['completed_rides']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Cancelled Rides: ${rideAdminController.ridesDetails[0]['cancelled_rides']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Longest Duration: ${rideAdminController.ridesDetails[0]['longest_duration']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Total Distance: ${rideAdminController.ridesDetails[0]['total_distance']} km',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Average Distance: ${rideAdminController.ridesDetails[0]['average_distance']} km',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Longest Distance: ${rideAdminController.ridesDetails[0]['longest_distance']} km',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Total Driver Earnings: \$${rideAdminController.ridesDetails[0]['total_driver_earnings']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Total Company Earnings: \$${rideAdminController.ridesDetails[0]['total_company_earnings']}',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
Text(
|
||||
'Company Percentage: ${rideAdminController.ridesDetails[0]['companyPercent']} %',
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
))
|
||||
]);
|
||||
}
|
||||
}
|
||||
575
lib/views/admin/static/static.dart
Normal file
575
lib/views/admin/static/static.dart
Normal file
@@ -0,0 +1,575 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/style.dart';
|
||||
import 'package:sefer_admin1/controller/admin/static_controller.dart';
|
||||
import 'package:sefer_admin1/views/widgets/mycircular.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
|
||||
class StaticDash extends StatelessWidget {
|
||||
const StaticDash({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(StaticController());
|
||||
return MyScafolld(
|
||||
title: 'Static Dash'.tr,
|
||||
action: IconButton(
|
||||
onPressed: () async {
|
||||
await Get.put(StaticController()).getAll();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.replay_circle_filled_rounded,
|
||||
color: AppColor.greenColor,
|
||||
),
|
||||
),
|
||||
body: [
|
||||
GetBuilder<StaticController>(builder: (staticController) {
|
||||
return staticController.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Get.height * .3,
|
||||
width: double.maxFinite,
|
||||
// decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: MediaQuery.of(context).size.height * 0.4,
|
||||
child: LineChart(
|
||||
LineChartData(
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
isStepLineChart: true,
|
||||
spots:
|
||||
staticController.chartDataPassengers,
|
||||
isCurved: true,
|
||||
color: Colors.blue, // Custom color
|
||||
barWidth: 3, // Thinner line
|
||||
dotData: const FlDotData(
|
||||
show:
|
||||
true), // Show dots on each point
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.deepPurpleAccent
|
||||
.withOpacity(
|
||||
0.3), // Custom gradient color
|
||||
),
|
||||
isStrokeJoinRound: true,
|
||||
shadow: const BoxShadow(
|
||||
color: Colors.yellow,
|
||||
blurRadius: 4,
|
||||
offset: Offset(2, 2),
|
||||
),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: const [],
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
topTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Total passengers on month ${staticController.totalMonthlyPassengers}'
|
||||
.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Counts of Passengers on days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: const FlGridData(show: true),
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: const Border(
|
||||
bottom:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
left:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
SizedBox(
|
||||
height: Get.height * .3,
|
||||
width: double.maxFinite,
|
||||
// decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: MediaQuery.of(context).size.height * 0.4,
|
||||
child: LineChart(
|
||||
LineChartData(
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
isStepLineChart: true,
|
||||
spots: staticController.chartDataDrivers,
|
||||
isCurved: true,
|
||||
color: Colors.blue, // Custom color
|
||||
barWidth: 3, // Thinner line
|
||||
dotData: const FlDotData(
|
||||
show:
|
||||
true), // Show dots on each point
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.deepPurpleAccent
|
||||
.withOpacity(
|
||||
0.3), // Custom gradient color
|
||||
),
|
||||
isStrokeJoinRound: true,
|
||||
shadow: const BoxShadow(
|
||||
color: Colors.yellow,
|
||||
blurRadius: 4,
|
||||
offset: Offset(2, 2),
|
||||
),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: const [],
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
topTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Total Drivers on month ${staticController.totalMonthlyDrivers}'
|
||||
.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Counts of Drivers on days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: const FlGridData(show: true),
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: const Border(
|
||||
bottom:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
left:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
SizedBox(
|
||||
height: Get.height * .3,
|
||||
width: double.maxFinite,
|
||||
// decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: MediaQuery.of(context).size.height * 0.4,
|
||||
child: LineChart(
|
||||
LineChartData(
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
isStepLineChart: true,
|
||||
spots: staticController.chartDataRides,
|
||||
isCurved: true,
|
||||
color: const Color.fromARGB(
|
||||
255, 84, 181, 182), // Custom color
|
||||
barWidth: 3, // Thinner line
|
||||
dotData: const FlDotData(
|
||||
show:
|
||||
true), // Show dots on each point
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: const Color.fromARGB(
|
||||
255, 65, 144, 86)
|
||||
.withOpacity(
|
||||
0.3), // Custom gradient color
|
||||
),
|
||||
isStrokeJoinRound: true,
|
||||
shadow: const BoxShadow(
|
||||
color: Colors.yellow,
|
||||
blurRadius: 4,
|
||||
offset: Offset(2, 2),
|
||||
),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: const [],
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
topTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Total Rides on month ${staticController.totalMonthlyRides}'
|
||||
.tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Counts of Rides on days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: const FlGridData(show: true),
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: const Border(
|
||||
bottom:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
left:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
SizedBox(
|
||||
height: Get.height * .3,
|
||||
width: double.maxFinite,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: MediaQuery.of(context).size.height * 0.4,
|
||||
child: LineChart(
|
||||
LineChartData(
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
spots: staticController
|
||||
.chartDataEmployeeMaryam,
|
||||
isCurved: true,
|
||||
color:
|
||||
Colors.blue, // Custom color for Maryam
|
||||
barWidth: 3,
|
||||
dotData: const FlDotData(show: true),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.blue.withOpacity(0.3)),
|
||||
),
|
||||
LineChartBarData(
|
||||
spots:
|
||||
staticController.chartDataEmployeeRawda,
|
||||
isCurved: true,
|
||||
color: Colors.red, // Custom color for Rawda
|
||||
barWidth: 3,
|
||||
dotData: const FlDotData(show: true),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.red.withOpacity(0.3)),
|
||||
),
|
||||
LineChartBarData(
|
||||
spots:
|
||||
staticController.chartDataEmployeeMena,
|
||||
isCurved: true,
|
||||
color:
|
||||
Colors.green, // Custom color for Mena
|
||||
barWidth: 3,
|
||||
dotData: const FlDotData(show: true),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.green.withOpacity(0.3)),
|
||||
),
|
||||
LineChartBarData(
|
||||
spots: staticController
|
||||
.chartDataEmployeeSefer4,
|
||||
isCurved: true,
|
||||
color:
|
||||
Colors.yellow, // Custom color for Mena
|
||||
barWidth: 3,
|
||||
dotData: const FlDotData(show: true),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.yellow.withOpacity(0.3)),
|
||||
),
|
||||
],
|
||||
titlesData: const FlTitlesData(
|
||||
bottomTitles: AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: true),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: true),
|
||||
),
|
||||
),
|
||||
gridData: const FlGridData(show: true),
|
||||
borderData: FlBorderData(show: true),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// SizedBox(
|
||||
// height: Get.height * .3,
|
||||
// width: double.maxFinite,
|
||||
// // decoration: AppStyle.boxDecoration1,
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(6),
|
||||
// child: Container(
|
||||
// decoration: AppStyle.boxDecoration1,
|
||||
// height: MediaQuery.of(context).size.height * 0.4,
|
||||
// child: LineChart(
|
||||
// LineChartData(
|
||||
// lineBarsData: [
|
||||
// LineChartBarData(
|
||||
// isStepLineChart: true,
|
||||
// spots: staticController
|
||||
// .chartDataDriversCalling,
|
||||
// isCurved: true,
|
||||
// color: Colors
|
||||
// .deepPurpleAccent, // Custom color
|
||||
// barWidth: 3, // Thinner line
|
||||
// dotData: const FlDotData(
|
||||
// show:
|
||||
// true), // Show dots on each point
|
||||
// belowBarData: BarAreaData(
|
||||
// show: true,
|
||||
// color: Colors.deepPurpleAccent
|
||||
// .withOpacity(
|
||||
// 0.3), // Custom gradient color
|
||||
// ),
|
||||
// isStrokeJoinRound: true,
|
||||
// shadow: const BoxShadow(
|
||||
// color: Colors.yellow,
|
||||
// blurRadius: 4,
|
||||
// offset: Offset(2, 2),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// showingTooltipIndicators: const [],
|
||||
// titlesData: FlTitlesData(
|
||||
// show: true,
|
||||
// topTitles: AxisTitles(
|
||||
// axisNameWidget: Text(
|
||||
// 'Days'.tr,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// axisNameSize: 30,
|
||||
// ),
|
||||
// bottomTitles: AxisTitles(
|
||||
// axisNameWidget: Text(
|
||||
// 'Total Drivers on month are Calliing ${staticController.staticList[0]['totalMonthlyCallingDrivers']}'
|
||||
// .tr,
|
||||
// style: AppStyle.subtitle,
|
||||
// ),
|
||||
// axisNameSize: 30,
|
||||
// sideTitles: const SideTitles(
|
||||
// reservedSize: 30,
|
||||
// showTitles: true,
|
||||
// ),
|
||||
// ),
|
||||
// leftTitles: AxisTitles(
|
||||
// axisNameWidget: Text(
|
||||
// 'Counts of Drivers on days'.tr,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// axisNameSize: 30,
|
||||
// sideTitles: const SideTitles(
|
||||
// reservedSize: 30,
|
||||
// showTitles: true,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// gridData: const FlGridData(show: true),
|
||||
// borderData: FlBorderData(
|
||||
// show: true,
|
||||
// border: const Border(
|
||||
// bottom:
|
||||
// BorderSide(color: Colors.blueAccent),
|
||||
// left:
|
||||
// BorderSide(color: Colors.blueAccent),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// )),
|
||||
// const SizedBox(
|
||||
// height: 5,
|
||||
// ),
|
||||
SizedBox(
|
||||
height: Get.height * .3,
|
||||
width: double.maxFinite,
|
||||
// decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
height: MediaQuery.of(context).size.height * 0.4,
|
||||
child: LineChart(
|
||||
LineChartData(
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
isStepLineChart: true,
|
||||
spots: staticController
|
||||
.chartDataDriversMatchingNotes,
|
||||
isCurved: true,
|
||||
color: Colors
|
||||
.deepPurpleAccent, // Custom color
|
||||
barWidth: 3, // Thinner line
|
||||
dotData: const FlDotData(
|
||||
show:
|
||||
true), // Show dots on each point
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: Colors.deepPurpleAccent
|
||||
.withOpacity(
|
||||
0.3), // Custom gradient color
|
||||
),
|
||||
isStrokeJoinRound: true,
|
||||
shadow: const BoxShadow(
|
||||
color: Colors.yellow,
|
||||
blurRadius: 4,
|
||||
offset: Offset(2, 2),
|
||||
),
|
||||
),
|
||||
],
|
||||
showingTooltipIndicators: const [],
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
topTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Total Drivers on month are register after calling ${staticController.staticList[0]['totalMonthlyMatchingNotes']}'
|
||||
.tr,
|
||||
style: AppStyle.subtitle,
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
axisNameWidget: Text(
|
||||
'Counts of Drivers on days'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
axisNameSize: 30,
|
||||
sideTitles: const SideTitles(
|
||||
reservedSize: 30,
|
||||
showTitles: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: const FlGridData(show: true),
|
||||
borderData: FlBorderData(
|
||||
show: true,
|
||||
border: const Border(
|
||||
bottom:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
left:
|
||||
BorderSide(color: Colors.blueAccent),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
],
|
||||
);
|
||||
})
|
||||
],
|
||||
isleading: true);
|
||||
}
|
||||
}
|
||||
83
lib/views/admin/wallet/wallet.dart
Normal file
83
lib/views/admin/wallet/wallet.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/constant/style.dart';
|
||||
import 'package:sefer_admin1/views/widgets/elevated_btn.dart';
|
||||
import 'package:sefer_admin1/views/widgets/mycircular.dart';
|
||||
|
||||
import '../../../controller/admin/wallet_admin_controller.dart';
|
||||
import '../../widgets/my_scafold.dart';
|
||||
|
||||
class Wallet extends StatelessWidget {
|
||||
Wallet({super.key});
|
||||
WalletAdminController walletAdminController =
|
||||
Get.put(WalletAdminController());
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(
|
||||
title: 'Wallet'.tr,
|
||||
body: [
|
||||
GetBuilder<WalletAdminController>(builder: (walletAdminController) {
|
||||
return Center(
|
||||
child: walletAdminController.isLoading
|
||||
? const MyCircularProgressIndicator()
|
||||
: Column(
|
||||
children: [
|
||||
MyElevatedButton(
|
||||
title: 'Pay to them to banks'.tr,
|
||||
onPressed: () async {
|
||||
await walletAdminController.payToBankDriverAll();
|
||||
}),
|
||||
SizedBox(
|
||||
height: Get.height * .8,
|
||||
child: ListView.builder(
|
||||
itemCount:
|
||||
walletAdminController.driversWalletPoints.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
var res = walletAdminController
|
||||
.driversWalletPoints[index];
|
||||
|
||||
if (res != null && res['name_arabic'] != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Container(
|
||||
decoration: AppStyle.boxDecoration1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'driver name: ${res['name_arabic'].toString()}'),
|
||||
Text(
|
||||
'Amount: ${res['total_amount'].toString()}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container(); // Return an empty container if the data is null
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
isleading: true,
|
||||
action: IconButton(
|
||||
onPressed: () async {
|
||||
walletAdminController.getWalletForEachDriverToPay();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.refresh,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
88
lib/views/auth/login_page.dart
Normal file
88
lib/views/auth/login_page.dart
Normal file
@@ -0,0 +1,88 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sefer_admin1/env/env.dart';
|
||||
|
||||
import '../../controller/auth/login_controller.dart';
|
||||
import '../../controller/auth/otp_helper.dart';
|
||||
|
||||
class AdminLoginPage extends StatefulWidget {
|
||||
const AdminLoginPage({super.key});
|
||||
@override
|
||||
State<AdminLoginPage> createState() => _AdminLoginPageState();
|
||||
}
|
||||
|
||||
class _AdminLoginPageState extends State<AdminLoginPage> {
|
||||
final _phoneController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
bool _isLoading = false;
|
||||
Future<void> _submit() async {
|
||||
final allowedPhones = Env.ALLOWED_ADMIN_PHONES;
|
||||
allowedPhones.toString().split(',');
|
||||
|
||||
final phone = _phoneController.text.trim();
|
||||
|
||||
if (!allowedPhones.contains(phone)) {
|
||||
Get.snackbar('رفض الدخول', 'رقم الهاتف غير مخوّل بالدخول إلى الإدارة');
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
final otpSent = await OtpHelper.sendOtp(phone);
|
||||
if (otpSent) {
|
||||
Get.to(() => OtpVerificationAdmin(phone: phone));
|
||||
}
|
||||
|
||||
setState(() => _isLoading = false);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(OtpHelper());
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('دخول الإدارة')),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
// IntlPhoneField(
|
||||
// initialCountryCode: 'SY',
|
||||
// decoration: const InputDecoration(labelText: 'رقم الهاتف'),
|
||||
// onChanged: (phone) {
|
||||
// _phoneController.text = phone.completeNumber;
|
||||
// },
|
||||
// validator: (phone) {
|
||||
// if (phone == null || phone.completeNumber.isEmpty) {
|
||||
// return 'الرجاء إدخال رقم الهاتف';
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
// ),
|
||||
TextFormField(
|
||||
controller: _phoneController,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: const InputDecoration(labelText: 'رقم الهاتف'),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'الرجاء إدخال رقم الهاتف';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_isLoading
|
||||
? const CircularProgressIndicator()
|
||||
: ElevatedButton(
|
||||
onPressed: _submit,
|
||||
child: const Text('إرسال رمز التحقق'),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
187
lib/views/invoice/add_invoice_page.dart
Normal file
187
lib/views/invoice/add_invoice_page.dart
Normal file
@@ -0,0 +1,187 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:sefer_admin1/constant/colors.dart';
|
||||
import 'package:sefer_admin1/constant/links.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
||||
import 'package:sefer_admin1/views/widgets/my_textField.dart';
|
||||
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/info.dart';
|
||||
import '../../controller/functions/encrypt_decrypt.dart';
|
||||
import '../../main.dart';
|
||||
|
||||
class AddInvoicePage extends StatefulWidget {
|
||||
const AddInvoicePage({super.key});
|
||||
|
||||
@override
|
||||
State<AddInvoicePage> createState() => _AddInvoicePageState();
|
||||
}
|
||||
|
||||
class _AddInvoicePageState extends State<AddInvoicePage> {
|
||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||
final TextEditingController _itemNameController = TextEditingController();
|
||||
final TextEditingController _amountController = TextEditingController();
|
||||
File? _imageFile;
|
||||
bool _isLoading = false;
|
||||
|
||||
String generateInvoiceNumber() {
|
||||
final now = DateTime.now();
|
||||
return "INV-${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}-${now.microsecond}";
|
||||
}
|
||||
|
||||
Future<void> uploadInvoice() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
final driverID = '123'; // ← عدّله حسب نظامك
|
||||
final invoiceNumber = generateInvoiceNumber();
|
||||
final amount = _amountController.text.trim();
|
||||
final date = DateTime.now().toIso8601String().split('T').first;
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
try {
|
||||
final headers = {
|
||||
'Authorization':
|
||||
'Bearer ${r(box.read(BoxName.jwt)).split(AppInformation.addd)[0]}',
|
||||
'X-HMAC-Auth': '${box.read(BoxName.hmac)}',
|
||||
};
|
||||
final uri = Uri.parse(AppLink.addInvoice);
|
||||
final request = http.MultipartRequest('POST', uri)
|
||||
..fields['driverID'] = driverID
|
||||
..fields['invoiceNumber'] = invoiceNumber
|
||||
..fields['amount'] = amount
|
||||
..fields['date'] = date
|
||||
..headers.addAll(headers);
|
||||
|
||||
if (_imageFile != null) {
|
||||
final imageName = _imageFile!.path.split('/').last;
|
||||
final imageStream = http.ByteStream(_imageFile!.openRead());
|
||||
final imageLength = await _imageFile!.length();
|
||||
|
||||
request.files.add(http.MultipartFile(
|
||||
'image',
|
||||
imageStream,
|
||||
imageLength,
|
||||
filename: imageName,
|
||||
));
|
||||
} else {}
|
||||
|
||||
final response = await request.send();
|
||||
final respStr = await response.stream.bytesToString();
|
||||
|
||||
final data = jsonDecode(respStr);
|
||||
|
||||
if (data['status'] == 'success') {
|
||||
Get.snackbar('تم الحفظ', 'تم حفظ الفاتورة بنجاح',
|
||||
backgroundColor: Colors.green.shade100);
|
||||
|
||||
_itemNameController.clear();
|
||||
_amountController.clear();
|
||||
setState(() => _imageFile = null);
|
||||
Get.back(); // العودة للصفحة السابقة
|
||||
} else {
|
||||
Get.snackbar('خطأ', data['message'],
|
||||
backgroundColor: Colors.red.shade100);
|
||||
}
|
||||
} catch (e, stacktrace) {
|
||||
Get.snackbar('فشل الإرسال', e.toString(),
|
||||
backgroundColor: Colors.red.shade100);
|
||||
} finally {
|
||||
setState(() => _isLoading = false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> pickInvoiceImage() async {
|
||||
final picker = ImagePicker();
|
||||
final picked = await picker.pickImage(source: ImageSource.gallery);
|
||||
if (picked != null) {
|
||||
setState(() => _imageFile = File(picked.path));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_itemNameController.dispose();
|
||||
_amountController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(
|
||||
title: 'إضافة فاتورة جديدة',
|
||||
body: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
children: [
|
||||
MyTextForm(
|
||||
controller: _itemNameController,
|
||||
label: 'اسم البضاعة',
|
||||
hint: 'مثال: قطع غيار',
|
||||
type: TextInputType.text,
|
||||
// validator: (val) =>
|
||||
// val!.isEmpty ? 'الرجاء إدخال اسم البضاعة' : null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
MyTextForm(
|
||||
controller: _amountController,
|
||||
label: 'قيمة الفاتورة',
|
||||
hint: 'مثال: 150.75',
|
||||
type: TextInputType.numberWithOptions(decimal: true),
|
||||
// validator: (val) =>
|
||||
// val!.isEmpty ? 'الرجاء إدخال المبلغ' : null,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text('صورة الفاتورة (اختياري)',
|
||||
style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
height: 180,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade200,
|
||||
border: Border.all(color: Colors.grey.shade400),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: _imageFile != null
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Image.file(_imageFile!, fit: BoxFit.cover),
|
||||
)
|
||||
: const Center(child: Text('لم يتم اختيار صورة')),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ElevatedButton.icon(
|
||||
onPressed: pickInvoiceImage,
|
||||
icon: const Icon(Icons.image),
|
||||
label: const Text('اختيار صورة'),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
ElevatedButton(
|
||||
onPressed: _isLoading ? null : uploadInvoice,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
backgroundColor: AppColor.primaryColor,
|
||||
),
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator(color: Colors.white)
|
||||
: const Text(
|
||||
'حفظ الفاتورة',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
isleading: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
280
lib/views/invoice/invoice_list_page.dart
Normal file
280
lib/views/invoice/invoice_list_page.dart
Normal file
@@ -0,0 +1,280 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../../constant/links.dart';
|
||||
import '../../controller/admin/get_all_invoice_controller.dart';
|
||||
import '../../controller/functions/crud.dart';
|
||||
import '../../print.dart';
|
||||
import 'add_invoice_page.dart';
|
||||
|
||||
class InvoiceListPage extends StatefulWidget {
|
||||
@override
|
||||
_InvoiceListPageState createState() => _InvoiceListPageState();
|
||||
}
|
||||
|
||||
class _InvoiceListPageState extends State<InvoiceListPage> {
|
||||
List<InvoiceModel> invoices = [];
|
||||
int totalCount = 0;
|
||||
double totalAmount = 0.0;
|
||||
bool isLoading = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fetchInvoices();
|
||||
}
|
||||
|
||||
Future<void> fetchInvoices() async {
|
||||
// لإظهار مؤشر التحديث بشكل جيد
|
||||
if (!isLoading) {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
final response = await CRUD().post(link: AppLink.getInvoices, payload: {});
|
||||
final data = (response);
|
||||
Log.print('data: $data');
|
||||
|
||||
if (mounted) {
|
||||
if (data != 'failure' && data['status'] == 'success') {
|
||||
setState(() {
|
||||
invoices = List.from(data['data'])
|
||||
.map((item) => InvoiceModel.fromJson(item))
|
||||
.toList();
|
||||
totalCount = data['summary']['count'];
|
||||
totalAmount =
|
||||
double.tryParse(data['summary']['total'].toString()) ?? 0.0;
|
||||
isLoading = false;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
Get.snackbar("خطأ", "فشل في تحميل الفواتير. حاول التحديث مرة أخرى.",
|
||||
backgroundColor: Colors.red.withOpacity(0.8),
|
||||
colorText: Colors.white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- دالة لعرض الصورة في نافذة منبثقة ---
|
||||
void _showImageDialog(BuildContext context, String imageUrl) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
child: GestureDetector(
|
||||
// لإغلاق الصورة عند الضغط عليها
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: InteractiveViewer(
|
||||
// لإتاحة التكبير والتصغير
|
||||
panEnabled: true,
|
||||
minScale: 0.5,
|
||||
maxScale: 4,
|
||||
child: Image.network(
|
||||
imageUrl,
|
||||
fit: BoxFit.contain,
|
||||
// إظهار مؤشر تحميل أثناء جلب الصورة
|
||||
loadingBuilder: (BuildContext context, Widget child,
|
||||
ImageChunkEvent? loadingProgress) {
|
||||
if (loadingProgress == null) return child;
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: loadingProgress.expectedTotalBytes != null
|
||||
? loadingProgress.cumulativeBytesLoaded /
|
||||
loadingProgress.expectedTotalBytes!
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
// إظهار أيقونة خطأ في حال فشل تحميل الصورة
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Icon(Icons.broken_image,
|
||||
size: 100, color: Colors.red);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("قائمة الفواتير"),
|
||||
centerTitle: true,
|
||||
elevation: 2,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.add_a_photo),
|
||||
onPressed: () {
|
||||
// يمكنك إضافة إجراء الطباعة هنا
|
||||
|
||||
Get.to(() => AddInvoicePage());
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: isLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: RefreshIndicator(
|
||||
onRefresh: fetchInvoices, // خاصية السحب للتحديث
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0),
|
||||
itemCount: invoices.length,
|
||||
itemBuilder: (context, index) {
|
||||
final invoice = invoices[index];
|
||||
return Card(
|
||||
elevation: 4,
|
||||
margin: EdgeInsets.symmetric(vertical: 8.0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
onTap: () {
|
||||
// التحقق من وجود رابط للصورة قبل محاولة عرضه
|
||||
if (invoice.imageLink != null &&
|
||||
invoice.imageLink!.isNotEmpty) {
|
||||
_showImageDialog(context, invoice.imageLink!);
|
||||
} else {
|
||||
Get.snackbar("لا توجد صورة",
|
||||
"هذه الفاتورة لا تحتوي على صورة مرفقة.");
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
// أيقونة الفاتورة الرئيسية
|
||||
Icon(Icons.receipt_long,
|
||||
color: Theme.of(context).primaryColor,
|
||||
size: 40),
|
||||
SizedBox(width: 16),
|
||||
// تفاصيل الفاتورة
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"فاتورة رقم: ${invoice.invoiceNumber}",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
"الاسم: ${invoice.name}",
|
||||
style: TextStyle(
|
||||
color: Colors.green.shade700,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
"المبلغ: ${invoice.amount} د.أ",
|
||||
style: TextStyle(
|
||||
color: Colors.green.shade700,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
"التاريخ: ${invoice.date}",
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// أيقونة توضح وجود صورة
|
||||
if (invoice.imageLink != null &&
|
||||
invoice.imageLink!.isNotEmpty)
|
||||
Icon(Icons.image_outlined,
|
||||
color: Colors.blueAccent, size: 30),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
_buildSummaryCard(), // بطاقة الملخص السفلية
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSummaryCard() {
|
||||
return Card(
|
||||
margin: EdgeInsets.all(0),
|
||||
elevation: 8,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 25),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"إجمالي الفواتير",
|
||||
style: TextStyle(color: Colors.grey.shade600, fontSize: 14),
|
||||
),
|
||||
Text(
|
||||
"$totalCount",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"المبلغ الإجمالي",
|
||||
style: TextStyle(color: Colors.grey.shade600, fontSize: 14),
|
||||
),
|
||||
Text(
|
||||
"${totalAmount.toStringAsFixed(2)} د.أ",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
color: Colors.green.shade800,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
63
lib/views/widgets/circle_container.dart
Normal file
63
lib/views/widgets/circle_container.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
|
||||
class MyCircleContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Color backgroundColor;
|
||||
final Color borderColor;
|
||||
|
||||
MyCircleContainer({
|
||||
Key? key,
|
||||
required this.child,
|
||||
this.backgroundColor = AppColor.secondaryColor,
|
||||
this.borderColor = AppColor.accentColor,
|
||||
}) : super(key: key);
|
||||
|
||||
final controller = Get.put(CircleController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<CircleController>(
|
||||
builder: ((controller) => GestureDetector(
|
||||
onTap: () {
|
||||
controller.changeColor();
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
onEnd: () {
|
||||
controller.onEnd();
|
||||
},
|
||||
duration: const Duration(milliseconds: 300),
|
||||
width: controller.size,
|
||||
height: controller.size,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: controller.backgroundColor,
|
||||
border: Border.all(
|
||||
color: borderColor,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Center(child: child),
|
||||
),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
class CircleController extends GetxController {
|
||||
Color backgroundColor = AppColor.secondaryColor;
|
||||
double size = 40;
|
||||
void changeColor() {
|
||||
backgroundColor = backgroundColor == AppColor.secondaryColor
|
||||
? AppColor.accentColor
|
||||
: AppColor.secondaryColor;
|
||||
size = 60;
|
||||
update();
|
||||
}
|
||||
|
||||
void onEnd() {
|
||||
size = 40;
|
||||
update();
|
||||
}
|
||||
}
|
||||
47
lib/views/widgets/elevated_btn.dart
Normal file
47
lib/views/widgets/elevated_btn.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
|
||||
class MyElevatedButton extends StatelessWidget {
|
||||
final String title;
|
||||
final VoidCallback onPressed;
|
||||
final Color kolor;
|
||||
final int vibrateDuration;
|
||||
const MyElevatedButton({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.onPressed,
|
||||
this.kolor = AppColor.primaryColor,
|
||||
this.vibrateDuration = 100,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(kolor),
|
||||
),
|
||||
onPressed: () async {
|
||||
// Handle haptic feedback for both iOS and Android
|
||||
if (Platform.isIOS) {
|
||||
HapticFeedback.selectionClick();
|
||||
} else {
|
||||
// Vibration.vibrate(duration: 100);
|
||||
// Vibrate.vibrateWithPauses(pauses);
|
||||
}
|
||||
|
||||
// Ensure the onPressed callback is called after haptic feedback
|
||||
onPressed();
|
||||
},
|
||||
child: Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title.copyWith(color: AppColor.secondaryColor),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
66
lib/views/widgets/icon_widget_menu.dart
Normal file
66
lib/views/widgets/icon_widget_menu.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
|
||||
class IconWidgetMenu extends StatelessWidget {
|
||||
const IconWidgetMenu({
|
||||
Key? key,
|
||||
required this.onpressed,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onpressed;
|
||||
final IconData icon;
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onpressed,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 25),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.secondaryColor,
|
||||
offset: Offset(-2, -2),
|
||||
blurRadius: 0,
|
||||
spreadRadius: 0,
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color: AppColor.accentColor,
|
||||
offset: Offset(3, 3),
|
||||
blurRadius: 0,
|
||||
spreadRadius: 0,
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 30,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: AppStyle.subtitle,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
50
lib/views/widgets/my_scafold.dart
Normal file
50
lib/views/widgets/my_scafold.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
|
||||
class MyScafolld extends StatelessWidget {
|
||||
const MyScafolld({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.body,
|
||||
this.action = const Icon(
|
||||
Icons.clear,
|
||||
color: AppColor.secondaryColor,
|
||||
),
|
||||
required this.isleading,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final List<Widget> body;
|
||||
final Widget action;
|
||||
final bool isleading;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
appBar: AppBar(
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
elevation: 0,
|
||||
leading: isleading
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios_new,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
actions: [action],
|
||||
title: Text(
|
||||
title,
|
||||
style: AppStyle.title.copyWith(fontSize: 30),
|
||||
),
|
||||
),
|
||||
body: SafeArea(child: Stack(children: body)));
|
||||
}
|
||||
}
|
||||
65
lib/views/widgets/my_textField.dart
Normal file
65
lib/views/widgets/my_textField.dart
Normal file
@@ -0,0 +1,65 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
|
||||
class MyTextForm extends StatelessWidget {
|
||||
const MyTextForm({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.label,
|
||||
required this.hint,
|
||||
required this.type,
|
||||
});
|
||||
final TextEditingController controller;
|
||||
final String label, hint;
|
||||
final TextInputType type;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: SizedBox(
|
||||
width: Get.width * .8,
|
||||
child: TextFormField(
|
||||
keyboardType: type,
|
||||
cursorColor: AppColor.accentColor,
|
||||
controller: controller,
|
||||
decoration: InputDecoration(
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(
|
||||
color: AppColor.primaryColor,
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
focusColor: AppColor.accentColor,
|
||||
fillColor: AppColor.accentColor,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12))),
|
||||
labelText: label.tr,
|
||||
hintText: hint.tr,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Please enter $label.'.tr;
|
||||
}
|
||||
|
||||
if (type == TextInputType.emailAddress) {
|
||||
if (!value.contains('@')) {
|
||||
return 'Please enter a valid email.'.tr;
|
||||
}
|
||||
} else if (type == TextInputType.phone) {
|
||||
if (value.length != 11) {
|
||||
return 'Please enter a valid phone number.'.tr;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
37
lib/views/widgets/mycircular.dart
Normal file
37
lib/views/widgets/mycircular.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MyCircularProgressIndicator extends StatelessWidget {
|
||||
final Color backgroundColor;
|
||||
|
||||
const MyCircularProgressIndicator({
|
||||
super.key,
|
||||
this.backgroundColor = Colors.transparent,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: 110,
|
||||
height: 110,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
Column(
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Image.asset('assets/images/logo.png'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
243
lib/views/widgets/mydialoug.dart
Executable file
243
lib/views/widgets/mydialoug.dart
Executable file
@@ -0,0 +1,243 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
|
||||
class DialogConfig {
|
||||
static const Duration animationDuration = Duration(milliseconds: 200);
|
||||
static const double blurStrength = 8.0;
|
||||
static const double cornerRadius = 14.0;
|
||||
static final BoxDecoration decoration = BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(cornerRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha(38), // 0.15 opacity
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class MyDialog extends GetxController {
|
||||
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
|
||||
HapticFeedback.mediumImpact();
|
||||
|
||||
Get.dialog(
|
||||
TweenAnimationBuilder<double>(
|
||||
duration: DialogConfig.animationDuration,
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
builder: (context, value, child) {
|
||||
return Transform.scale(
|
||||
scale: 0.95 + (0.05 * value),
|
||||
child: Opacity(opacity: value, child: child),
|
||||
);
|
||||
},
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: DialogConfig.blurStrength,
|
||||
sigmaY: DialogConfig.blurStrength,
|
||||
),
|
||||
child: Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
dialogBackgroundColor: CupertinoColors.systemBackground,
|
||||
),
|
||||
child: CupertinoAlertDialog(
|
||||
title: Column(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.5,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
children: [
|
||||
CupertinoButton(
|
||||
padding: const EdgeInsets.all(8),
|
||||
onPressed: () async {
|
||||
HapticFeedback.selectionClick();
|
||||
// await textToSpeechController.speakText(title);
|
||||
// await textToSpeechController.speakText(midTitle!);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
AppColor.primaryColor.withAlpha(26), // 0.1 opacity
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
CupertinoIcons.speaker_2_fill,
|
||||
color: AppColor.primaryColor,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
midTitle!,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 16,
|
||||
height: 1.3,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
onPressed: () {
|
||||
HapticFeedback.lightImpact();
|
||||
Get.back();
|
||||
},
|
||||
child: Text(
|
||||
'Cancel'.tr,
|
||||
style: TextStyle(
|
||||
color: AppColor.redColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 17,
|
||||
),
|
||||
),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
onPressed: () {
|
||||
HapticFeedback.mediumImpact();
|
||||
onPressed();
|
||||
},
|
||||
child: Text(
|
||||
'OK'.tr,
|
||||
style: TextStyle(
|
||||
color: AppColor.greenColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 17,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
barrierDismissible: true,
|
||||
barrierColor: Colors.black.withAlpha(102), // 0.4 opacity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyDialogContent extends GetxController {
|
||||
void getDialog(String title, Widget? content, VoidCallback onPressed) {
|
||||
// final textToSpeechController = Get.put(TextToSpeechController());
|
||||
|
||||
HapticFeedback.mediumImpact();
|
||||
|
||||
Get.dialog(
|
||||
TweenAnimationBuilder<double>(
|
||||
duration: DialogConfig.animationDuration,
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
builder: (context, value, child) {
|
||||
return Transform.scale(
|
||||
scale: 0.95 + (0.05 * value),
|
||||
child: Opacity(opacity: value, child: child),
|
||||
);
|
||||
},
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: DialogConfig.blurStrength,
|
||||
sigmaY: DialogConfig.blurStrength,
|
||||
),
|
||||
child: Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
dialogBackgroundColor: CupertinoColors.systemBackground,
|
||||
),
|
||||
child: CupertinoAlertDialog(
|
||||
title: Column(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.5,
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
children: [
|
||||
CupertinoButton(
|
||||
padding: const EdgeInsets.all(8),
|
||||
onPressed: () async {
|
||||
HapticFeedback.selectionClick();
|
||||
// await textToSpeechController.speakText(title);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
AppColor.primaryColor.withAlpha(26), // 0.1 opacity
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
CupertinoIcons.headphones,
|
||||
color: AppColor.primaryColor,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
content!,
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
onPressed: () {
|
||||
HapticFeedback.lightImpact();
|
||||
Get.back();
|
||||
},
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: TextStyle(
|
||||
color: AppColor.redColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 17,
|
||||
),
|
||||
),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
onPressed: () {
|
||||
HapticFeedback.mediumImpact();
|
||||
onPressed();
|
||||
},
|
||||
child: Text(
|
||||
'OK'.tr,
|
||||
style: TextStyle(
|
||||
color: AppColor.greenColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 17,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
barrierDismissible: true,
|
||||
barrierColor: Colors.black.withAlpha(102), // 0.4 opacity
|
||||
);
|
||||
}
|
||||
}
|
||||
123
lib/views/widgets/snackbar.dart
Normal file
123
lib/views/widgets/snackbar.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
|
||||
class SnackbarConfig {
|
||||
static const duration = Duration(seconds: 3);
|
||||
static const animationDuration = Duration(milliseconds: 300);
|
||||
static const margin = EdgeInsets.symmetric(horizontal: 16, vertical: 10);
|
||||
static const borderRadius = 12.0;
|
||||
static const elevation = 6.0;
|
||||
|
||||
static final BoxShadow shadow = BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
);
|
||||
}
|
||||
|
||||
SnackbarController mySnackeBarError(String message) {
|
||||
// Trigger error haptic feedback
|
||||
HapticFeedback.mediumImpact();
|
||||
|
||||
return Get.snackbar(
|
||||
'Error'.tr,
|
||||
message,
|
||||
backgroundColor: AppColor.redColor.withOpacity(0.95),
|
||||
colorText: AppColor.secondaryColor,
|
||||
icon: const Icon(
|
||||
Icons.error_outline_rounded,
|
||||
color: AppColor.secondaryColor,
|
||||
size: 28,
|
||||
),
|
||||
shouldIconPulse: true,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
margin: SnackbarConfig.margin,
|
||||
borderRadius: SnackbarConfig.borderRadius,
|
||||
duration: SnackbarConfig.duration,
|
||||
animationDuration: SnackbarConfig.animationDuration,
|
||||
forwardAnimationCurve: Curves.easeOutCirc,
|
||||
reverseAnimationCurve: Curves.easeInCirc,
|
||||
boxShadows: [SnackbarConfig.shadow],
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
titleText: Text(
|
||||
'Error'.tr,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
letterSpacing: 0.2,
|
||||
),
|
||||
),
|
||||
messageText: Text(
|
||||
message,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.95),
|
||||
fontSize: 14,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
onTap: (_) {
|
||||
HapticFeedback.lightImpact();
|
||||
Get.closeCurrentSnackbar();
|
||||
},
|
||||
isDismissible: true,
|
||||
dismissDirection: DismissDirection.horizontal,
|
||||
overlayBlur: 0.8,
|
||||
overlayColor: Colors.black12,
|
||||
);
|
||||
}
|
||||
|
||||
SnackbarController mySnackbarSuccess(String message) {
|
||||
// Trigger success haptic feedback
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
return Get.snackbar(
|
||||
'Success'.tr,
|
||||
message,
|
||||
backgroundColor: AppColor.greenColor.withOpacity(0.95),
|
||||
colorText: AppColor.secondaryColor,
|
||||
icon: const Icon(
|
||||
Icons.check_circle_outline_rounded,
|
||||
color: AppColor.secondaryColor,
|
||||
size: 28,
|
||||
),
|
||||
shouldIconPulse: true,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
margin: SnackbarConfig.margin,
|
||||
borderRadius: SnackbarConfig.borderRadius,
|
||||
duration: SnackbarConfig.duration,
|
||||
animationDuration: SnackbarConfig.animationDuration,
|
||||
forwardAnimationCurve: Curves.easeOutCirc,
|
||||
reverseAnimationCurve: Curves.easeInCirc,
|
||||
boxShadows: [SnackbarConfig.shadow],
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
titleText: Text(
|
||||
'Success'.tr,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
letterSpacing: 0.2,
|
||||
),
|
||||
),
|
||||
messageText: Text(
|
||||
message,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.95),
|
||||
fontSize: 14,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
onTap: (_) {
|
||||
HapticFeedback.lightImpact();
|
||||
Get.closeCurrentSnackbar();
|
||||
},
|
||||
isDismissible: true,
|
||||
dismissDirection: DismissDirection.horizontal,
|
||||
overlayBlur: 0.8,
|
||||
overlayColor: Colors.black12,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user