Update codebase

This commit is contained in:
Hamza-Ayed
2026-08-05 14:12:41 +03:00
parent 58928cd258
commit 95e2e4f35d
51 changed files with 3141 additions and 390 deletions
+25 -10
View File
@@ -23,11 +23,32 @@ class BuildConfig {
static const String logoAsset = 'assets/images/logo.png';
static const String splashLogoAsset = 'assets/images/splash_logo.png';
/// روابط خارجية لكل مستأجر — تُولَّد مع بقية الملف (N3).
static const String storeUrl = String.fromEnvironment(
'STORE_URL',
defaultValue: 'https://tripz.app',
/// روابط المتاجر الأربعة — **صفحات المتجر الحقيقية المنشورة**، أعطاها
/// المالك 2026-08-05. لا تُستعمل مباشرةً: `StoreLinks` هو من يختار الرابط
/// حسب المنصّة والدور، لأن «قيّم التطبيق» على آيفون سائق ≠ نفس الرابط على
/// أندرويد راكب.
///
/// المعرّفات تطابق هوية النشر المقفلة: `com.mobileapp.store.ride` للراكب
/// و`com.sefer_driver` للسائق.
static const String riderIosUrl = String.fromEnvironment(
'RIDER_IOS_URL',
defaultValue: 'https://apps.apple.com/eg/app/tripz-rider/id6458734951',
);
static const String driverIosUrl = String.fromEnvironment(
'DRIVER_IOS_URL',
defaultValue: 'https://apps.apple.com/eg/app/tripz-driver/id6502189302',
);
static const String riderAndroidUrl = String.fromEnvironment(
'RIDER_ANDROID_URL',
defaultValue:
'https://play.google.com/store/apps/details?id=com.mobileapp.store.ride',
);
static const String driverAndroidUrl = String.fromEnvironment(
'DRIVER_ANDROID_URL',
defaultValue:
'https://play.google.com/store/apps/details?id=com.sefer_driver',
);
static const String privacyUrl = String.fromEnvironment(
'PRIVACY_URL',
defaultValue: 'https://tripz.app/privacy',
@@ -38,12 +59,6 @@ class BuildConfig {
'SUPPORT_PHONE',
defaultValue: '962790000000',
);
/// رابط تطبيق الطرف الآخر — السائق يدعو ركّاباً والعكس.
static const String driverAppUrl = String.fromEnvironment(
'RIDER_APP_URL',
defaultValue: 'https://tripz.app',
);
}
/// أعلام الاستحقاقات (docs/23 §5). **`const` إجبارياً** كي يُحذف كود الميزة
+1
View File
@@ -140,6 +140,7 @@ Future<void> setupInjector() async {
trips: sl(),
location: sl(),
realtime: sl(),
maps: sl(),
));
}
+19 -1
View File
@@ -65,6 +65,12 @@
"settingsLanguage": "اللغة",
"settingsLanguageArabic": "العربية",
"settingsLanguageEnglish": "English",
"settingsSectionGeneral": "عام",
"settingsSectionSupport": "الدعم والمعلومات",
"settingsSupportLead": "أسئلة شائعة وطرق التواصل",
"settingsShareLead": "شارك التطبيق مع أصدقائك",
"paymentCash": "نقداً",
"paymentWallet": "من المحفظة",
"rideWhereTo": "إلى أين؟",
"rideOrigin": "من",
"rideDestination": "إلى",
@@ -224,12 +230,24 @@
"menuNotifications": "الإشعارات",
"menuPrivacy": "سياسة الخصوصية",
"menuRateApp": "قيّم التطبيق",
"shareMessage": "انضم لـTripz كسائق — استعمل كودي {code}",
"shareMessage": "انضم لـTripz كسائق — استعمل كودي {code}\n{link}",
"shareMessagePlain": "انضم لـTripz كسائق\n{link}",
"menuRiderApp": "تطبيق الراكب",
"menuDriverApp": "تطبيق الراكب",
"@shareMessage": {
"placeholders": {
"code": {
"type": "String"
},
"link": {
"type": "String"
}
}
},
"@shareMessagePlain": {
"placeholders": {
"link": {
"type": "String"
}
}
},
+19 -1
View File
@@ -65,6 +65,12 @@
"settingsLanguage": "Language",
"settingsLanguageArabic": "العربية",
"settingsLanguageEnglish": "English",
"settingsSectionGeneral": "General",
"settingsSectionSupport": "Support & info",
"settingsSupportLead": "FAQ and ways to reach us",
"settingsShareLead": "Share the app with your friends",
"paymentCash": "Cash",
"paymentWallet": "Wallet",
"rideWhereTo": "Where to?",
"rideOrigin": "From",
"rideDestination": "To",
@@ -224,12 +230,24 @@
"menuNotifications": "Notifications",
"menuPrivacy": "Privacy policy",
"menuRateApp": "Rate the app",
"shareMessage": "Join Tripz as a driver — use my code {code}",
"shareMessage": "Join Tripz as a driver — use my code {code}\n{link}",
"shareMessagePlain": "Join Tripz as a driver\n{link}",
"menuRiderApp": "Rider app",
"menuDriverApp": "Rider app",
"@shareMessage": {
"placeholders": {
"code": {
"type": "String"
},
"link": {
"type": "String"
}
}
},
"@shareMessagePlain": {
"placeholders": {
"link": {
"type": "String"
}
}
},
+37
View File
@@ -0,0 +1,37 @@
import 'package:flutter/foundation.dart';
import 'build_config.dart';
import 'config.dart';
/// اختيار رابط المتجر الصحيح — **بالمنصّة والدور معاً**.
///
/// كان الخطأ (مثبت 2026-08-05): رابط واحد ثابت `https://tripz.app` لكل
/// شيء — فـ«قيّم التطبيق» لا يفتح صفحة تقييم، و«شارك التطبيق» يرسل رسالة
/// بلا رابط أصلاً، و«سجّل كسائق» يفتح صفحة تسويقية لا تطبيق السائق.
///
/// أربع حالات لا واحدة: {آيفون، أندرويد} × {راكب، سائق}. والدور يأتي من
/// [AppConfig.appRole] الذي يميّز البناءين أصلاً.
class StoreLinks {
const StoreLinks._();
static bool get _isIos => defaultTargetPlatform == TargetPlatform.iOS;
static bool get _isDriverBuild => AppConfig.appRole == 'driver';
/// رابط تطبيق الراكب على منصّة هذا الجهاز.
static String get rider =>
_isIos ? BuildConfig.riderIosUrl : BuildConfig.riderAndroidUrl;
/// رابط تطبيق السائق على منصّة هذا الجهاز.
static String get driver =>
_isIos ? BuildConfig.driverIosUrl : BuildConfig.driverAndroidUrl;
/// **هذا** التطبيق في متجر هذا الجهاز — لـ«قيّم التطبيق» ولرابط المشاركة.
///
/// السائق يشارك رابط السائق، والراكب رابط الراكب: مشاركةُ راكبٍ لرابط
/// السائق تُنزِّل المدعوَّ تطبيقاً خاطئاً.
static String get thisApp => _isDriverBuild ? driver : rider;
/// تطبيق الطرف الآخر — «سجّل كسائق» في تطبيق الراكب، والعكس.
static String get otherApp => _isDriverBuild ? rider : driver;
}
+20 -9
View File
@@ -12,6 +12,7 @@ import '../l10n/l10n.dart';
import '../router.dart';
import '../session/session_cubit.dart';
import '../session/session_state.dart';
import '../store_links.dart';
import '../tenant/feature_gate.dart';
/// الدراور — نقطة تطبيق **طبقتَي الميزات** معاً (docs/23 §5 + docs/38 §10):
@@ -72,28 +73,38 @@ class AppDrawer extends StatelessWidget {
route: Routes.support,
),
// مداخل محليّة بلا نقطة خادم — تُنفَّذ في الجهاز مباشرة.
//
// الروابط من `StoreLinks` لا من ثابتٍ واحد: هذا البناء
// يشارك **رابط نفسه** (سائق يشارك رابط السائق)، ويفتح
// متجر منصّته هو.
_Action(
icon: Icons.share_outlined,
label: l10n.menuShare,
onTap: () => SharePlus.instance
.share(ShareParams(text: l10n.shareMessage(''))),
onTap: () => SharePlus.instance.share(
ShareParams(
text: l10n.shareMessagePlain(StoreLinks.thisApp),
),
),
),
_Action(
icon: Icons.star_outline_rounded,
label: l10n.menuRateApp,
onTap: () => _open(BuildConfig.storeUrl),
onTap: () => _open(StoreLinks.thisApp),
),
_Action(
icon: Icons.shield_outlined,
label: l10n.menuPrivacy,
onTap: () => _open(BuildConfig.privacyUrl),
),
if (!isDriver)
_Action(
icon: Icons.local_taxi_outlined,
label: l10n.menuDriverApp,
onTap: () => _open(BuildConfig.driverAppUrl),
),
// كان `if (!isDriver)` — وهذا البناء سائق دائماً، فالمدخل
// لم يكن يظهر أبداً. الطرف الآخر يُحسب لا يُخفى.
_Action(
icon: isDriver
? Icons.person_outline_rounded
: Icons.local_taxi_outlined,
label: isDriver ? l10n.menuRiderApp : l10n.menuDriverApp,
onTap: () => _open(StoreLinks.otherApp),
),
],
),
),