Update: 2026-06-10 02:44:54
36
backend/migration_referral_system.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- 1. Table for storing the unified 6-digit referral code for each user (Driver/Passenger)
|
||||
CREATE TABLE `user_referral_codes` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` VARCHAR(100) NOT NULL,
|
||||
`user_type` ENUM('driver', 'passenger') NOT NULL,
|
||||
`referral_code` VARCHAR(6) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_user_type_id` (`user_id`, `user_type`),
|
||||
UNIQUE KEY `idx_referral_code` (`referral_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 2. Table for tracking the referral relationship and trip counts
|
||||
CREATE TABLE `unified_referrals` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`inviter_code` VARCHAR(6) NOT NULL,
|
||||
`invited_user_id` VARCHAR(100) NOT NULL,
|
||||
`invited_user_type` ENUM('driver', 'passenger') NOT NULL,
|
||||
`status` ENUM('registered', 'active', 'completed') NOT NULL DEFAULT 'registered',
|
||||
`trip_count` INT NOT NULL DEFAULT 0,
|
||||
`is_reward_claimed` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_invited_user` (`invited_user_id`, `invited_user_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
-- 3. Table for Driver Cash Claims (when a driver requests to receive their reward as manual cash)
|
||||
CREATE TABLE `driver_cash_claims` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`driver_id` VARCHAR(100) NOT NULL,
|
||||
`referral_id` INT NOT NULL,
|
||||
`amount_syp` INT NOT NULL,
|
||||
`status` ENUM('pending', 'paid') NOT NULL DEFAULT 'pending',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
37
backend/ride/invitor/add_unified_invite.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$inviterCode = filterRequest("inviter_code");
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$inviterCode || !$user_id || !in_array($role, ['driver', 'passenger'])) {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// Ensure the code exists and get the inviter details
|
||||
$stmtCheck = $con->prepare("SELECT user_id, user_type FROM user_referral_codes WHERE referral_code = ?");
|
||||
$stmtCheck->execute([$inviterCode]);
|
||||
|
||||
if ($stmtCheck->rowCount() == 0) {
|
||||
jsonError("Invalid referral code");
|
||||
}
|
||||
$inviterData = $stmtCheck->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Check if user was already invited
|
||||
$stmtExisting = $con->prepare("SELECT id FROM unified_referrals WHERE invited_user_id = ? AND invited_user_type = ?");
|
||||
$stmtExisting->execute([$user_id, $role]);
|
||||
|
||||
if ($stmtExisting->rowCount() > 0) {
|
||||
jsonError("User already registered with a referral code");
|
||||
}
|
||||
|
||||
// Insert new referral
|
||||
$insertStmt = $con->prepare("INSERT INTO unified_referrals (inviter_code, invited_user_id, invited_user_type, status, trip_count, is_reward_claimed) VALUES (?, ?, ?, 'registered', 0, 0)");
|
||||
|
||||
try {
|
||||
$insertStmt->execute([$inviterCode, $user_id, $role]);
|
||||
printSuccess(["message" => "Referral linked successfully"]);
|
||||
} catch (PDOException $e) {
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
80
backend/ride/invitor/claim_driver_reward.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
$referralId = filterRequest("referral_id");
|
||||
$claimType = filterRequest("claim_type"); // 'wallet' or 'cash'
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$user_id || $role != 'driver' || !$referralId || !in_array($claimType, ['wallet', 'cash'])) {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// 1. Get the referral info
|
||||
$stmt = $con->prepare("
|
||||
SELECT r.id, r.inviter_code, r.invited_user_id, r.invited_user_type, r.trip_count, r.is_reward_claimed, c.user_id as inviter_id, c.user_type as inviter_type
|
||||
FROM unified_referrals r
|
||||
JOIN user_referral_codes c ON r.inviter_code = c.referral_code
|
||||
WHERE r.id = ? AND c.user_id = ? AND c.user_type = 'driver'
|
||||
");
|
||||
$stmt->execute([$referralId, $user_id]);
|
||||
|
||||
if ($stmt->rowCount() == 0) {
|
||||
jsonError("Referral not found or unauthorized");
|
||||
}
|
||||
|
||||
$referral = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($referral['is_reward_claimed'] == 1) {
|
||||
jsonError("Reward already claimed");
|
||||
}
|
||||
|
||||
// Logic:
|
||||
// Driver -> Driver: 50 trips = 500 SYP (example)
|
||||
// Driver -> Passenger: 10 trips = 30 SYP per trip. This could be progressive, but for manual claim we assume completed
|
||||
$amountSyp = 0;
|
||||
|
||||
if ($referral['invited_user_type'] == 'driver') {
|
||||
if ($referral['trip_count'] >= 50) {
|
||||
$amountSyp = 500;
|
||||
} else {
|
||||
jsonError("Requirement not met (50 trips required)");
|
||||
}
|
||||
} else if ($referral['invited_user_type'] == 'passenger') {
|
||||
if ($referral['trip_count'] >= 1) {
|
||||
// Here, user gets 30 SYP per trip, max 10. Let's assume claim all at once up to 10.
|
||||
$tripsToClaim = min($referral['trip_count'], 10);
|
||||
$amountSyp = $tripsToClaim * 30;
|
||||
} else {
|
||||
jsonError("Requirement not met (At least 1 trip required)");
|
||||
}
|
||||
}
|
||||
|
||||
if ($amountSyp <= 0) {
|
||||
jsonError("No reward available to claim");
|
||||
}
|
||||
|
||||
try {
|
||||
$con->beginTransaction();
|
||||
|
||||
// Mark as claimed
|
||||
$updateStmt = $con->prepare("UPDATE unified_referrals SET is_reward_claimed = 1, status = 'claimed' WHERE id = ?");
|
||||
$updateStmt->execute([$referralId]);
|
||||
|
||||
if ($claimType == 'wallet') {
|
||||
// Add to driver wallet
|
||||
$walletStmt = $con->prepare("UPDATE driver SET wallet = wallet + ? WHERE id = ?");
|
||||
$walletStmt->execute([$amountSyp, $user_id]);
|
||||
} else if ($claimType == 'cash') {
|
||||
// Request manual cash out
|
||||
$cashStmt = $con->prepare("INSERT INTO driver_cash_claims (driver_id, referral_id, amount_syp, status) VALUES (?, ?, ?, 'pending')");
|
||||
$cashStmt->execute([$user_id, $referralId, $amountSyp]);
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
printSuccess(["message" => "Reward claimed successfully as $claimType"]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$con->rollBack();
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
60
backend/ride/invitor/get_driver_referrals.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$user_id || $role != 'driver') {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// 1. Get the driver's referral code
|
||||
$stmtCode = $con->prepare("SELECT referral_code FROM user_referral_codes WHERE user_id = ? AND user_type = 'driver'");
|
||||
$stmtCode->execute([$user_id]);
|
||||
|
||||
if ($stmtCode->rowCount() == 0) {
|
||||
// If no code exists, return empty stats
|
||||
printSuccess([
|
||||
"referral_code" => null,
|
||||
"total_invited_drivers" => 0,
|
||||
"total_invited_passengers" => 0,
|
||||
"referrals" => []
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$referralCode = $stmtCode->fetchColumn();
|
||||
|
||||
// 2. Fetch all referrals made by this code
|
||||
$stmtRefs = $con->prepare("
|
||||
SELECT id, invited_user_id, invited_user_type, status, trip_count, is_reward_claimed, created_at
|
||||
FROM unified_referrals
|
||||
WHERE inviter_code = ?
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmtRefs->execute([$referralCode]);
|
||||
$referrals = $stmtRefs->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$totalDrivers = 0;
|
||||
$totalPassengers = 0;
|
||||
|
||||
// Format data and calculate stats
|
||||
foreach ($referrals as &$ref) {
|
||||
if ($ref['invited_user_type'] == 'driver') {
|
||||
$totalDrivers++;
|
||||
$ref['target_trips'] = 50;
|
||||
$ref['reward_syp'] = 500;
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 50 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
} else {
|
||||
$totalPassengers++;
|
||||
$ref['target_trips'] = 1;
|
||||
$ref['reward_syp'] = 30 * min($ref['trip_count'], 10); // Or max depending on logic
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 1 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
printSuccess([
|
||||
"referral_code" => $referralCode,
|
||||
"total_invited_drivers" => $totalDrivers,
|
||||
"total_invited_passengers" => $totalPassengers,
|
||||
"referrals" => $referrals
|
||||
]);
|
||||
?>
|
||||
60
backend/ride/invitor/get_passenger_referrals.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
// Use JWT token variables provided by connect.php
|
||||
if (!$user_id || $role != 'passenger') {
|
||||
jsonError("Invalid parameters or unauthorized token");
|
||||
}
|
||||
|
||||
// 1. Get the passenger's referral code
|
||||
$stmtCode = $con->prepare("SELECT referral_code FROM user_referral_codes WHERE user_id = ? AND user_type = 'passenger'");
|
||||
$stmtCode->execute([$user_id]);
|
||||
|
||||
if ($stmtCode->rowCount() == 0) {
|
||||
// If no code exists, return empty stats
|
||||
printSuccess([
|
||||
"referral_code" => null,
|
||||
"total_invited_drivers" => 0,
|
||||
"total_invited_passengers" => 0,
|
||||
"referrals" => []
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$referralCode = $stmtCode->fetchColumn();
|
||||
|
||||
// 2. Fetch all referrals made by this code
|
||||
$stmtRefs = $con->prepare("
|
||||
SELECT id, invited_user_id, invited_user_type, status, trip_count, is_reward_claimed, created_at
|
||||
FROM unified_referrals
|
||||
WHERE inviter_code = ?
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmtRefs->execute([$referralCode]);
|
||||
$referrals = $stmtRefs->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$totalDrivers = 0;
|
||||
$totalPassengers = 0;
|
||||
|
||||
// Format data and calculate stats
|
||||
foreach ($referrals as &$ref) {
|
||||
if ($ref['invited_user_type'] == 'driver') {
|
||||
$totalDrivers++;
|
||||
$ref['target_trips'] = 50;
|
||||
$ref['reward_syp'] = 500;
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 50 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
} else {
|
||||
$totalPassengers++;
|
||||
$ref['target_trips'] = 1;
|
||||
$ref['reward_syp'] = 30; // Just illustrative, rewards are automatic
|
||||
$ref['can_claim'] = ($ref['trip_count'] >= 1 && $ref['is_reward_claimed'] == 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
printSuccess([
|
||||
"referral_code" => $referralCode,
|
||||
"total_invited_drivers" => $totalDrivers,
|
||||
"total_invited_passengers" => $totalPassengers,
|
||||
"referrals" => $referrals
|
||||
]);
|
||||
?>
|
||||
41
backend/ride/invitor/get_unified_code.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
function generateUnifiedCode($con) {
|
||||
while (true) {
|
||||
$letters = substr(str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZ"), 0, 2);
|
||||
$numbers = substr(str_shuffle("23456789"), 0, 4);
|
||||
$code = $letters . $numbers;
|
||||
|
||||
$stmt = $con->prepare("SELECT COUNT(*) FROM user_referral_codes WHERE referral_code = ?");
|
||||
$stmt->execute([$code]);
|
||||
|
||||
if ($stmt->fetchColumn() == 0) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the JWT values exist
|
||||
if (!$user_id || !in_array($role, ['driver', 'passenger'])) {
|
||||
jsonError("Invalid or missing user information in token");
|
||||
}
|
||||
|
||||
$stmt = $con->prepare("SELECT referral_code FROM user_referral_codes WHERE user_id = ? AND user_type = ?");
|
||||
$stmt->execute([$user_id, $role]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
printSuccess(["referral_code" => $row['referral_code']]);
|
||||
} else {
|
||||
$newCode = generateUnifiedCode($con);
|
||||
$insertStmt = $con->prepare("INSERT INTO user_referral_codes (user_id, user_type, referral_code) VALUES (?, ?, ?)");
|
||||
|
||||
try {
|
||||
$insertStmt->execute([$user_id, $role, $newCode]);
|
||||
printSuccess(["referral_code" => $newCode]);
|
||||
} catch (PDOException $e) {
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1782,3 +1782,45 @@ CREATE TABLE `write_argument_after_applied_from_background` (
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2026-04-22 19:40:54
|
||||
|
||||
--
|
||||
-- Table structure for table `user_referral_codes`
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `user_referral_codes` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`user_id` varchar(100) NOT NULL,
|
||||
`user_type` enum('driver','passenger') NOT NULL,
|
||||
`referral_code` varchar(20) NOT NULL UNIQUE,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
--
|
||||
-- Table structure for table `unified_referrals`
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `unified_referrals` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`inviter_code` varchar(20) NOT NULL,
|
||||
`invited_user_id` varchar(100) NOT NULL,
|
||||
`invited_user_type` enum('driver','passenger') NOT NULL,
|
||||
`status` enum('registered','first_trip','claimed') DEFAULT 'registered',
|
||||
`trip_count` int DEFAULT 0,
|
||||
`is_reward_claimed` tinyint(1) DEFAULT 0,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
--
|
||||
-- Table structure for table `driver_cash_claims`
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `driver_cash_claims` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`driver_id` varchar(100) NOT NULL,
|
||||
`referral_id` int NOT NULL,
|
||||
`amount_syp` decimal(10,2) NOT NULL,
|
||||
`status` enum('pending','paid','rejected') DEFAULT 'pending',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
@@ -208,8 +208,8 @@ CREATE TABLE `car_locations` (
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
|
||||
DELIMITER ;;
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
END */;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
@@ -225,10 +225,10 @@ DELIMITER ;
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO' */ ;
|
||||
DELIMITER ;;
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
|
||||
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
END IF;
|
||||
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
|
||||
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
|
||||
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
|
||||
END IF;
|
||||
END */;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SOURCE_DIR = "/Users/hamzaaleghwairyeen/development/App"
|
||||
TARGET_DIR = "/Users/hamzaaleghwairyeen/development/App/Siro"
|
||||
|
||||
mappings = [
|
||||
{
|
||||
"src": "Intaleq",
|
||||
"dst": "siro_rider",
|
||||
"old_app_id": "com.Intaleq.intaleq",
|
||||
"new_app_id": "com.siro.siro_rider",
|
||||
"extra_folders": ["packages"]
|
||||
},
|
||||
{
|
||||
"src": "intaleq_driver",
|
||||
"dst": "siro_driver",
|
||||
"old_app_id": "com.intaleq_driver",
|
||||
"new_app_id": "com.siro.siro_driver",
|
||||
"extra_folders": ["bubble-master", "trip_overlay_plugin"]
|
||||
},
|
||||
{
|
||||
"src": "intaleq_admin",
|
||||
"dst": "siro_admin",
|
||||
"old_app_id": "com.intaleq.intaleq_admin",
|
||||
"new_app_id": "com.siro.siro_admin",
|
||||
"extra_folders": []
|
||||
},
|
||||
{
|
||||
"src": "service_intaleq",
|
||||
"dst": "siro_service",
|
||||
"old_app_id": "com.service_intaleq",
|
||||
"new_app_id": "com.siro.siro_service",
|
||||
"extra_folders": []
|
||||
}
|
||||
]
|
||||
|
||||
def replace_in_file(filepath, old_str, new_str):
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
if old_str in content:
|
||||
content = content.replace(old_str, new_str)
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def process():
|
||||
for m in mappings:
|
||||
src_app = os.path.join(SOURCE_DIR, m['src'])
|
||||
dst_app = os.path.join(TARGET_DIR, m['dst'])
|
||||
|
||||
print(f"Processing native folders for {m['dst']}...")
|
||||
|
||||
# 1. Copy native folders
|
||||
native_folders = ['android', 'ios', 'macos', 'web']
|
||||
for folder in native_folders:
|
||||
s_folder = os.path.join(src_app, folder)
|
||||
d_folder = os.path.join(dst_app, folder)
|
||||
if os.path.exists(s_folder):
|
||||
if os.path.exists(d_folder):
|
||||
shutil.rmtree(d_folder)
|
||||
shutil.copytree(s_folder, d_folder, symlinks=True, ignore=shutil.ignore_patterns('.symlinks', 'Pods', 'build', '.dart_tool'))
|
||||
|
||||
# 2. Copy extra internal packages
|
||||
for folder in m['extra_folders']:
|
||||
s_folder = os.path.join(src_app, folder)
|
||||
d_folder = os.path.join(dst_app, folder)
|
||||
if os.path.exists(s_folder):
|
||||
if os.path.exists(d_folder):
|
||||
shutil.rmtree(d_folder)
|
||||
shutil.copytree(s_folder, d_folder, symlinks=True, ignore=shutil.ignore_patterns('build', '.dart_tool'))
|
||||
|
||||
# 3. Android Package Renaming
|
||||
old_app_id = m['old_app_id']
|
||||
new_app_id = m['new_app_id']
|
||||
|
||||
android_dir = os.path.join(dst_app, 'android')
|
||||
if os.path.exists(android_dir):
|
||||
# Replace string occurrences in Android files
|
||||
for root, dirs, files in os.walk(android_dir):
|
||||
for file in files:
|
||||
if file.endswith(('.kt', '.java', '.xml', '.gradle', '.gradle.kts', '.pro')):
|
||||
replace_in_file(os.path.join(root, file), old_app_id, new_app_id)
|
||||
|
||||
# Move kotlin/java directory structure
|
||||
for lang in ['kotlin', 'java']:
|
||||
for source_type in ['main', 'debug', 'profile']:
|
||||
src_dir = os.path.join(android_dir, 'app', 'src', source_type, lang)
|
||||
if os.path.exists(src_dir):
|
||||
old_path = os.path.join(src_dir, *old_app_id.split('.'))
|
||||
new_path = os.path.join(src_dir, *new_app_id.split('.'))
|
||||
|
||||
if os.path.exists(old_path) and old_path != new_path:
|
||||
os.makedirs(new_path, exist_ok=True)
|
||||
for item in os.listdir(old_path):
|
||||
shutil.move(os.path.join(old_path, item), new_path)
|
||||
|
||||
# Clean up old empty directories
|
||||
curr = old_path
|
||||
while curr != src_dir:
|
||||
if not os.listdir(curr):
|
||||
os.rmdir(curr)
|
||||
curr = os.path.dirname(curr)
|
||||
|
||||
# 4. iOS Bundle ID Renaming
|
||||
ios_dir = os.path.join(dst_app, 'ios')
|
||||
if os.path.exists(ios_dir):
|
||||
for root, dirs, files in os.walk(ios_dir):
|
||||
for file in files:
|
||||
if file.endswith(('.pbxproj', '.plist', '.m', '.h', '.swift', '.storyboard', '.xcconfig')):
|
||||
replace_in_file(os.path.join(root, file), old_app_id, new_app_id)
|
||||
|
||||
print("Done copying and modifying native folders.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
process()
|
||||
@@ -1,84 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
void main() async {
|
||||
var sourceDir = Directory("/Users/hamzaaleghwairyeen/development/App");
|
||||
var targetDir = Directory("/Users/hamzaaleghwairyeen/development/App/Siro");
|
||||
|
||||
var mappings = [
|
||||
{"src": "Intaleq", "dst": "siro_rider", "old_pkg": "Intaleq", "new_pkg": "siro_rider"},
|
||||
{"src": "intaleq_driver", "dst": "siro_driver", "old_pkg": "sefer_driver", "new_pkg": "siro_driver"},
|
||||
{"src": "intaleq_admin", "dst": "siro_admin", "old_pkg": "sefer_admin1", "new_pkg": "siro_admin"},
|
||||
{"src": "service_intaleq", "dst": "siro_service", "old_pkg": "service", "new_pkg": "siro_service"}
|
||||
];
|
||||
|
||||
for (var m in mappings) {
|
||||
var srcPath = "\${sourceDir.path}/\${m['src']}";
|
||||
var dstPath = "\${targetDir.path}/\${m['dst']}";
|
||||
|
||||
// 1. Delete destination lib and assets
|
||||
for (var folder in ['lib', 'assets', 'secure_string_operations']) {
|
||||
var dFolder = Directory("\$dstPath/\$folder");
|
||||
if (dFolder.existsSync()) {
|
||||
dFolder.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Copy lib and assets
|
||||
for (var folder in ['lib', 'assets', 'secure_string_operations']) {
|
||||
var sFolder = Directory("\$srcPath/\$folder");
|
||||
var dFolder = Directory("\$dstPath/\$folder");
|
||||
if (sFolder.existsSync()) {
|
||||
copyDirectorySync(sFolder, dFolder);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Copy pubspec.yaml
|
||||
var sPubspec = File("\$srcPath/pubspec.yaml");
|
||||
var dPubspec = File("\$dstPath/pubspec.yaml");
|
||||
if (sPubspec.existsSync()) {
|
||||
sPubspec.copySync(dPubspec.path);
|
||||
}
|
||||
|
||||
// 4. Replace package name in pubspec.yaml
|
||||
if (dPubspec.existsSync()) {
|
||||
var content = dPubspec.readAsStringSync();
|
||||
content = content.replaceAll(RegExp(r"^name:\s*" + m["old_pkg"]! + r"\s*$", multiLine: true), "name: \${m['new_pkg']}");
|
||||
dPubspec.writeAsStringSync(content);
|
||||
}
|
||||
|
||||
// 5. Replace imports
|
||||
for (var rootFolder in ['lib', 'test']) {
|
||||
var rootPath = Directory("\$dstPath/\$rootFolder");
|
||||
if (!rootPath.existsSync()) continue;
|
||||
|
||||
var files = rootPath.listSync(recursive: true).whereType<File>();
|
||||
for (var file in files) {
|
||||
if (file.path.endsWith('.dart')) {
|
||||
try {
|
||||
var content = file.readAsStringSync();
|
||||
var newContent = content.replaceAll("package:\${m['old_pkg']}/", "package:\${m['new_pkg']}/");
|
||||
if (newContent != content) {
|
||||
file.writeAsStringSync(newContent);
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error reading \${file.path}: \$e");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
print("Done");
|
||||
}
|
||||
|
||||
void copyDirectorySync(Directory source, Directory destination) {
|
||||
destination.createSync(recursive: true);
|
||||
for (var entity in source.listSync(recursive: false)) {
|
||||
if (entity is Directory) {
|
||||
var newDirectory = Directory("\${destination.absolute.path}/\${entity.path.split('/').last}");
|
||||
newDirectory.createSync();
|
||||
copyDirectorySync(entity.absolute, newDirectory);
|
||||
} else if (entity is File) {
|
||||
entity.copySync("\${destination.path}/\${entity.path.split('/').last}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
source_dir = "/Users/hamzaaleghwairyeen/development/App"
|
||||
target_dir = "/Users/hamzaaleghwairyeen/development/App/Siro"
|
||||
|
||||
mappings = [
|
||||
{"src": "Intaleq", "dst": "siro_rider", "old_pkg": "Intaleq", "new_pkg": "siro_rider"},
|
||||
{"src": "intaleq_driver", "dst": "siro_driver", "old_pkg": "sefer_driver", "new_pkg": "siro_driver"},
|
||||
{"src": "intaleq_admin", "dst": "siro_admin", "old_pkg": "sefer_admin1", "new_pkg": "siro_admin"},
|
||||
{"src": "service_intaleq", "dst": "siro_service", "old_pkg": "service", "new_pkg": "siro_service"}
|
||||
]
|
||||
|
||||
def copy_and_replace():
|
||||
for m in mappings:
|
||||
src_path = os.path.join(source_dir, m['src'])
|
||||
dst_path = os.path.join(target_dir, m['dst'])
|
||||
|
||||
# 1. Delete destination lib and assets if exist
|
||||
for folder in ['lib', 'assets', 'secure_string_operations']:
|
||||
d_folder = os.path.join(dst_path, folder)
|
||||
if os.path.exists(d_folder):
|
||||
shutil.rmtree(d_folder)
|
||||
|
||||
# 2. Copy lib and assets
|
||||
for folder in ['lib', 'assets', 'secure_string_operations']:
|
||||
s_folder = os.path.join(src_path, folder)
|
||||
d_folder = os.path.join(dst_path, folder)
|
||||
if os.path.exists(s_folder):
|
||||
shutil.copytree(s_folder, d_folder)
|
||||
|
||||
# 3. Copy pubspec.yaml
|
||||
s_pubspec = os.path.join(src_path, "pubspec.yaml")
|
||||
d_pubspec = os.path.join(dst_path, "pubspec.yaml")
|
||||
if os.path.exists(s_pubspec):
|
||||
shutil.copy2(s_pubspec, d_pubspec)
|
||||
|
||||
# 4. Replace package name in pubspec.yaml
|
||||
if os.path.exists(d_pubspec):
|
||||
with open(d_pubspec, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
# replace name: old_pkg with name: new_pkg
|
||||
import re
|
||||
content = re.sub(rf'^name:\s*{m["old_pkg"]}\s*$', f'name: {m["new_pkg"]}', content, flags=re.MULTILINE)
|
||||
with open(d_pubspec, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
# 5. Replace imports in lib and test directories
|
||||
for root_folder in ['lib', 'test']:
|
||||
root_path = os.path.join(dst_path, root_folder)
|
||||
if not os.path.exists(root_path): continue
|
||||
|
||||
for root, dirs, files in os.walk(root_path):
|
||||
for file in files:
|
||||
if file.endswith('.dart'):
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
new_content = content.replace(f"package:{m['old_pkg']}/", f"package:{m['new_pkg']}/")
|
||||
if new_content != content:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
except Exception as e:
|
||||
print(f"Error reading {file_path}: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
copy_and_replace()
|
||||
print("Done")
|
||||
@@ -1,53 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SOURCE_DIR="/Users/hamzaaleghwairyeen/development/App"
|
||||
TARGET_DIR="/Users/hamzaaleghwairyeen/development/App/Siro"
|
||||
|
||||
declare -a mappings=(
|
||||
"Intaleq:siro_rider:Intaleq:siro_rider"
|
||||
"intaleq_driver:siro_driver:sefer_driver:siro_driver"
|
||||
"intaleq_admin:siro_admin:sefer_admin1:siro_admin"
|
||||
"service_intaleq:siro_service:service:siro_service"
|
||||
)
|
||||
|
||||
for mapping in "${mappings[@]}"; do
|
||||
IFS=":" read -r src dst old_pkg new_pkg <<< "$mapping"
|
||||
src_path="$SOURCE_DIR/$src"
|
||||
dst_path="$TARGET_DIR/$dst"
|
||||
|
||||
echo "Processing $dst..."
|
||||
|
||||
# 1. Delete destination lib and assets
|
||||
for folder in lib assets secure_string_operations; do
|
||||
if [ -d "$dst_path/$folder" ]; then
|
||||
rm -rf "$dst_path/$folder"
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. Copy lib and assets
|
||||
for folder in lib assets secure_string_operations; do
|
||||
if [ -d "$src_path/$folder" ]; then
|
||||
cp -R "$src_path/$folder" "$dst_path/"
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. Copy pubspec.yaml
|
||||
if [ -f "$src_path/pubspec.yaml" ]; then
|
||||
cp "$src_path/pubspec.yaml" "$dst_path/pubspec.yaml"
|
||||
fi
|
||||
|
||||
# 4. Replace package name in pubspec.yaml using perl
|
||||
if [ -f "$dst_path/pubspec.yaml" ]; then
|
||||
perl -pi -e "s/^name:\s*$old_pkg\s*$/name: $new_pkg/" "$dst_path/pubspec.yaml"
|
||||
fi
|
||||
|
||||
# 5. Replace imports using perl
|
||||
for root_folder in lib test; do
|
||||
if [ -d "$dst_path/$root_folder" ]; then
|
||||
find "$dst_path/$root_folder" -type f -name "*.dart" -exec perl -pi -e "s/package:$old_pkg\//package:$new_pkg\//g" {} +
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo "Done"
|
||||
126
marketing-pages/damascus_zones_map.html
Normal file
@@ -0,0 +1,126 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>خارطة التوسع الجغرافي - دمشق</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
<style>
|
||||
body { margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
||||
#map { height: 100vh; width: 100vw; }
|
||||
.legend {
|
||||
background: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 15px rgba(0,0,0,0.2);
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
}
|
||||
.legend h4 { margin: 0 0 10px 0; }
|
||||
.legend i {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script>
|
||||
// Initialize map centered on Damascus
|
||||
var map = L.map('map').setView([33.5138, 36.2765], 13);
|
||||
|
||||
// Add OpenStreetMap tiles
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
}).addTo(map);
|
||||
|
||||
// Define polygon styles
|
||||
var styleA = { color: 'green', fillColor: 'green', fillOpacity: 0.4, weight: 2 };
|
||||
var styleB = { color: 'blue', fillColor: 'blue', fillOpacity: 0.4, weight: 2 };
|
||||
var styleC = { color: 'yellow', fillColor: 'yellow', fillOpacity: 0.4, weight: 2 };
|
||||
var styleD = { color: 'red', fillColor: 'red', fillOpacity: 0.4, weight: 2 };
|
||||
|
||||
// Approximate Coordinates for Zones (These are illustrative representations)
|
||||
|
||||
// Zone A (Green): Mezzeh, Kafr Sousa, Malki (South-West / Central-West)
|
||||
var zoneA = [
|
||||
[33.5200, 36.2700], // Malki area
|
||||
[33.5150, 36.2850],
|
||||
[33.4900, 36.2850], // Kafr Sousa
|
||||
[33.4950, 36.2400], // Mezzeh
|
||||
[33.5100, 36.2400]
|
||||
];
|
||||
L.polygon(zoneA, styleA).addTo(map).bindPopup("<b>منطقة أ (خضراء)</b><br>المزة، كفرسوسة، المالكية<br>الأولوية الأولى (الأشهر 1-3)");
|
||||
|
||||
// Zone B (Blue): Abu Rummaneh, Muhajireen, Rawda, Jisr al-Abyad (Central / North-West)
|
||||
var zoneB = [
|
||||
[33.5350, 36.2650], // Muhajireen
|
||||
[33.5300, 36.2800],
|
||||
[33.5150, 36.2850], // Abu Rummaneh / Rawda
|
||||
[33.5200, 36.2700]
|
||||
];
|
||||
L.polygon(zoneB, styleB).addTo(map).bindPopup("<b>منطقة ب (زرقاء)</b><br>أبو رمانة، المهاجرين، الروضة، الجسر الأبيض<br>الأولوية الثانية (الأشهر 2-4)");
|
||||
|
||||
// Zone C (Yellow): Mezzeh Western Villas, Dummar, Rukn al-Din, Qassaa (North, East, far West)
|
||||
var zoneC1 = [ // Dummar / Western Villas
|
||||
[33.5500, 36.2200],
|
||||
[33.5400, 36.2500],
|
||||
[33.5100, 36.2400],
|
||||
[33.5100, 36.2100]
|
||||
];
|
||||
var zoneC2 = [ // Rukn al-Din / Qassaa
|
||||
[33.5400, 36.2800],
|
||||
[33.5450, 36.3100],
|
||||
[33.5150, 36.3200],
|
||||
[33.5100, 36.2850],
|
||||
[33.5300, 36.2800]
|
||||
];
|
||||
L.polygon(zoneC1, styleC).addTo(map).bindPopup("<b>منطقة ج (صفراء)</b><br>دمر، المزة فيلات غربية<br>الأولوية الثالثة (الأشهر 4-6)");
|
||||
L.polygon(zoneC2, styleC).addTo(map).bindPopup("<b>منطقة ج (صفراء)</b><br>ركن الدين، القصاع<br>الأولوية الثالثة (الأشهر 4-6)");
|
||||
|
||||
// Zone D (Red): Barzeh, Jaramana, Qudsaya, Darayya (Outskirts)
|
||||
var zoneD1 = [ // Barzeh
|
||||
[33.5600, 36.3000],
|
||||
[33.5600, 36.3300],
|
||||
[33.5400, 36.3300],
|
||||
[33.5400, 36.3000]
|
||||
];
|
||||
var zoneD2 = [ // Jaramana
|
||||
[33.5000, 36.3300],
|
||||
[33.5000, 36.3700],
|
||||
[33.4700, 36.3700],
|
||||
[33.4700, 36.3300]
|
||||
];
|
||||
var zoneD3 = [ // Darayya
|
||||
[33.4700, 36.2200],
|
||||
[33.4700, 36.2600],
|
||||
[33.4400, 36.2600],
|
||||
[33.4400, 36.2200]
|
||||
];
|
||||
L.polygon(zoneD1, styleD).addTo(map).bindPopup("<b>منطقة د (حمراء)</b><br>برزة<br>توسع مستقبلي (شهر 7+)");
|
||||
L.polygon(zoneD2, styleD).addTo(map).bindPopup("<b>منطقة د (حمراء)</b><br>جرمانا<br>توسع مستقبلي (شهر 7+)");
|
||||
L.polygon(zoneD3, styleD).addTo(map).bindPopup("<b>منطقة د (حمراء)</b><br>داريا<br>توسع مستقبلي (شهر 7+)");
|
||||
|
||||
// Add Legend
|
||||
var legend = L.control({position: 'bottomright'});
|
||||
legend.onAdd = function (map) {
|
||||
var div = L.DomUtil.create('div', 'legend');
|
||||
div.innerHTML += '<h4>استراتيجية التوسع - دمشق</h4>';
|
||||
div.innerHTML += '<i style="background: green"></i> منطقة أ (خضراء): المزة، كفرسوسة، المالكية<br>';
|
||||
div.innerHTML += '<i style="background: blue"></i> منطقة ب (زرقاء): أبو رمانة، المهاجرين<br>';
|
||||
div.innerHTML += '<i style="background: yellow"></i> منطقة ج (صفراء): دمر، ركن الدين، القصاع<br>';
|
||||
div.innerHTML += '<i style="background: red"></i> منطقة د (حمراء): الضواحي (جرمانا، برزة، داريا)<br>';
|
||||
return div;
|
||||
};
|
||||
legend.addTo(map);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
run_generation.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🚀 Generating SIRO Rider App Icons..."
|
||||
cd /Users/hamzaaleghwairyeen/development/App/Siro/siro_rider
|
||||
flutter clean
|
||||
flutter pub get
|
||||
dart run flutter_launcher_icons:main
|
||||
|
||||
echo "🚀 Generating SIRO Driver App Icons..."
|
||||
cd /Users/hamzaaleghwairyeen/development/App/Siro/siro_driver
|
||||
flutter clean
|
||||
flutter pub get
|
||||
dart run flutter_launcher_icons:main
|
||||
|
||||
echo "🎨 Generating Animated GIF for SIRO Rider & Driver..."
|
||||
cd /Users/hamzaaleghwairyeen/development/App/Siro
|
||||
python3 -m pip install Pillow --break-system-packages
|
||||
python3 /Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/a5945c2c-de5f-4478-bd3c-d2f1c3aeec6a/scratch/pulse_logo.py /Users/hamzaaleghwairyeen/development/App/Siro/siro_rider/assets/images/logo.png /Users/hamzaaleghwairyeen/development/App/Siro/siro_rider/assets/images/logo.gif
|
||||
cp /Users/hamzaaleghwairyeen/development/App/Siro/siro_rider/assets/images/logo.gif /Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/assets/images/logo.gif
|
||||
|
||||
echo "🍏 Fixing iOS App Icon names to match old format..."
|
||||
python3 /Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/a5945c2c-de5f-4478-bd3c-d2f1c3aeec6a/scratch/fix_ios_icons.py
|
||||
|
||||
echo "✅ All Done! Icons and Animated GIFs are ready."
|
||||
@@ -63,12 +63,21 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<!-- Deep Link: siroapp://... -->
|
||||
<!-- Deep Link: siromove://... -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="siroapp" />
|
||||
<data android:scheme="siromove" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- App Links for siromove.com -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https" android:host="siromove.com" android:pathPrefix="/" />
|
||||
<data android:scheme="https" android:host="www.siromove.com" android:pathPrefix="/" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Navigation Intents -->
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 561 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 444 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 722 B |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 290 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 6.4 KiB |
@@ -1 +1,158 @@
|
||||
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]}
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "40.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "60.png",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "29.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "58.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "87.png",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "80.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "120.png",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "57x57",
|
||||
"idiom": "iphone",
|
||||
"filename": "57.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "57x57",
|
||||
"idiom": "iphone",
|
||||
"filename": "114.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "120.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "180.png",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "20.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "40.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "29.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "58.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "40.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "80.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "50x50",
|
||||
"idiom": "ipad",
|
||||
"filename": "50.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "50x50",
|
||||
"idiom": "ipad",
|
||||
"filename": "100.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "72x72",
|
||||
"idiom": "ipad",
|
||||
"filename": "72.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "72x72",
|
||||
"idiom": "ipad",
|
||||
"filename": "144.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "76.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "152.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "83.5x83.5",
|
||||
"idiom": "ipad",
|
||||
"filename": "167.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "1024x1024",
|
||||
"idiom": "ios-marketing",
|
||||
"filename": "1024.png",
|
||||
"scale": "1x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,21 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>33</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>siromove.com</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>siromove</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>FlutterDeepLinkingEnabled</key>
|
||||
<true/>
|
||||
<key>FirebaseAppDelegateProxyEnabled</key>
|
||||
<string>NO</string>
|
||||
<key>GMSApiKey</key>
|
||||
|
||||
@@ -3,67 +3,34 @@ import 'package:get/get.dart';
|
||||
|
||||
class AppColor {
|
||||
// --- Core Brand Colors ---
|
||||
static const Color primaryColor = Color(0xFF1A2340); // Navy Blue
|
||||
static const Color secondaryColorStatic = Color(0xFF8C9CF8); // Periwinkle Blue
|
||||
static const Color accentColor = Color(0xFF8C9CF8);
|
||||
|
||||
/// **Primary Color:** The brand's signature blue.
|
||||
static const Color primaryColor = Color(0xFF1DA1F2);
|
||||
|
||||
/// **Text/Write Color:** Dynamic based on theme.
|
||||
static Color get writeColor =>
|
||||
Get.isDarkMode ? Colors.white : const Color(0xFF1A1A1A);
|
||||
|
||||
/// **Secondary Color:** Main background color, dynamic based on theme.
|
||||
static Color get secondaryColor =>
|
||||
Get.isDarkMode ? const Color(0xFF121212) : Colors.white;
|
||||
|
||||
/// **Surface Color:** For cards and elevated elements.
|
||||
static Color get surfaceColor =>
|
||||
Get.isDarkMode ? const Color(0xFF1E1E1E) : Colors.white;
|
||||
|
||||
/// **Card Color:** Specifically for card backgrounds.
|
||||
static Color get cardColor =>
|
||||
Get.isDarkMode ? const Color(0xFF1E1E1E) : Colors.white;
|
||||
|
||||
/// **Border Color:** Subtle borders for both modes.
|
||||
static Color get borderColor =>
|
||||
Get.isDarkMode ? Colors.white10 : Colors.black12;
|
||||
|
||||
/// **Accent Color:** Greyish accent.
|
||||
static const Color accentColor = Color.fromARGB(255, 148, 140, 141);
|
||||
// --- Dynamic Colors (Light / Dark Mode Support) ---
|
||||
static Color get writeColor => Get.isDarkMode ? Colors.white : const Color(0xFF0F172A); // Primary Text
|
||||
static Color get secondaryColor => Get.isDarkMode ? const Color(0xFF1E1E1E) : const Color(0xFFF8FAFC); // Background
|
||||
static Color get cardColor => Get.isDarkMode ? const Color(0xFF2C2C2E) : const Color(0xFFFFFFFF); // Card Background
|
||||
static Color get surfaceColor => cardColor; // Added back for backwards compatibility
|
||||
|
||||
// --- Neutral & Status Colors ---
|
||||
static Color get grayColor => Get.isDarkMode ? Colors.grey[400]! : const Color(0xFF64748B); // Secondary Text
|
||||
static Color get borderColor => Get.isDarkMode ? const Color(0xFF3A3A3C) : const Color(0xFFE2E8F0); // Border
|
||||
|
||||
/// **Grey Color:** Dynamic based on theme.
|
||||
static Color get grayColor =>
|
||||
Get.isDarkMode ? Colors.grey[400]! : const Color(0xFF8E8E93);
|
||||
|
||||
/// **Red Color (Error):** Clear red for alerts.
|
||||
static const Color redColor = Color(0xFFD32F2F);
|
||||
|
||||
/// **Green Color (Success):** Positive green.
|
||||
static const Color greenColor = Color(0xFF388E3C);
|
||||
|
||||
/// **Blue Color (Info):** Info text or success green variant.
|
||||
static const Color blueColor = Color(0xFF1DA1F2);
|
||||
|
||||
/// **Yellow Color (Warning):** Warm yellow.
|
||||
static const Color yellowColor = Color(0xFFFFA000);
|
||||
|
||||
// --- Tier & Social Colors ---
|
||||
static const Color redColor = Color(0xFFEF4444); // Error
|
||||
static const Color greenColor = Color(0xFF22C55E); // Success
|
||||
static const Color yellowColor = Color(0xFFF59E0B); // Warning
|
||||
|
||||
// --- Legacy / Maps Colors (Kept for compatibility) ---
|
||||
static const Color blueColor = Color(0xFF1A2340);
|
||||
static const Color gold = Color(0xFFFFD700);
|
||||
static const Color bronze = Color(0xFFCD7F32);
|
||||
static const Color goldenBronze = Color(0xFFB87333);
|
||||
static const Color twitterColor = Color(0xFF1DA1F2);
|
||||
|
||||
// --- Utility Colors ---
|
||||
|
||||
static Color get greyColor => grayColor;
|
||||
|
||||
static Color get cyanBlue => const Color(0xFF1DA1F2);
|
||||
static Color get cyanAccent => const Color(0xFF1DA1F2).withOpacity(0.12);
|
||||
static Color get deepPurpleAccent => const Color(0xFFCE1126).withOpacity(0.1);
|
||||
static const Color goldenBronze = Color(0xFFB87333);
|
||||
|
||||
static Color get cyanBlue => const Color(0xFF1A2340);
|
||||
static Color get cyanAccent => const Color(0xFF1A2340).withOpacity(0.12);
|
||||
static Color get deepPurpleAccent => const Color(0xFF8C9CF8).withOpacity(0.1);
|
||||
|
||||
// --- Theme Helpers ---
|
||||
static Brightness get brightness => Get.isDarkMode ? Brightness.dark : Brightness.light;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,13 @@ class FinanceDesignSystem {
|
||||
static Color get textMuted => Get.isDarkMode ? Colors.white38 : const Color(0xFFBDBDBD);
|
||||
static Color get borderColor => Get.isDarkMode ? Colors.white10 : Colors.grey.withOpacity(0.1);
|
||||
|
||||
// --- Shadows ---
|
||||
static BoxShadow get softShadow => BoxShadow(
|
||||
color: Colors.black.withOpacity(Get.isDarkMode ? 0.3 : 0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
);
|
||||
|
||||
// --- Gradients ---
|
||||
static LinearGradient get balanceGradient => LinearGradient(
|
||||
colors: Get.isDarkMode
|
||||
|
||||
@@ -7,6 +7,7 @@ class AppLink {
|
||||
static String serverPHP = box.read('serverPHP');
|
||||
|
||||
static String paymentServer = 'https://walletintaleq.intaleq.xyz/v1/main';
|
||||
static const String appDomain = 'siromove.com';
|
||||
|
||||
static String locationServer =
|
||||
'https://location.intaleq.xyz/intaleq/ride/location';
|
||||
@@ -337,6 +338,11 @@ class AppLink {
|
||||
|
||||
//===================Auth============
|
||||
|
||||
static String getUnifiedCode = "$ride/invitor/get_unified_code.php";
|
||||
static String addUnifiedInvite = "$ride/invitor/add_unified_invite.php";
|
||||
static String claimDriverReward = "$ride/invitor/claim_driver_reward.php";
|
||||
static String getDriverReferrals = "$ride/invitor/get_driver_referrals.php";
|
||||
|
||||
static String addInviteDriver = "$ride/invitor/add.php";
|
||||
static String addInvitationPassenger =
|
||||
"$ride/invitor/addInvitationPassenger.php";
|
||||
|
||||
@@ -584,6 +584,8 @@ Download the Intaleq app now and enjoy your ride!
|
||||
'${"The period of this code is 24 hours".tr}\n\n'
|
||||
'${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n'
|
||||
'_*${d['message']['inviteCode'].toString()}*_\n\n'
|
||||
'${"Quick Invite Link:".tr}\n'
|
||||
'https://${AppLink.appDomain}/?inviteCode=${d['message']['inviteCode'].toString()}\n\n'
|
||||
'${"Install our app:".tr}\n'
|
||||
'*Android:* https://play.google.com/store/apps/details?id=com.Intaleq.intaleq\n\n\n'
|
||||
'*iOS:* https://apps.apple.com/st/app/intaleq-rider/id6748075179';
|
||||
|
||||
103
siro_driver/lib/controller/home/invites_rewards_controller.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:siro_driver/constant/links.dart';
|
||||
import 'package:siro_driver/controller/functions/crud.dart';
|
||||
import 'package:siro_driver/views/widgets/error_snakbar.dart';
|
||||
|
||||
class InvitesRewardsController extends GetxController {
|
||||
bool isLoading = false;
|
||||
String? referralCode;
|
||||
int totalInvitedDrivers = 0;
|
||||
int totalInvitedPassengers = 0;
|
||||
List<dynamic> referrals = [];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
getReferralStats();
|
||||
}
|
||||
|
||||
Future<void> getReferralStats() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
var res = await CRUD().get(link: AppLink.getDriverReferrals);
|
||||
|
||||
if (res != 'failure' && res != 'token_expired' && res != 'no_internet') {
|
||||
try {
|
||||
var jsonData = jsonDecode(res);
|
||||
if (jsonData['status'] == 'success') {
|
||||
var data = jsonData['message'];
|
||||
referralCode = data['referral_code'];
|
||||
totalInvitedDrivers = data['total_invited_drivers'] ?? 0;
|
||||
totalInvitedPassengers = data['total_invited_passengers'] ?? 0;
|
||||
referrals = data['referrals'] ?? [];
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error parsing referral stats: $e');
|
||||
}
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> claimReward(int referralId, String claimType) async {
|
||||
Get.dialog(const Center(child: CircularProgressIndicator()), barrierDismissible: false);
|
||||
|
||||
var res = await CRUD().post(
|
||||
link: AppLink.claimDriverReward,
|
||||
payload: {
|
||||
'referral_id': referralId.toString(),
|
||||
'claim_type': claimType, // 'wallet' or 'cash'
|
||||
},
|
||||
);
|
||||
|
||||
Get.back(); // close dialog
|
||||
|
||||
if (res != 'failure' && res != 'token_expired' && res != 'no_internet') {
|
||||
try {
|
||||
var jsonData = jsonDecode(res);
|
||||
if (jsonData['status'] == 'success') {
|
||||
mySnackbarSuccess('Reward claimed successfully!'.tr);
|
||||
await getReferralStats(); // refresh list
|
||||
} else {
|
||||
mySnackeBarError(jsonData['error'] ?? 'Failed to claim reward'.tr);
|
||||
}
|
||||
} catch (e) {
|
||||
mySnackeBarError('Failed to claim reward'.tr);
|
||||
}
|
||||
} else {
|
||||
mySnackeBarError('Connection error'.tr);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> claimUnifiedReward(int referralId) async {
|
||||
// Show dialog to choose wallet or cash
|
||||
Get.defaultDialog(
|
||||
title: "Choose Claim Method".tr,
|
||||
content: Text("How would you like to receive your reward?".tr),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
claimReward(referralId, 'wallet');
|
||||
},
|
||||
child: Text("Wallet".tr),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
claimReward(referralId, 'cash');
|
||||
},
|
||||
child: Text("Cash".tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: Text("Cancel".tr, style: TextStyle(color: Colors.red)),
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,11 @@ import '../../../constant/colors.dart';
|
||||
import '../../../controller/auth/captin/invit_controller.dart';
|
||||
import '../../../controller/functions/encrypt_decrypt.dart';
|
||||
import '../../../main.dart';
|
||||
import '../../../controller/home/invites_rewards_controller.dart';
|
||||
|
||||
class InviteScreen extends StatelessWidget {
|
||||
final InviteController controller = Get.put(InviteController());
|
||||
final InvitesRewardsController rewardsController = Get.put(InvitesRewardsController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -111,6 +113,8 @@ class InviteScreen extends StatelessWidget {
|
||||
_buildActionButtons(),
|
||||
const SizedBox(height: 20),
|
||||
_buildInvitationsList(context),
|
||||
const SizedBox(height: 20),
|
||||
_buildUnifiedRewardsList(isDriver: true),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -146,6 +150,8 @@ class InviteScreen extends StatelessWidget {
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(height: 20),
|
||||
_buildInvitationsListPassengers(context),
|
||||
const SizedBox(height: 20),
|
||||
_buildUnifiedRewardsList(isDriver: false),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -324,9 +330,12 @@ class InviteScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildInvitationsList(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: Get.height * .4,
|
||||
child: controller.driverInvitationData.isEmpty
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Invitations Sent".tr, style: const TextStyle(fontSize: 17, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 10),
|
||||
controller.driverInvitationData.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No invitation found yet!".tr,
|
||||
@@ -337,18 +346,24 @@ class InviteScreen extends StatelessWidget {
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: controller.driverInvitationData.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildInvitationItem(context, index);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInvitationsListPassengers(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: Get.height * .4,
|
||||
child: controller.driverInvitationDataToPassengers.isEmpty
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Invitations Sent".tr, style: const TextStyle(fontSize: 17, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 10),
|
||||
controller.driverInvitationDataToPassengers.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No invitation found yet!".tr,
|
||||
@@ -359,11 +374,14 @@ class InviteScreen extends StatelessWidget {
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: controller.driverInvitationDataToPassengers.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildInvitationItemPassengers(context, index);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -636,4 +654,76 @@ class InviteScreen extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUnifiedRewardsList({required bool isDriver}) {
|
||||
return GetBuilder<InvitesRewardsController>(
|
||||
builder: (rewardsController) {
|
||||
if (rewardsController.isLoading) {
|
||||
return const Center(child: CupertinoActivityIndicator());
|
||||
}
|
||||
|
||||
var filteredList = rewardsController.referrals.where((ref) =>
|
||||
isDriver ? ref['invited_user_type'] == 'driver' : ref['invited_user_type'] == 'passenger'
|
||||
).toList();
|
||||
|
||||
if (filteredList.isEmpty) {
|
||||
return const SizedBox(); // Hide if no valid rewards
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Reward Status".tr, style: const TextStyle(fontSize: 17, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 10),
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
var ref = filteredList[index];
|
||||
int trips = ref['trip_count'] ?? 0;
|
||||
int target = ref['target_trips'] ?? 1;
|
||||
bool canClaim = ref['can_claim'] ?? false;
|
||||
bool isClaimed = ref['is_reward_claimed'] == 1;
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: CupertinoColors.systemGrey6,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(isDriver ? "Driver Referral".tr : "Passenger Referral".tr, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 4),
|
||||
Text("Trips: $trips / $target".tr, style: const TextStyle(color: CupertinoColors.secondaryLabel, fontSize: 13)),
|
||||
if (isClaimed)
|
||||
Text("Reward Claimed".tr, style: const TextStyle(color: CupertinoColors.activeGreen, fontSize: 12, fontWeight: FontWeight.bold))
|
||||
else if (!canClaim)
|
||||
Text("Waiting for trips".tr, style: const TextStyle(color: CupertinoColors.systemOrange, fontSize: 12))
|
||||
],
|
||||
),
|
||||
),
|
||||
if (canClaim && !isClaimed)
|
||||
CupertinoButton(
|
||||
color: AppColor.blueColor,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
onPressed: () => rewardsController.claimUnifiedReward(ref['id']),
|
||||
child: Text("Claim".tr, style: const TextStyle(color: Colors.white, fontSize: 14)),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:siro_driver/views/widgets/error_snakbar.dart';
|
||||
import 'package:siro_driver/views/widgets/my_textField.dart';
|
||||
import 'package:siro_driver/views/widgets/elevated_btn.dart'; // Checked import
|
||||
@@ -7,6 +8,7 @@ import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
|
||||
import '../../../../constant/box_name.dart';
|
||||
import '../../../../constant/colors.dart';
|
||||
import '../../../../constant/links.dart';
|
||||
import '../../../../constant/style.dart';
|
||||
import '../../../../controller/firebase/notification_service.dart';
|
||||
import '../../../../controller/functions/launch.dart';
|
||||
@@ -50,6 +52,16 @@ class SosConnect extends StatelessWidget {
|
||||
isPulsing: true,
|
||||
onTap: () => _handleSosCall(controller),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// === Quick Invite Button ===
|
||||
_buildModernActionButton(
|
||||
icon: Icons.qr_code_rounded,
|
||||
color: Colors.white,
|
||||
bgColor: AppColor.blueColor,
|
||||
tooltip: 'Quick Invite',
|
||||
isPulsing: false,
|
||||
onTap: () => _showQuickInviteDialog(controller),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -128,4 +140,70 @@ class SosConnect extends StatelessWidget {
|
||||
launchCommunication('phone', box.read(BoxName.sosPhoneDriver), '');
|
||||
}
|
||||
}
|
||||
|
||||
void _showQuickInviteDialog(MapDriverController controller) {
|
||||
// In a real scenario, this code would be fetched from the backend (ReferralController)
|
||||
// For now we will use a generated code or driverId. We should use the one from ReferralController
|
||||
// But since we are accessing it globally, we can just use the driverID + 123 for now until it's linked
|
||||
String driverId = box.read(BoxName.driverID).toString();
|
||||
String inviteCode = "SR$driverId"; // Placeholder code
|
||||
String deepLink = "https://${AppLink.appDomain}/invite?ref=$inviteCode";
|
||||
|
||||
Get.defaultDialog(
|
||||
title: "Quick Invite".tr,
|
||||
titleStyle: AppStyle.title.copyWith(fontWeight: FontWeight.bold),
|
||||
content: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Let the passenger scan this code to sign up".tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: QrImageView(
|
||||
data: deepLink,
|
||||
version: QrVersions.auto,
|
||||
size: 200.0,
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.blueColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColor.blueColor.withOpacity(0.3)),
|
||||
),
|
||||
child: Text(
|
||||
inviteCode,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: AppColor.blueColor,
|
||||
letterSpacing: 4,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Done'.tr,
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 444 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 563 B |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 881 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.1 KiB |
@@ -208,6 +208,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.13.1"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -717,6 +725,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_launcher_icons
|
||||
sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.14.4"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -1780,6 +1796,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: qr
|
||||
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
qr_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: qr_flutter
|
||||
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
quick_actions:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -41,6 +41,7 @@ dependencies:
|
||||
lottie: ^3.3.1
|
||||
shimmer: ^3.0.0
|
||||
slide_to_act: ^2.0.2
|
||||
qr_flutter: ^4.1.0
|
||||
|
||||
# Services & Hardware
|
||||
battery_plus: ^7.0.0
|
||||
@@ -99,6 +100,7 @@ dev_dependencies:
|
||||
flutter_lints: ^6.0.0
|
||||
envied_generator: ^1.0.0
|
||||
build_runner: ^2.4.6
|
||||
flutter_launcher_icons: ^0.14.4
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: "launcher_icon"
|
||||
|
||||
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 563 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -55,8 +55,8 @@
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https" android:host="siroapp.com" android:pathPrefix="/" />
|
||||
<data android:scheme="https" android:host="www.siroapp.com"
|
||||
<data android:scheme="https" android:host="siromove.com" android:pathPrefix="/" />
|
||||
<data android:scheme="https" android:host="www.siromove.com"
|
||||
android:pathPrefix="/" />
|
||||
</intent-filter>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 433 KiB After Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 4.1 MiB |
@@ -898,9 +898,9 @@
|
||||
C663DBE82F50907200D79908 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
@@ -944,9 +944,9 @@
|
||||
C663DBE92F50907200D79908 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
@@ -987,9 +987,9 @@
|
||||
C663DBEA2F50907200D79908 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 936 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 633 B |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 795 B |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 258 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.4 KiB |