Update: 2026-06-10 02:44:54

This commit is contained in:
Hamza-Ayed
2026-06-10 02:44:55 +03:00
parent 9bc7a31c94
commit a0473a8b0f
134 changed files with 1706 additions and 544 deletions

View File

@@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 KiB

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 4.1 MiB

View File

@@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -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"
}
}

View File

@@ -28,11 +28,11 @@
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>siroapp.com</string>
<string>siromove.com</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.1086900987150-9jv4oa8l3t23d54lrf27c1d22tbt9i6d</string>
<string>siroapp</string>
<string>siromove</string>
</array>
</dict>
</array>

View File

@@ -51,6 +51,7 @@ class BoxName {
static const String package = "package";
static const String isInstall = "isInstall";
static const String isGiftToken = "isGiftToken";
static const String isClaim = "isClaim";
static const String inviteCode = "inviteCode";
static const String phoneWallet = "phoneWallet";
static const String phoneDriver = "phoneDriver";

View File

@@ -4,63 +4,31 @@ import 'package:get/get.dart';
/// The palette is professionally designed to be modern, cohesive, and culturally
/// relevant, inspired by the Syrian flag and the app's brand identity.
class AppColor {
// --- Core Brand Colors (Inspired by the Syrian Flag) ---
// --- 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 Twitter Blue representing trust and modern communication.
/// Ideal for app bars, primary buttons, and major UI elements.
static const Color primaryColor = Color(0xFF1DA1F2);
/// **Text/Write Color:** A very dark, near-black color for main text.
/// It's softer on the eyes than pure black, improving readability.
/// The variable name `writeColor` is kept as requested.
static Color get writeColor => Get.isDarkMode ? Colors.white : const Color(0xFF1A1A1A);
/// **Secondary Color:** Pure white, used for backgrounds to create a clean
/// and spacious look, ensuring content stands out.
static Color get secondaryColor => Get.isDarkMode ? const Color(0xFF1E1E1E) : Colors.white;
/// **Accent Color:** A vibrant, energetic red from the Syrian flag.
/// Perfect for calls-to-action, highlights, icons, and notifications.
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
// --- 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:** A neutral grey for secondary text, borders, dividers,
/// and disabled states.
static Color get grayColor => Get.isDarkMode ? Colors.grey[400]! : const Color(0xFF8E8E93);
static const Color redColor = Color(0xFFEF4444); // Error
static const Color greenColor = Color(0xFF22C55E); // Success
static const Color yellowColor = Color(0xFFF59E0B); // Warning
/// **Red Color (Error):** A clear, attention-grabbing red for error messages and alerts.
static const Color redColor = Color(0xFFD32F2F);
/// **Green Color (Success):** A positive green for success messages and confirmations.
static const Color greenColor = Color(0xFF388E3C);
/// **Blue Color (Info):** A standard blue for informational text, links, or icons.
static const Color blueColor = Color(0xFF108942);
/// **Yellow Color (Warning):** A warm yellow for warning messages or important highlights.
static const Color yellowColor = Color(0xFFFFA000);
// --- Tier & Social Colors ---
/// **Gold Tier:** A bright gold for premium features, user ranks, or rewards.
// --- Legacy / Maps Colors (Kept for compatibility) ---
static const Color blueColor = Color(0xFF1A2340);
static const Color gold = Color(0xFFFFD700);
/// **Bronze Tiers:** Classic bronze colors for other user tiers or levels.
static const Color bronze = Color(0xFFCD7F32);
static const Color goldenBronze = Color(0xFFB87333); // Kept from original
/// **Twitter/X Color:** The official brand color for social login buttons.
/// **Twitter Blue:** The brand's signature blue color used for the drawer,
/// menu icons, and secondary actions (formerly Cyan Blue).
static Color get cyanBlue => const Color(0xFF1DA1F2);
/// **Blue Accent:** A softer, translucent version of the brand blue.
static Color get cyanAccent => const Color(0xFF1DA1F2).withOpacity(0.12);
// --- Utility Colors ---
/// **Accent Tint:** A transparent version of the red accent color.
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);
}

View File

@@ -2,6 +2,7 @@ import 'package:siro_rider/constant/box_name.dart';
import 'package:siro_rider/main.dart';
class AppLink {
static const String appDomain = 'siromove.com';
///https://walletintaleq.intaleq.xyz/v1/main
static String paymentServer = 'https://walletintaleq.intaleq.xyz/v2/main';
@@ -177,7 +178,9 @@ class AppLink {
static String deleteNotificationCaptain =
"$server/ride/notificationCaptain/delete.php";
//-----------------invitor------------------
static String getUnifiedCode = "$server/ride/invitor/get_unified_code.php";
static String addUnifiedInvite = "$server/ride/invitor/add_unified_invite.php";
static String getPassengerReferrals = "$server/ride/invitor/get_passenger_referrals.php";
static String addInviteDriver = "$server/ride/invitor/add.php";
static String addInvitationPassenger =
"$server/ride/invitor/addInvitationPassenger.php";

View File

@@ -308,6 +308,7 @@ class LoginController extends GetxController {
box.write(BoxName.validity, data['validity']);
box.write(BoxName.isInstall, data['isInstall'] ?? 'none');
box.write(BoxName.isGiftToken, data['isGiftToken'] ?? 'none');
box.write(BoxName.isClaim, data['isClaim'] ?? '0');
if (data['inviteCode'] != null) {
box.write(BoxName.inviteCode, data['inviteCode'].toString());
}
@@ -384,6 +385,15 @@ class LoginController extends GetxController {
"inviteCode": invite,
"passengerID": passengerID,
});
// سجل الدعوة أيضاً في النظام الموحد الجديد
await CRUD().post(link: AppLink.addUnifiedInvite, payload: {
"inviter_code": invite,
});
// تحديث الحالة محلياً لضمان عدم إرسال الطلب مرة أخرى
box.write(BoxName.isInstall, '1');
await Get.defaultDialog(
title: 'Invitation Used'.tr,
middleText: "Your invite code was successfully applied!".tr,

View File

@@ -2,6 +2,8 @@ import 'package:siro_rider/print.dart';
import 'dart:async';
import 'package:app_links/app_links.dart';
import 'package:get/get.dart';
import '../../main.dart';
import 'profile/invites_rewards_controller.dart';
class DeepLinkController extends GetxController {
final _appLinks = AppLinks();
@@ -21,6 +23,7 @@ class DeepLinkController extends GetxController {
_linkSubscription = _appLinks.uriLinkStream.listen((uri) {
Log.print('🔗 Received deep link (Stream): $uri');
rawDeepLink.value = uri.toString();
_processInviteCode(uri);
});
// الاستماع للروابط إذا كان التطبيق مغلقاً تماماً (Cold Start)
@@ -29,15 +32,37 @@ class DeepLinkController extends GetxController {
if (initialUri != null) {
Log.print('🔗 Received initial deep link (Cold Start): $initialUri');
rawDeepLink.value = initialUri.toString();
_processInviteCode(initialUri);
}
} catch (e) {
Log.print('Error getting initial link: $e');
}
}
void _processInviteCode(Uri uri) {
if (uri.queryParameters.containsKey('inviteCode')) {
String? inviteCode = uri.queryParameters['inviteCode'];
if (inviteCode != null && inviteCode.isNotEmpty) {
// دائماً نخزن الكود حتى لو لم يكن مسجلاً، ليتم استخدامه بعد التسجيل
box.write('inviteCode', inviteCode);
// إذا كان المستخدم مسجل دخول (يمتلك JWT)، نربط الدعوة فوراً
if (box.read('jwt') != null) {
try {
var rewardsController = Get.find<InvitesRewardsController>();
rewardsController.linkInviteCode(inviteCode);
} catch (e) {
var rewardsController = Get.put(InvitesRewardsController());
rewardsController.linkInviteCode(inviteCode);
}
}
}
}
}
@override
void onClose() {
_linkSubscription?.cancel();
super.onClose();
}
}
}

View File

@@ -0,0 +1,94 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_rider/constant/links.dart';
import 'package:siro_rider/controller/functions/crud.dart';
class InvitesRewardsController extends GetxController {
bool isLoading = false;
String? referralCode;
int totalInvitedDrivers = 0;
int totalInvitedPassengers = 0;
List<dynamic> referrals = [];
@override
void onInit() {
super.onInit();
fetchPassengerReferrals();
}
Future<void> fetchPassengerReferrals() async {
isLoading = true;
update();
try {
var response = await CRUD().post(
link: AppLink.getPassengerReferrals,
payload: {} // Token is automatically handled by CRUD()
);
if (response != 'failure') {
var data = jsonDecode(response);
if (data['status'] == 'success') {
referralCode = data['message']['referral_code'];
totalInvitedDrivers = data['message']['total_invited_drivers'] ?? 0;
totalInvitedPassengers = data['message']['total_invited_passengers'] ?? 0;
referrals = data['message']['referrals'] ?? [];
} else {
referrals = [];
}
}
} catch (e) {
print("Error fetching passenger referrals: $e");
}
isLoading = false;
update();
}
Future<void> processScannedQRCode(String code) async {
if (code.contains('inviteCode=')) {
Uri uri = Uri.parse(code);
String? inviteCode = uri.queryParameters['inviteCode'];
if (inviteCode != null && inviteCode.isNotEmpty) {
await linkInviteCode(inviteCode);
} else {
Get.snackbar("Error".tr, "Invalid QR Code".tr);
}
} else if (code.length >= 4 && code.length <= 15) {
await linkInviteCode(code);
} else {
Get.snackbar("Error".tr, "Invalid QR Code format".tr);
}
}
Future<void> linkInviteCode(String inviteCode) async {
Get.dialog(const Center(child: CircularProgressIndicator()), barrierDismissible: false);
try {
var response = await CRUD().post(
link: AppLink.addUnifiedInvite,
payload: {
"inviter_code": inviteCode,
}
);
Get.back(); // close loading
if (response != 'failure') {
var data = jsonDecode(response);
if (data['status'] == 'success') {
Get.snackbar("Success".tr, "You have been successfully referred!".tr, backgroundColor: Colors.green, colorText: Colors.white);
} else {
Get.snackbar("Notice".tr, data['message'] ?? "Could not add invite".tr);
}
} else {
Get.snackbar("Error".tr, "Network error occurred".tr);
}
} catch (e) {
Get.back(); // close loading
Get.snackbar("Error".tr, "Network error occurred".tr);
}
}
}

View File

@@ -0,0 +1,67 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:siro_rider/constant/colors.dart';
import 'package:siro_rider/controller/home/profile/invites_rewards_controller.dart';
class QRScannerPage extends StatefulWidget {
@override
_QRScannerPageState createState() => _QRScannerPageState();
}
class _QRScannerPageState extends State<QRScannerPage> {
final InvitesRewardsController controller = Get.find<InvitesRewardsController>();
bool _isScanned = false;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.black,
iconTheme: const IconThemeData(color: Colors.white),
title: Text("Scan QR Code".tr, style: const TextStyle(color: Colors.white)),
),
body: Stack(
children: [
MobileScanner(
onDetect: (capture) {
if (_isScanned) return;
final List<Barcode> barcodes = capture.barcodes;
for (final barcode in barcodes) {
if (barcode.rawValue != null) {
setState(() => _isScanned = true);
Get.back(); // close scanner page
controller.processScannedQRCode(barcode.rawValue!);
break;
}
}
},
),
Center(
child: Container(
width: 250,
height: 250,
decoration: BoxDecoration(
border: Border.all(color: AppColor.primaryColor, width: 3),
borderRadius: BorderRadius.circular(12),
),
),
),
Positioned(
bottom: 50,
left: 0,
right: 0,
child: Center(
child: Text(
"Align QR Code within the frame".tr,
style: const TextStyle(color: Colors.white, fontSize: 16),
),
),
),
],
),
);
}
}

View File

@@ -3,12 +3,18 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constant/colors.dart';
import '../../../constant/links.dart';
import '../../../constant/style.dart';
import '../../../controller/home/profile/invit_controller.dart';
import '../../../controller/home/profile/invites_rewards_controller.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'qr_scanner_page.dart';
import '../../../print.dart';
class ShareAppPage extends StatelessWidget {
final InviteController controller = Get.put(InviteController());
final InvitesRewardsController rewardsController =
Get.put(InvitesRewardsController());
@override
Widget build(BuildContext context) {
@@ -42,6 +48,12 @@ class ShareAppPage extends StatelessWidget {
},
),
),
floatingActionButton: FloatingActionButton.extended(
backgroundColor: AppColor.primaryColor,
onPressed: () => Get.to(() => QRScannerPage()),
icon: const Icon(CupertinoIcons.qrcode_viewfinder, color: Colors.white),
label: Text("Scan QR".tr, style: const TextStyle(color: Colors.white)),
),
);
}
@@ -49,6 +61,8 @@ class ShareAppPage extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildQRCodeSection(),
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
@@ -74,8 +88,11 @@ class ShareAppPage extends StatelessWidget {
const SizedBox(height: 20),
_buildActionButtonsPassengers(),
const SizedBox(height: 20),
const SizedBox(height: 20),
_buildInvitationsListPassengers(context),
const SizedBox(height: 20),
_buildUnifiedRewardsList(),
const SizedBox(
height: 60), // Add padding for the floating action button
],
);
}
@@ -226,24 +243,35 @@ class ShareAppPage extends StatelessWidget {
}
Widget _buildInvitationsListPassengers(BuildContext context) {
return SizedBox(
height: Get.height * .4,
child: controller.driverInvitationDataToPassengers.isEmpty
? Center(
child: Text(
"No invitation found yet!".tr,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 17,
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Invitations Sent".tr,
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
color: AppColor.writeColor,
)),
const SizedBox(height: 10),
controller.driverInvitationDataToPassengers.isEmpty
? Center(
child: Text(
"No invitation found yet!".tr,
style: TextStyle(
color: AppColor.grayColor,
fontSize: 17,
),
),
)
: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.driverInvitationDataToPassengers.length,
itemBuilder: (context, index) {
return _buildInvitationItemPassengers(context, index);
},
),
)
: ListView.builder(
itemCount: controller.driverInvitationDataToPassengers.length,
itemBuilder: (context, index) {
return _buildInvitationItemPassengers(context, index);
},
),
],
);
}
@@ -574,4 +602,136 @@ class ShareAppPage extends StatelessWidget {
// ),
// );
}
Widget _buildQRCodeSection() {
return GetBuilder<InvitesRewardsController>(
builder: (rewardsController) {
if (rewardsController.isLoading) {
return const Center(child: CupertinoActivityIndicator());
}
String qrData =
'https://${AppLink.appDomain}/?inviteCode=${rewardsController.referralCode ?? ''}';
return Center(
child: Column(
children: [
Text("Your QR Code".tr,
style: const TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
if (rewardsController.referralCode != null)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: QrImageView(
data: qrData,
version: QrVersions.auto,
size: 200.0,
backgroundColor: Colors.white,
),
),
const SizedBox(height: 10),
if (rewardsController.referralCode != null)
Text(
rewardsController.referralCode!,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
letterSpacing: 2),
),
],
),
);
},
);
}
Widget _buildUnifiedRewardsList() {
return GetBuilder<InvitesRewardsController>(
builder: (rewardsController) {
if (rewardsController.isLoading) {
return const Center(child: CupertinoActivityIndicator());
}
var filteredList = rewardsController.referrals;
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(
ref['invited_user_type'] == 'driver'
? "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))
else
Text("Reward Earned".tr,
style: const TextStyle(
color: CupertinoColors.activeGreen,
fontSize: 12,
fontWeight: FontWeight.bold))
],
),
),
],
),
);
},
),
],
);
},
);
}
}

View File

@@ -23,6 +23,7 @@ import google_sign_in_ios
import just_audio
import local_auth_darwin
import location
import mobile_scanner
import package_info_plus
import record_macos
import share_plus
@@ -52,6 +53,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))

View File

@@ -1,68 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
"info": {
"version": 1,
"author": "xcode"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
"images": [
{
"size": "16x16",
"idiom": "mac",
"filename": "app_icon_16.png",
"scale": "1x"
},
{
"size": "16x16",
"idiom": "mac",
"filename": "app_icon_32.png",
"scale": "2x"
},
{
"size": "32x32",
"idiom": "mac",
"filename": "app_icon_32.png",
"scale": "1x"
},
{
"size": "32x32",
"idiom": "mac",
"filename": "app_icon_64.png",
"scale": "2x"
},
{
"size": "128x128",
"idiom": "mac",
"filename": "app_icon_128.png",
"scale": "1x"
},
{
"size": "128x128",
"idiom": "mac",
"filename": "app_icon_256.png",
"scale": "2x"
},
{
"size": "256x256",
"idiom": "mac",
"filename": "app_icon_256.png",
"scale": "1x"
},
{
"size": "256x256",
"idiom": "mac",
"filename": "app_icon_512.png",
"scale": "2x"
},
{
"size": "512x512",
"idiom": "mac",
"filename": "app_icon_512.png",
"scale": "1x"
},
{
"size": "512x512",
"idiom": "mac",
"filename": "app_icon_1024.png",
"scale": "2x"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -1397,6 +1397,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
mobile_scanner:
dependency: "direct main"
description:
name: mobile_scanner
sha256: d234581c090526676fd8fab4ada92f35c6746e3fb4f05a399665d75a399fb760
url: "https://pub.dev"
source: hosted
version: "5.2.3"
nested:
dependency: transitive
description:
@@ -1637,6 +1645,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:

View File

@@ -84,6 +84,8 @@ dependencies:
app_links: ^7.0.0
intaleq_maps: ^2.2.0
socket_io_client: 1.0.2
mobile_scanner: ^5.2.3
qr_flutter: ^4.1.0
# home_widget: ^0.7.0+1
dev_dependencies:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB