feat: add Jordan 3D topographic platform, Siro Map cinematic orbit studio, sun-shadow simulation, and sovereign intelligence security gating
@@ -12,7 +12,7 @@
|
||||
IMPORTANT NOTICE FOR APP REVIEWERS:
|
||||
|
||||
1. Operational Geographic Coverage:
|
||||
Uruk Map is engineered on an independent, self-hosted regional spatial vector engine. Our active vector map tiles and routing servers are currently provisioned specifically for three operational countries in the MENA region:
|
||||
Siro Map is engineered on an independent, self-hosted regional spatial vector engine. Our active vector map tiles and routing servers are currently provisioned specifically for three operational countries in the MENA region:
|
||||
- Jordan (الأردن)
|
||||
- Iraq (العراق)
|
||||
- Egypt (مصر)
|
||||
@@ -51,7 +51,7 @@ For any technical inquiries during review, please contact: support@intaleqapp.co
|
||||
ملاحظة هامة لفاحصي ومراجعي التطبيق:
|
||||
|
||||
1. نطاق التغطية الجغرافية التشغيلية:
|
||||
تعتمد «خرائط أوروك» على منظومة خرائط وملاحة فيكتورية مستقلة ومستضافة ذاتياً، وتغطي خوادم الخرائط والبيانات المكانية الحالية ثلاث دول تشغيلية رئيسية في منطقة الشرق الأوسط وشمال أفريقيا:
|
||||
تعتمد «خرائط سيرو» على منظومة خرائط وملاحة فيكتورية مستقلة ومستضافة ذاتياً، وتغطي خوادم الخرائط والبيانات المكانية الحالية ثلاث دول تشغيلية رئيسية في منطقة الشرق الأوسط وشمال أفريقيا:
|
||||
- الأردن
|
||||
- العراق
|
||||
- مصر
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ملف بيانات ونصوص النشر على Google Play Console | خرائط أوروك (Uruk Map)
|
||||
# ملف بيانات ونصوص النشر على Google Play Console | خرائط سيرو (Siro Map)
|
||||
================================================================================
|
||||
|
||||
هذا الملف يحتوي على كافة النصوص والبيانات المطلوبة لرفع وتعبئة تطبيق **Uruk Map** على **Google Play Console** باللغتين العربية والإنجليزية، وفق معايير خوارزميات تحسين متجر التطبيقات (ASO) وتوافقاً مع الحدود الرسمية لعدد الحروف.
|
||||
هذا الملف يحتوي على كافة النصوص والبيانات المطلوبة لرفع وتعبئة تطبيق **Siro Map** على **Google Play Console** باللغتين العربية والإنجليزية، وفق معايير خوارزميات تحسين متجر التطبيقات (ASO) وتوافقاً مع الحدود الرسمية لعدد الحروف، مع الحفاظ على معرف الحزمة التقني المعتمد على المتجر: `com.urukmap.app`.
|
||||
|
||||
---
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
### باللغة العربية (Arabic - Default)
|
||||
* **اسم التطبيق (App name - بحد أقصى 30 حرفاً)**:
|
||||
```text
|
||||
خرائط أوروك: ملاحة وتوجيه ذكي
|
||||
خرائط سيرو: ملاحة وتوجيه ذكي
|
||||
```
|
||||
*(بديل مقترح: `خرائط أوروك - Uruk Map`)*
|
||||
*(بديل مقترح: `خرائط سيرو - Siro Map`)*
|
||||
|
||||
* **الوصف القصير (Short description - بحد أقصى 80 حرفاً)**:
|
||||
```text
|
||||
@@ -21,13 +21,11 @@
|
||||
|
||||
* **الوصف الكامل (Full description - بحد أقصى 4000 حرف)**:
|
||||
```text
|
||||
«خرائط أوروك - Uruk Map» هي المنظومة المتقدمة للملاحة والخرائط الذكية المصممة خصيصاً لتلبية احتياجات العالم العربي ومنطقة الشرق الأوسط وشمال أفريقيا، بموثوقية فائقة وتقنيات تشغيل مستقلة.
|
||||
«خرائط سيرو - Siro Map» هي المنظومة المتقدمة للملاحة والخرائط الذكية المصممة خصيصاً لتلبية احتياجات العالم العربي ومنطقة الشرق الأوسط وشمال أفريقيا، بموثوقية فائقة وتقنيات تشغيل مستقلة.
|
||||
|
||||
🏆 مشروع يحظى برعاية ودعم برنامج جائزة أوروك الدولية للابتكار وتطوير الخدمات التقنية.
|
||||
سواء كنت تتنقل داخل المدن المزدحمة، أو تقود عبر الطرق السريعة في المناطق التي تعاني من ضعف شبكات التغطية أو قيود خدمات الخرائط العالمية (في العراق، السودان، اليمن، سوريا، والمنطقة)، تمنحك خرائط سيرو تجربة تنقل دقيقة، سريعة، واقتصادية في استهلاك البيانات.
|
||||
|
||||
سواء كنت تتنقل داخل المدن المزدحمة، أو تقود عبر الطرق السريعة في المناطق التي تعاني من ضعف شبكات التغطية أو قيود خدمات الخرائط العالمية (في العراق، السودان، اليمن، سوريا، والمنطقة)، تمنحك خرائط أوروك تجربة تنقل دقيقة، سريعة، واقتصادية في استهلاك البيانات.
|
||||
|
||||
لماذا تختار خرائط أوروك؟
|
||||
لماذا تختار خرائط سيرو؟
|
||||
|
||||
🧠 1. كاش ذكي واستدعاء فوري من الذاكرة
|
||||
نظام متقدم لحفظ بلاطات الخريطة في ذاكرة الجهاز (Memory Cache) لاستدعائها فوراً دون تأخير، مما يوفر سرعة استجابة فائقة ويقلل استهلاك باقة الإنترنت.
|
||||
@@ -56,7 +54,7 @@
|
||||
🛡️ 9. حماية الخصوصية وتوفير البطارية
|
||||
تصميم برمجي حديث ومحسّن لا يستهلك طاقة البطارية ولا يجمع بياناتك الخاصة بدون إذن.
|
||||
|
||||
حمّل «خرائط أوروك» اليوم واستمتع بتجربة ملاحة حرة، ذكية، ومستقلة 100%!
|
||||
حمّل «خرائط سيرو» اليوم واستمتع بتجربة ملاحة حرة، ذكية، ومستقلة 100%!
|
||||
```
|
||||
|
||||
---
|
||||
@@ -64,9 +62,9 @@
|
||||
### باللغة الإنجليزية (English - United States)
|
||||
* **App Name (Max 30 characters)**:
|
||||
```text
|
||||
Uruk Map: GPS Navigation
|
||||
Siro Map: GPS Navigation
|
||||
```
|
||||
*(Alternative: `Uruk Map - Smart Navigation`)*
|
||||
*(Alternative: `Siro Map - Smart Navigation`)*
|
||||
|
||||
* **Short Description (Max 80 characters)**:
|
||||
```text
|
||||
@@ -75,11 +73,9 @@
|
||||
|
||||
* **Full Description (Max 4000 characters)**:
|
||||
```text
|
||||
Uruk Map is an advanced GPS navigation and digital mapping platform engineered specifically for the Middle East, North Africa, and regional markets requiring dependable offline capabilities.
|
||||
Siro Map is an advanced GPS navigation and digital mapping platform engineered specifically for the Middle East, North Africa, and regional markets requiring dependable offline capabilities.
|
||||
|
||||
🏆 Backed and supported by the Uruk International Prize program for technological innovation and digital service infrastructure.
|
||||
|
||||
Whether commuting through bustling metropolitan hubs or navigating transit routes across Iraq, Sudan, Yemen, Syria, and the broader MENA region, Uruk Map delivers unmatched precision, high-speed memory caching, and independent offline reliability.
|
||||
Whether commuting through bustling metropolitan hubs or navigating transit routes across Iraq, Sudan, Yemen, Syria, and the broader MENA region, Siro Map delivers unmatched precision, high-speed memory caching, and independent offline reliability.
|
||||
|
||||
KEY FEATURES:
|
||||
|
||||
@@ -110,7 +106,7 @@
|
||||
🔋 9. Battery & Data Optimized
|
||||
Engineered with high-performance native rendering (MapLibre vector graphics) that maximizes battery endurance and minimizes background data.
|
||||
|
||||
Download Uruk Map today and experience fast, smart, and independent navigation!
|
||||
Download Siro Map today and experience fast, smart, and independent navigation!
|
||||
```
|
||||
|
||||
---
|
||||
@@ -135,14 +131,12 @@
|
||||
1. **أيقونة التطبيق (App Icon)**:
|
||||
- القياس: `512 x 512` بكسل
|
||||
- الصيغة: `PNG 32-bit`
|
||||
- المسار الجاهز: `assets/images/uruk_map_playstore_512.png`
|
||||
- *(ملف تم إنشاؤه مسبقاً ومطابق لمعايير جوجل بلاي)*.
|
||||
- المسار الجاهز: `assets/images/siro_map_playstore_512.png`
|
||||
|
||||
2. **الرسم المميز / البانر (Feature Graphic)**:
|
||||
- القياس: `1024 x 500` بكسل
|
||||
- الصيغة: `JPEG / PNG` (بدون شفافية)
|
||||
- المسار الجاهز: `assets/images/uruk_playstore_feature_graphic_1024x500.jpg`
|
||||
- *(بانر ملكي فاخر يدمج تمثال أوروك الذهبي وشبكة الطرق المتوهجة)*.
|
||||
- المسار الجاهز: `assets/images/siro_playstore_feature_graphic_1024x500.png`
|
||||
|
||||
3. **لقطات الشاشة (Screenshots)**:
|
||||
- الحد الأدنى: 2 لقطات (المستحسن من 4 إلى 8 لقطات).
|
||||
@@ -151,7 +145,7 @@
|
||||
1. شاشة الخريطة الرئيسية مع شريط البحث والملاحة الفيكتورية.
|
||||
2. شاشة التوجيه الفعلي Turn-by-Turn مع بطاقة PiP ولوحة السرعة.
|
||||
3. شاشة طبقات الخريطة وتخصيص أيقونة المركبة.
|
||||
4. شاشة الاعتماد وجائزة أوروك الدولية للسيادة المكانية.
|
||||
4. شاشة بطاقة التعريف ومنظومة سيرو ماب للسيادة المكانية.
|
||||
|
||||
---
|
||||
|
||||
@@ -196,7 +190,7 @@
|
||||
IMPORTANT NOTICE FOR APP REVIEWERS:
|
||||
|
||||
1. Operational Geographic Coverage:
|
||||
Uruk Map operates on an independent, self-hosted regional spatial vector engine. Our vector map tiles and routing servers are currently live specifically for three operational countries in the MENA region:
|
||||
Siro Map operates on an independent, self-hosted regional spatial vector engine. Our vector map tiles and routing servers are currently live specifically for three operational countries in the MENA region:
|
||||
- Jordan (الأردن)
|
||||
- Iraq (العراق)
|
||||
- Egypt (مصر)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
|
||||
|
||||
<application
|
||||
android:label="Uruk Map"
|
||||
android:label="Siro Map"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
||||
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 276 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 800 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 392 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 30 KiB |
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Uruk Map</string>
|
||||
<string>Siro Map</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>uruk_map</string>
|
||||
<string>siro_maps</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
@@ -27,9 +27,9 @@
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>يستخدم تطبيق خرائط أوروك (Uruk Map) موقعك لعرض خريطة تفاعلية وتوفير الملاحة الحية الدقيقة.</string>
|
||||
<string>يستخدم تطبيق خرائط سيرو (Siro Map) موقعك لعرض خريطة تفاعلية وتوفير الملاحة الحية الدقيقة.</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>يستخدم تطبيق خرائط أوروك (Uruk Map) موقعك في الخلفية لتقديم التوجيهات الصوتية الحية وتنبيهات الطريق أثناء القيادة.</string>
|
||||
<string>يستخدم تطبيق خرائط سيرو (Siro Map) موقعك في الخلفية لتقديم التوجيهات الصوتية الحية وتنبيهات الطريق أثناء القيادة.</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>location</string>
|
||||
|
||||
@@ -20,10 +20,10 @@ class AppColors {
|
||||
static const Color tacticalNavy = Color(0xFF0B192C);
|
||||
static const Color tacticalEmerald = Color(0xFF059669);
|
||||
static const Color sovereignGold = Color(0xFFD97706);
|
||||
static const Color urukGold = Color(0xFFD4AF37);
|
||||
static const Color urukGoldLight = Color(0xFFFFF9E6);
|
||||
static const Color urukGoldDark = Color(0xFF8C6B1C);
|
||||
static const Color urukGoldBorder = Color(0x40D4AF37);
|
||||
static const Color siroGold = Color(0xFFD4AF37);
|
||||
static const Color siroGoldLight = Color(0xFFFFF9E6);
|
||||
static const Color siroGoldDark = Color(0xFF8C6B1C);
|
||||
static const Color siroGoldBorder = Color(0x40D4AF37);
|
||||
static const Color coralDanger = Color(0xFFDC2626);
|
||||
|
||||
// Borders & Dividers
|
||||
|
||||
@@ -55,7 +55,7 @@ class SiroMapsApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'خرائط أوروك - Uruk Map',
|
||||
title: 'خرائط سيرو - Siro Map',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: AppTheme.lightTheme,
|
||||
locale: const Locale('ar', 'JO'),
|
||||
|
||||
@@ -21,6 +21,7 @@ import 'widgets/report_hazard_sheet.dart';
|
||||
import 'widgets/add_place_sheet.dart';
|
||||
import 'widgets/vehicle_customizer_sheet.dart';
|
||||
import 'widgets/about_awards_sheet.dart';
|
||||
import 'widgets/cinematic_3d_studio_sheet.dart';
|
||||
|
||||
class MapView extends StatefulWidget {
|
||||
const MapView({super.key});
|
||||
@@ -116,6 +117,18 @@ class _MapViewState extends State<MapView> {
|
||||
);
|
||||
}
|
||||
|
||||
void _showCinematic3DStudio(BuildContext context, NavigationCubit cubit, NavigationState state) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (_) => Cinematic3DStudioSheet(
|
||||
cubit: cubit,
|
||||
state: state,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showLayerSelector(BuildContext context, NavigationCubit cubit, MapThemeType current) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
@@ -126,6 +139,10 @@ class _MapViewState extends State<MapView> {
|
||||
cubit.setMapTheme(theme);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
onOpenCinematic3DStudio: () {
|
||||
Navigator.of(context).pop();
|
||||
_showCinematic3DStudio(context, cubit, cubit.state);
|
||||
},
|
||||
onOpenVehicleCustomizer: () {
|
||||
Navigator.of(context).pop();
|
||||
_showVehicleCustomizer(context, cubit, cubit.state);
|
||||
@@ -1251,6 +1268,14 @@ class _MapViewState extends State<MapView> {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 3D Cinematic Studio Button
|
||||
_buildFloatingCircle(
|
||||
icon: Icons.view_in_ar_rounded,
|
||||
color: const Color(0xFFEA580C),
|
||||
tooltip: 'استوديو التضاريس والسينما 3D',
|
||||
onTap: () => _showCinematic3DStudio(context, cubit, state),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Layer Selector Button
|
||||
_buildFloatingCircle(
|
||||
icon: Icons.layers_rounded,
|
||||
@@ -1259,11 +1284,11 @@ class _MapViewState extends State<MapView> {
|
||||
onTap: () => _showLayerSelector(context, cubit, state.mapTheme),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Uruk International Prize & Platform Architecture Button
|
||||
// Siro Map Platform Architecture & Info Button
|
||||
_buildFloatingCircle(
|
||||
icon: Icons.workspace_premium_rounded,
|
||||
color: AppColors.urukGoldDark,
|
||||
tooltip: 'عن جائزة أوروك والمنظومة التقنية',
|
||||
icon: Icons.info_outline_rounded,
|
||||
color: AppColors.appleBlue,
|
||||
tooltip: 'عن سيرو ماب والمنظومة التقنية',
|
||||
onTap: () => _showAboutAwardsSheet(context),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
@@ -56,12 +56,12 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
shape: BoxShape.circle,
|
||||
color: AppColors.pureWhite,
|
||||
border: Border.all(
|
||||
color: AppColors.urukGold.withValues(alpha: 0.45),
|
||||
color: AppColors.appleBlue.withValues(alpha: 0.35),
|
||||
width: 2,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.urukGold.withValues(alpha: 0.2),
|
||||
color: AppColors.appleBlue.withValues(alpha: 0.15),
|
||||
blurRadius: 26,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
@@ -70,14 +70,14 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: ClipOval(
|
||||
child: Image.asset(
|
||||
'assets/images/uruk_prize_logo.png',
|
||||
'assets/images/siro_maps_logo.png',
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
Text(
|
||||
'جائزة أوروك الدولية',
|
||||
'خرائط سيرو',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w800,
|
||||
@@ -86,11 +86,11 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
'URUK INTERNATIONAL PRIZE',
|
||||
'SIRO MAP',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.urukGoldDark,
|
||||
color: AppColors.appleBlue,
|
||||
letterSpacing: 1.5,
|
||||
),
|
||||
),
|
||||
@@ -98,25 +98,25 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.urukGoldLight,
|
||||
color: AppColors.surfaceMuted,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: AppColors.urukGoldBorder),
|
||||
border: Border.all(color: AppColors.borderSubtle),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.workspace_premium_rounded,
|
||||
Icons.verified_rounded,
|
||||
size: 16,
|
||||
color: AppColors.urukGoldDark,
|
||||
color: AppColors.appleBlue,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'رعاية ودعم الابتكار والخدمات التقنية',
|
||||
'منظومة الملاحة والخرائط الذكية المستقلة',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.urukGoldDark,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -128,16 +128,16 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
|
||||
const SizedBox(height: 22),
|
||||
|
||||
// ── 2. URUK PRIZE MISSION & ROLE ──
|
||||
// ── 2. SIRO MAP MISSION & VISION ──
|
||||
_buildSectionCard(
|
||||
icon: Icons.lightbulb_rounded,
|
||||
iconColor: AppColors.urukGoldDark,
|
||||
title: 'دور جائزة أوروك ورسالتها التقنية',
|
||||
icon: Icons.explore_rounded,
|
||||
iconColor: AppColors.appleBlue,
|
||||
title: 'عن سيرو ماب والرؤية التقنية',
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'تستلهم جائزة أوروك الدولية رمزيتها من حضارة أوروك العريقة — مهد التنظيم المدني والقياسات الأولى في تاريخ الإنسانية — لتبني وتدعم المشاريع والخدمات التقنية المبتكرة في العالم العربي والشرق الأوسط.',
|
||||
'تعتمد خرائط سيرو (Siro Map) على منظومة خرائط وملاحة فيكتورية متقدمة ومستضافة ذاتياً، لتقديم حلول مكانية متطورة تخدم التنقل الذكي وسلاسل الإمداد في العالم العربي ومنطقة الشرق الأوسط وشمال أفريقيا.',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 12.5,
|
||||
height: 1.65,
|
||||
@@ -147,7 +147,7 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'تعمل الجائزة وبرامجها على تشجيع التوسع في البنى التحتية الرقمية، وتمكين الحلول الذكية المستقلة التي تسد الفجوات التقنية وتخدم المجتمعات وقطاعات النقل والحركة بكفاءة عالية.',
|
||||
'تهدف المنظومة إلى تمكين الاستقلالية الرقمية الجغرافية الكاملة، وتقديم خرائط عالية السرعة والدقة مع خفض جذري في تكاليف واستهلاك البيانات مقارنة بالخدمات العالمية التقليدية.',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 12.5,
|
||||
height: 1.65,
|
||||
@@ -191,7 +191,7 @@ class AboutAwardsSheet extends StatelessWidget {
|
||||
const Divider(height: 18, color: AppColors.borderSubtle),
|
||||
_buildTechRow(
|
||||
icon: Icons.public_rounded,
|
||||
iconColor: AppColors.urukGoldDark,
|
||||
iconColor: AppColors.appleBlue,
|
||||
title: 'تغطية الأسواق الإقليمية الحيوية',
|
||||
desc: 'تركيز استراتيجي على توفير بيانات طرق تفصيلية ومحدثة للأسواق التي تعاني من نقص أو قيود في الخرائط العالمية (العراق، السودان، اليمن، سوريا، والمنطقة).',
|
||||
),
|
||||
|
||||
@@ -55,7 +55,7 @@ class _AddPlaceSheetState extends State<AddPlaceSheet> {
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
const Text(
|
||||
'إضافة مكان جديد إلى خرائط أوروك',
|
||||
'إضافة مكان جديد إلى خرائط سيرو',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w700),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,756 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../core/constants/app_colors.dart';
|
||||
import '../../../../logic/cubits/navigation/navigation_cubit.dart';
|
||||
import '../../../../logic/cubits/navigation/navigation_state.dart';
|
||||
|
||||
class Cinematic3DStudioSheet extends StatefulWidget {
|
||||
final NavigationCubit cubit;
|
||||
final NavigationState state;
|
||||
|
||||
const Cinematic3DStudioSheet({
|
||||
super.key,
|
||||
required this.cubit,
|
||||
required this.state,
|
||||
});
|
||||
|
||||
@override
|
||||
State<Cinematic3DStudioSheet> createState() => _Cinematic3DStudioSheetState();
|
||||
}
|
||||
|
||||
class _Cinematic3DStudioSheetState extends State<Cinematic3DStudioSheet> {
|
||||
// Camera Tilt State
|
||||
double _tilt = 55.0;
|
||||
|
||||
// Orbit State
|
||||
bool _isOrbiting = false;
|
||||
double _orbitSpeed = 1.0;
|
||||
Timer? _orbitTimer;
|
||||
|
||||
// Sun & Shadow Simulation State
|
||||
// Range: 330 minutes (05:30 AM) to 1260 minutes (09:00 PM)
|
||||
int _sunTimeMinutes = 1110; // Default: 18:30 (Golden Hour Sunset)
|
||||
bool _isSunPlaying = false;
|
||||
Timer? _sunTimer;
|
||||
|
||||
// Layer Toggles
|
||||
bool _showBuildings = true;
|
||||
bool _showContours = true;
|
||||
bool _showHillshading = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Get initial camera tilt if available
|
||||
final initialPos = widget.cubit.mapController?.cameraPosition;
|
||||
if (initialPos != null && initialPos.tilt > 0) {
|
||||
_tilt = initialPos.tilt;
|
||||
} else {
|
||||
// Set to 55 degrees for instant 3D perspective
|
||||
widget.cubit.mapController?.setTilt(55.0);
|
||||
}
|
||||
|
||||
// Apply initial golden hour lighting
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_applySunLighting(_sunTimeMinutes);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_orbitTimer?.cancel();
|
||||
_sunTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// ── Orbit Logic ──
|
||||
void _toggleOrbit() {
|
||||
setState(() {
|
||||
_isOrbiting = !_isOrbiting;
|
||||
});
|
||||
|
||||
_orbitTimer?.cancel();
|
||||
if (_isOrbiting) {
|
||||
_orbitTimer = Timer.periodic(const Duration(milliseconds: 60), (_) {
|
||||
if (!mounted || !_isOrbiting) return;
|
||||
widget.cubit.mapController?.orbitStep(
|
||||
_orbitSpeed,
|
||||
duration: const Duration(milliseconds: 60),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ── Sun & Shadows Simulation Logic ──
|
||||
void _toggleSunAutoPlay() {
|
||||
setState(() {
|
||||
_isSunPlaying = !_isSunPlaying;
|
||||
});
|
||||
|
||||
_sunTimer?.cancel();
|
||||
if (_isSunPlaying) {
|
||||
_sunTimer = Timer.periodic(const Duration(milliseconds: 130), (_) {
|
||||
if (!mounted || !_isSunPlaying) return;
|
||||
setState(() {
|
||||
_sunTimeMinutes += 12;
|
||||
if (_sunTimeMinutes > 1260) {
|
||||
_sunTimeMinutes = 330; // Loop back to 05:30 AM
|
||||
}
|
||||
});
|
||||
_applySunLighting(_sunTimeMinutes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _onSunSliderChanged(double value) {
|
||||
setState(() {
|
||||
_sunTimeMinutes = value.toInt();
|
||||
});
|
||||
_applySunLighting(_sunTimeMinutes);
|
||||
}
|
||||
|
||||
void _setPresetTime(int minutes) {
|
||||
setState(() {
|
||||
_sunTimeMinutes = minutes;
|
||||
});
|
||||
_applySunLighting(minutes);
|
||||
}
|
||||
|
||||
void _applySunLighting(int minutes) {
|
||||
// Fraction of daylight cycle: 0.0 (05:30) to 1.0 (21:00)
|
||||
final double fraction = ((minutes - 330) / (1260 - 330)).clamp(0.0, 1.0);
|
||||
|
||||
// Azimuth sweeps from 75° (East - Sunrise) to 180° (South - Noon) to 290° (West - Sunset)
|
||||
final double sunAzimuth = 75.0 + (fraction * 215.0);
|
||||
|
||||
String shadowColor;
|
||||
String highlightColor;
|
||||
String buildingColor;
|
||||
double opacity = 0.88;
|
||||
|
||||
if (minutes < 420) {
|
||||
// Dawn (05:30 - 07:00)
|
||||
shadowColor = '#4c1d95'; // Deep violet dawn shadow
|
||||
highlightColor = '#fed7aa'; // Peach highlight
|
||||
buildingColor = '#fbcfe8'; // Morning rose tint
|
||||
opacity = 0.85;
|
||||
} else if (minutes < 660) {
|
||||
// Morning (07:00 - 11:00)
|
||||
shadowColor = '#334155';
|
||||
highlightColor = '#ffffff';
|
||||
buildingColor = '#fef08a'; // Golden morning sun
|
||||
opacity = 0.88;
|
||||
} else if (minutes < 840) {
|
||||
// Noon (11:00 - 14:00)
|
||||
shadowColor = '#1e293b'; // Crisp direct shadow
|
||||
highlightColor = '#ffffff';
|
||||
buildingColor = '#f8fafc'; // Crisp bright daylight
|
||||
opacity = 0.90;
|
||||
} else if (minutes < 1050) {
|
||||
// Afternoon (14:00 - 17:30)
|
||||
shadowColor = '#374151';
|
||||
highlightColor = '#ffedd5';
|
||||
buildingColor = '#fed7aa'; // Warm afternoon sun
|
||||
opacity = 0.88;
|
||||
} else if (minutes < 1170) {
|
||||
// Sunset / Golden Hour (17:30 - 19:30)
|
||||
shadowColor = '#3b0764'; // Dramatic deep purple-amber shadow
|
||||
highlightColor = '#ffedd5';
|
||||
buildingColor = '#ea580c'; // Glowing warm sunset orange
|
||||
opacity = 0.92;
|
||||
} else {
|
||||
// Night / Twilight (19:30 - 21:00)
|
||||
shadowColor = '#020617';
|
||||
highlightColor = '#60a5fa'; // Cool blue moonlight
|
||||
buildingColor = '#1e293b'; // Dark sapphire buildings
|
||||
opacity = 0.80;
|
||||
}
|
||||
|
||||
widget.cubit.mapController?.updateSunSimulation(
|
||||
sunAzimuth: sunAzimuth,
|
||||
shadowColorHex: shadowColor,
|
||||
highlightColorHex: highlightColor,
|
||||
buildingColorHex: buildingColor,
|
||||
buildingOpacity: opacity,
|
||||
);
|
||||
}
|
||||
|
||||
String _formatSunTime(int minutes) {
|
||||
final int hours = minutes ~/ 60;
|
||||
final int mins = minutes % 60;
|
||||
final String minsStr = mins.toString().padLeft(2, '0');
|
||||
final String period = hours >= 12 ? 'م' : 'ص';
|
||||
final int displayHour = hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours);
|
||||
|
||||
String label = '';
|
||||
if (minutes < 420) {
|
||||
label = 'الفجر والشروق 🌅';
|
||||
} else if (minutes < 660) {
|
||||
label = 'الصباح الباكر ☀️';
|
||||
} else if (minutes < 840) {
|
||||
label = 'الظهيرة الساطعة 🌤️';
|
||||
} else if (minutes < 1050) {
|
||||
label = 'العصر ⛅';
|
||||
} else if (minutes < 1170) {
|
||||
label = 'الغروب الذهبي 🌇';
|
||||
} else {
|
||||
label = 'الليل التكتيكي 🌙';
|
||||
}
|
||||
|
||||
return '$displayHour:$minsStr $period • $label';
|
||||
}
|
||||
|
||||
// ── Tilt Logic ──
|
||||
void _setTilt(double newTilt) {
|
||||
setState(() => _tilt = newTilt);
|
||||
widget.cubit.mapController?.setTilt(newTilt);
|
||||
}
|
||||
|
||||
// ── Layer Toggles ──
|
||||
void _toggleBuildings() {
|
||||
setState(() => _showBuildings = !_showBuildings);
|
||||
widget.cubit.mapController?.setLayerVisibility('building-3d', _showBuildings);
|
||||
widget.cubit.mapController?.setLayerVisibility('building-3d-osm', _showBuildings);
|
||||
}
|
||||
|
||||
void _toggleContours() {
|
||||
setState(() => _showContours = !_showContours);
|
||||
widget.cubit.mapController?.setLayerVisibility('tactical-contour-minor', _showContours);
|
||||
widget.cubit.mapController?.setLayerVisibility('tactical-contour-major', _showContours);
|
||||
widget.cubit.mapController?.setLayerVisibility('opentopo-contour-lines', _showContours);
|
||||
}
|
||||
|
||||
void _toggleHillshading() {
|
||||
setState(() => _showHillshading = !_showHillshading);
|
||||
widget.cubit.mapController?.setLayerVisibility('hillshading', _showHillshading);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isSatellite = widget.state.mapTheme == MapThemeType.satellite;
|
||||
final double fraction = ((_sunTimeMinutes - 330) / (1260 - 330)).clamp(0.0, 1.0);
|
||||
final double sunAzimuth = 75.0 + (fraction * 215.0);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(20, 16, 20, 36),
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.pureWhite,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Color(0x28000000),
|
||||
blurRadius: 28,
|
||||
offset: Offset(0, -8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Drag Handle
|
||||
Center(
|
||||
child: Container(
|
||||
width: 42,
|
||||
height: 4.5,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.borderGlass,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Header
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 38,
|
||||
height: 38,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFEA580C), Color(0xFFF59E0B)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(11),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFFEA580C).withValues(alpha: 0.35),
|
||||
blurRadius: 10,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Icon(Icons.view_in_ar_rounded, color: Colors.white, size: 22),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'استوديو التضاريس والسينما 3D',
|
||||
style: TextStyle(
|
||||
fontSize: 15.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'دوران سينمائي • محاكاة حركة الشمس والظلال',
|
||||
style: TextStyle(fontSize: 11, color: AppColors.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
icon: const Icon(Icons.close_rounded, color: AppColors.textMuted),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 18),
|
||||
const Divider(height: 1, color: AppColors.borderSubtle),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// ── 1. DAY-TO-NIGHT SUN & SHADOWS SIMULATION (Stationary Location) ──
|
||||
Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0F172A),
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: const Color(0xFF334155)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFEA580C).withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Icon(Icons.wb_sunny_rounded, color: Color(0xFFFB923C), size: 16),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'محاكاة حركة الشمس وسقوط الظلال',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Auto-Play Toggle Button
|
||||
InkWell(
|
||||
onTap: _toggleSunAutoPlay,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: _isSunPlaying
|
||||
? const Color(0xFFEA580C)
|
||||
: Colors.white.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: _isSunPlaying
|
||||
? const Color(0xFFEA580C)
|
||||
: Colors.white.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_isSunPlaying ? Icons.pause_rounded : Icons.play_arrow_rounded,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_isSunPlaying ? 'إيقاف الدورة' : 'دورة تلقائية',
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
const Text(
|
||||
'المكان ثابت: وحركة الضوء تحاكي زاوية الشمس لرؤية تشكل وظلال المباني والجبال',
|
||||
style: TextStyle(fontSize: 10.5, color: Color(0xFF94A3B8)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Current Time Display & Azimuth
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
_formatSunTime(_sunTimeMinutes),
|
||||
style: const TextStyle(
|
||||
fontSize: 12.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Color(0xFFFDBA74),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.08),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
'زاوية الإسقاط: ${sunAzimuth.toStringAsFixed(0)}°',
|
||||
style: const TextStyle(fontSize: 10, color: Color(0xFFCBD5E1)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
|
||||
// Slider
|
||||
SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
activeTrackColor: const Color(0xFFEA580C),
|
||||
inactiveTrackColor: Colors.white.withValues(alpha: 0.15),
|
||||
thumbColor: const Color(0xFFFB923C),
|
||||
overlayColor: const Color(0xFFEA580C).withValues(alpha: 0.2),
|
||||
trackHeight: 4,
|
||||
),
|
||||
child: Slider(
|
||||
min: 330.0,
|
||||
max: 1260.0,
|
||||
value: _sunTimeMinutes.toDouble(),
|
||||
onChanged: _onSunSliderChanged,
|
||||
),
|
||||
),
|
||||
|
||||
// Quick Sun Period Buttons
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_buildSunPeriodChip('06:00 ص', 'الفجر', 360),
|
||||
_buildSunPeriodChip('09:00 ص', 'الصباح', 540),
|
||||
_buildSunPeriodChip('12:00 م', 'الظهيرة', 720),
|
||||
_buildSunPeriodChip('06:30 م', 'الغروب', 1110),
|
||||
_buildSunPeriodChip('08:30 م', 'الليل', 1230),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// ── 2. CINEMATIC 360° ORBIT & CAMERA TILT ──
|
||||
Row(
|
||||
children: [
|
||||
// Orbit Button
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: _toggleOrbit,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 13, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: _isOrbiting
|
||||
? AppColors.appleBlue.withValues(alpha: 0.1)
|
||||
: AppColors.surfaceMuted,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: _isOrbiting ? AppColors.appleBlue : AppColors.borderSubtle,
|
||||
width: _isOrbiting ? 2 : 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.rotate_right_rounded,
|
||||
color: _isOrbiting ? AppColors.appleBlue : AppColors.textPrimary,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_isOrbiting ? 'الدوران نشط 360°' : 'دوران سينمائي',
|
||||
style: TextStyle(
|
||||
fontSize: 12.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: _isOrbiting ? AppColors.appleBlue : AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_isOrbiting ? 'انقر للإيقاف' : 'التفاف حول الموقع',
|
||||
style: const TextStyle(fontSize: 10, color: AppColors.textMuted),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
|
||||
// Orbit Speed Selector (When active)
|
||||
if (_isOrbiting)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surfaceMuted,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: AppColors.borderSubtle),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildSpeedChip(0.6, 'بطيء'),
|
||||
_buildSpeedChip(1.2, 'سلس'),
|
||||
_buildSpeedChip(2.4, 'سريع'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// ── 3. CAMERA TILT CONTROLS ──
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surfaceMuted,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: AppColors.borderSubtle),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'إمالة الكاميرا للأفق (Camera Tilt):',
|
||||
style: TextStyle(
|
||||
fontSize: 12.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${_tilt.toStringAsFixed(0)}°',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.appleBlue,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
_buildTiltPresetChip(0.0, '2D مسطح (0°)'),
|
||||
const SizedBox(width: 8),
|
||||
_buildTiltPresetChip(45.0, '3D كتل (45°)'),
|
||||
const SizedBox(width: 8),
|
||||
_buildTiltPresetChip(60.0, 'أفق سينمائي (60°)'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// ── 4. 3D LAYERS TOGGLES ──
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildFeatureToggle(
|
||||
title: 'المباني 3D',
|
||||
icon: Icons.apartment_rounded,
|
||||
active: _showBuildings,
|
||||
onTap: _toggleBuildings,
|
||||
),
|
||||
_buildFeatureToggle(
|
||||
title: 'خطوط الكنتور',
|
||||
icon: Icons.layers_outlined,
|
||||
active: _showContours,
|
||||
onTap: _toggleContours,
|
||||
),
|
||||
_buildFeatureToggle(
|
||||
title: 'ظلال التضاريس',
|
||||
icon: Icons.landscape_rounded,
|
||||
active: _showHillshading,
|
||||
onTap: _toggleHillshading,
|
||||
),
|
||||
_buildFeatureToggle(
|
||||
title: 'أقمار صناعية',
|
||||
icon: Icons.satellite_alt_rounded,
|
||||
active: isSatellite,
|
||||
onTap: () {
|
||||
widget.cubit.setMapTheme(
|
||||
isSatellite ? MapThemeType.vectorLight : MapThemeType.satellite,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSunPeriodChip(String time, String label, int minutes) {
|
||||
final bool isSelected = (_sunTimeMinutes - minutes).abs() < 40;
|
||||
return InkWell(
|
||||
onTap: () => _setPresetTime(minutes),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? const Color(0xFFEA580C)
|
||||
: Colors.white.withValues(alpha: 0.08),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 9.5,
|
||||
fontWeight: isSelected ? FontWeight.w800 : FontWeight.w500,
|
||||
color: isSelected ? Colors.white : const Color(0xFFCBD5E1),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
time,
|
||||
style: TextStyle(
|
||||
fontSize: 8.5,
|
||||
color: isSelected ? Colors.white.withValues(alpha: 0.9) : const Color(0xFF64748B),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSpeedChip(double speed, String label) {
|
||||
final bool isSelected = (_orbitSpeed - speed).abs() < 0.1;
|
||||
return InkWell(
|
||||
onTap: () => setState(() => _orbitSpeed = speed),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AppColors.appleBlue : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 10.5,
|
||||
fontWeight: isSelected ? FontWeight.w700 : FontWeight.w500,
|
||||
color: isSelected ? Colors.white : AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTiltPresetChip(double tiltValue, String label) {
|
||||
final bool isSelected = (_tilt - tiltValue).abs() < 4.0;
|
||||
return Expanded(
|
||||
child: InkWell(
|
||||
onTap: () => _setTilt(tiltValue),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AppColors.appleBlue : Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: isSelected ? AppColors.appleBlue : AppColors.borderSubtle,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: isSelected ? FontWeight.w700 : FontWeight.w600,
|
||||
color: isSelected ? Colors.white : AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFeatureToggle({
|
||||
required String title,
|
||||
required IconData icon,
|
||||
required bool active,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
width: 76,
|
||||
padding: const EdgeInsets.symmetric(vertical: 9),
|
||||
decoration: BoxDecoration(
|
||||
color: active
|
||||
? AppColors.appleBlue.withValues(alpha: 0.08)
|
||||
: AppColors.surfaceMuted,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: active ? AppColors.appleBlue : AppColors.borderSubtle,
|
||||
width: active ? 1.5 : 1,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 20,
|
||||
color: active ? AppColors.appleBlue : AppColors.textMuted,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: active ? FontWeight.w700 : FontWeight.w500,
|
||||
color: active ? AppColors.appleBlue : AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ class LayerSelectorSheet extends StatelessWidget {
|
||||
final ValueChanged<MapThemeType> onThemeChanged;
|
||||
final VoidCallback? onOpenVehicleCustomizer;
|
||||
final VoidCallback? onOpenAboutAwards;
|
||||
final VoidCallback? onOpenCinematic3DStudio;
|
||||
|
||||
const LayerSelectorSheet({
|
||||
super.key,
|
||||
@@ -14,6 +15,7 @@ class LayerSelectorSheet extends StatelessWidget {
|
||||
required this.onThemeChanged,
|
||||
this.onOpenVehicleCustomizer,
|
||||
this.onOpenAboutAwards,
|
||||
this.onOpenCinematic3DStudio,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -68,6 +70,43 @@ class LayerSelectorSheet extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (onOpenCinematic3DStudio != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
ListTile(
|
||||
onTap: onOpenCinematic3DStudio,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
side: const BorderSide(color: Color(0x33EA580C)),
|
||||
),
|
||||
tileColor: const Color(0xFFEA580C).withValues(alpha: 0.08),
|
||||
leading: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFEA580C), Color(0xFFF59E0B)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Icon(Icons.view_in_ar_rounded, color: Colors.white, size: 22),
|
||||
),
|
||||
title: const Text(
|
||||
'استوديو التضاريس والسينما 3D',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
subtitle: const Text(
|
||||
'دوران سينمائي 360° • محاكاة حركة الشمس وسقوط الظلال',
|
||||
style: TextStyle(fontSize: 11, color: Color(0xFFEA580C), fontWeight: FontWeight.w600),
|
||||
),
|
||||
trailing: const Icon(Icons.arrow_forward_ios_rounded, size: 14, color: Color(0xFFEA580C)),
|
||||
),
|
||||
],
|
||||
if (onOpenVehicleCustomizer != null) ...[
|
||||
const SizedBox(height: 18),
|
||||
const Divider(height: 1, color: AppColors.borderSubtle),
|
||||
@@ -106,37 +145,37 @@ class LayerSelectorSheet extends StatelessWidget {
|
||||
onTap: onOpenAboutAwards,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
side: const BorderSide(color: AppColors.urukGoldBorder),
|
||||
side: const BorderSide(color: AppColors.borderSubtle),
|
||||
),
|
||||
tileColor: AppColors.urukGoldLight,
|
||||
tileColor: AppColors.surfaceMuted,
|
||||
leading: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.pureWhite,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: AppColors.urukGold.withValues(alpha: 0.4)),
|
||||
border: Border.all(color: AppColors.borderSubtle),
|
||||
),
|
||||
child: ClipOval(
|
||||
child: Image.asset(
|
||||
'assets/images/uruk_prize_logo.png',
|
||||
'assets/images/siro_maps_logo.png',
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: const Text(
|
||||
'عن منظومة أوروك والتقنيات المفعلة',
|
||||
'عن منظومة سيرو ماب والتقنيات المفعلة',
|
||||
style: TextStyle(
|
||||
fontSize: 13.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.urukGoldDark,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
subtitle: const Text(
|
||||
'الكاش الذكي، مفاتيح الأجهزة، والملاحة دون اتصال',
|
||||
style: TextStyle(fontSize: 11, color: AppColors.textSecondary),
|
||||
),
|
||||
trailing: const Icon(Icons.workspace_premium_rounded, size: 20, color: AppColors.urukGoldDark),
|
||||
trailing: const Icon(Icons.info_outline_rounded, size: 20, color: AppColors.appleBlue),
|
||||
),
|
||||
],
|
||||
],
|
||||
|
||||
@@ -75,20 +75,20 @@ class _SplashViewState extends State<SplashView> with SingleTickerProviderStateM
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Luxury Uruk Emblem Container
|
||||
// Luxury Siro Maps Emblem Container
|
||||
Container(
|
||||
width: 114,
|
||||
height: 114,
|
||||
width: 116,
|
||||
height: 116,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF131722),
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
border: Border.all(
|
||||
color: AppColors.urukGold.withValues(alpha: 0.35),
|
||||
color: AppColors.appleBlue.withValues(alpha: 0.35),
|
||||
width: 1.5,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.urukGold.withValues(alpha: 0.22),
|
||||
color: AppColors.appleBlue.withValues(alpha: 0.18),
|
||||
blurRadius: 36,
|
||||
offset: const Offset(0, 14),
|
||||
),
|
||||
@@ -102,7 +102,7 @@ class _SplashViewState extends State<SplashView> with SingleTickerProviderStateM
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
child: Image.asset(
|
||||
'assets/images/siro_uruk_logo.png',
|
||||
'assets/images/siro_maps_logo.png',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
@@ -110,7 +110,7 @@ class _SplashViewState extends State<SplashView> with SingleTickerProviderStateM
|
||||
const SizedBox(height: 24),
|
||||
// App Title
|
||||
Text(
|
||||
'خرائط أوروك',
|
||||
'خرائط سيرو',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w800,
|
||||
@@ -121,104 +121,13 @@ class _SplashViewState extends State<SplashView> with SingleTickerProviderStateM
|
||||
const SizedBox(height: 6),
|
||||
// Subtitle
|
||||
Text(
|
||||
'Uruk Map • منظومة الخرائط والملاحة الذكية',
|
||||
'Siro Map • منظومة الخرائط والملاحة الذكية',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 26),
|
||||
|
||||
// Official Uruk International Prize Award Badge
|
||||
Container(
|
||||
constraints: const BoxConstraints(maxWidth: 340),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 11),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [
|
||||
Color(0xFFFFFDF7),
|
||||
Color(0xFFFFF6D8),
|
||||
],
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: AppColors.urukGoldBorder, width: 1.2),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.urukGold.withValues(alpha: 0.14),
|
||||
blurRadius: 22,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColors.pureWhite,
|
||||
border: Border.all(
|
||||
color: AppColors.urukGold.withValues(alpha: 0.4),
|
||||
width: 1.2,
|
||||
),
|
||||
),
|
||||
child: ClipOval(
|
||||
child: Image.asset(
|
||||
'assets/images/uruk_prize_logo.png',
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.workspace_premium_rounded,
|
||||
size: 16,
|
||||
color: AppColors.urukGoldDark,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
child: Text(
|
||||
'الحائز على جائزة أوروك الدولية',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.urukGoldDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
'مشروع منبثق عن برنامج جوائز أوروك للسيادة الرقمية',
|
||||
style: GoogleFonts.alexandria(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 28),
|
||||
// Regional Sovereignty Pill Badge
|
||||
Container(
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
// 'flutter create' template.
|
||||
|
||||
// The application's name. By default this is also the title of the Flutter window.
|
||||
PRODUCT_NAME = uruk_map
|
||||
PRODUCT_NAME = siro_maps
|
||||
|
||||
// The application's bundle identifier
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.urukmap.app
|
||||
|
||||
// The copyright displayed in application information
|
||||
PRODUCT_COPYRIGHT = Copyright © 2026 com.urukmap. All rights reserved.
|
||||
PRODUCT_COPYRIGHT = Copyright © 2026 Siro Map. All rights reserved.
|
||||
|
||||
@@ -627,10 +627,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
|
||||
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.18"
|
||||
version: "0.12.19"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -643,10 +643,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
||||
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.0"
|
||||
version: "1.18.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1032,10 +1032,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
|
||||
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.9"
|
||||
version: "0.7.11"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -27,7 +27,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('خرائط أوروك'), findsOneWidget);
|
||||
expect(find.text('خرائط سيرو'), findsOneWidget);
|
||||
expect(find.textContaining('v2.4 PRO'), findsOneWidget);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 3000));
|
||||
|
||||