2026-04-12-1

This commit is contained in:
Hamza-Ayed
2026-04-12 22:35:38 +03:00
parent e3799c422c
commit 5ebd7ea3b1
84 changed files with 532 additions and 5136 deletions
+7 -3
View File
@@ -13,7 +13,7 @@ REDIS_HOST=redis
REDIS_PORT=6379
# GraphHopper (Routing)
GRAPH_HOPPER_URL=http://routing:8989
GRAPH_HOPPER_URL=http://routing:8080
# Map Server
TILE_SERVER_URL=http://tileserver:8080
@@ -25,6 +25,10 @@ NODE_ENV=development
# External Location Server Integration (Every 10 days)
# إعدادات الاتصال بسيرفر المواقع الخارجي
LOCATION_SERVER_URL=https://location.intaleq.xyz/location
LOCATION_SERVER_API_KEY=intaleq_secret_2026
LOCATION_SERVER_URL=https://location.intaleq.xyz
LOCATION_SERVER_API_KEY=intaleq_secure_key_2026_jy@kjhk
MAP_API_KEY=zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX
# Telegram Notifications
TELEGRAM_BOT_TOKEN=7618792580:AAE6YAdrgUdcuUu9g8kXveCb-hiO3ECOd1g
TELEGRAM_CHAT_ID=1766663126
+4 -3
View File
@@ -13,10 +13,11 @@ export class ApiKeyGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const apiKeyHeader = request.headers['x-api-key'];
const validApiKey = this.configService.get<string>('API_KEY');
const validApiKey = this.configService.get<string>('MAP_API_KEY') || 'intaleq_secret_2026';
// If API_KEY is set in environment, enforce it
if (validApiKey && apiKeyHeader !== validApiKey) {
// Enforce API key match
if (apiKeyHeader !== validApiKey) {
console.error(`[ApiKeyGuard] Unauthorized. Expected: ${validApiKey}, Received: ${apiKeyHeader}`);
throw new UnauthorizedException('Invalid or missing API Key');
}
+70
View File
@@ -0,0 +1,70 @@
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
@Injectable()
export class TelegramService {
private readonly logger = new Logger(TelegramService.name);
private readonly botToken: string;
private readonly chatId: string;
constructor(private configService: ConfigService) {
this.botToken = this.configService.get<string>('TELEGRAM_BOT_TOKEN') || '';
this.chatId = this.configService.get<string>('TELEGRAM_CHAT_ID') || '';
}
/**
* Send a message to the configured Telegram chat.
* إرسال رسالة إلى دردشة تيليجرام المحددة.
*/
async sendMessage(text: string): Promise<boolean> {
if (!this.botToken || !this.chatId || this.botToken.includes('YOUR_BOT_TOKEN')) {
this.logger.warn('Telegram Bot Token or Chat ID not configured. Skipping notification.');
return false;
}
try {
this.logger.log('Sending report to Telegram...');
const url = `https://api.telegram.org/bot${this.botToken}/sendMessage`;
await axios.post(url, {
chat_id: this.chatId,
text: text,
parse_mode: 'HTML',
});
this.logger.log('✅ Telegram notification sent successfully.');
return true;
} catch (error) {
this.logger.error(`❌ Failed to send Telegram message: ${error.message}`);
if (error.response) {
this.logger.error(`Status: ${error.response.status}, Data: ${JSON.stringify(error.response.data)}`);
}
return false;
}
}
/**
* Formats a summary report for the Inteligence Process.
*/
async sendIntelligenceReport(stats: {
syncResult: number;
updatedSegments: number;
discoveredRoads: number;
totalPoints: number;
days: number;
timeProfiles?: number;
}) {
const message = `
🚀 <b>Intaleq Map Intelligence Report</b>
━━━━━━━━━━━━━━━━━━
📅 <b>Window:</b> Last ${stats.days} days
📥 <b>Tracks Imported:</b> ${stats.syncResult} points
🛣️ <b>Roads Updated:</b> ${stats.updatedSegments} segments
✨ <b>New Roads Found:</b> ${stats.discoveredRoads} candidates
🕒 <b>Time Profiles:</b> ${stats.timeProfiles || 0} buckets
📍 <b>Database Total:</b> ${stats.totalPoints} points
━━━━━━━━━━━━━━━━━━
✅ <i>Deep Sync and Analysis Complete.</i>
`;
return this.sendMessage(message);
}
}
+34 -8
View File
@@ -10,14 +10,40 @@ export class MapsController {
constructor(private readonly mapsService: MapsService) {}
@Get('route')
@ApiOperation({ summary: 'Calculate a route between two points 🚗' })
async getRoute(
@Query('fromLat') fromLat: number,
@Query('fromLng') fromLng: number,
@Query('toLat') toLat: number,
@Query('toLng') toLng: number,
) {
return this.mapsService.getRoute([fromLat, fromLng], [toLat, toLng]);
@ApiOperation({ summary: 'Calculate a route with dynamic waypoints 🚗' })
async getRoute(@Query() query: any) {
const waypoints: [number, number][] = [];
// 1. Extract Origin (fromLat, fromLng)
if (query.fromLat && query.fromLng) {
waypoints.push([parseFloat(query.fromLat), parseFloat(query.fromLng)]);
}
// 2. Extract Intermediate Stops (stop1Lat, stop1Lng, stop2Lat, etc.)
// We sort keys to ensure stops are in order: stop1, stop2, stop3...
const stopKeys = Object.keys(query)
.filter(key => key.startsWith('stop') && key.endsWith('Lat'))
.sort((a, b) => {
const numA = parseInt(a.replace('stop', '').replace('Lat', ''), 10);
const numB = parseInt(b.replace('stop', '').replace('Lat', ''), 10);
return numA - numB;
});
for (const latKey of stopKeys) {
const prefix = latKey.replace('Lat', '');
const lngKey = `${prefix}Lng`;
if (query[latKey] && query[lngKey]) {
waypoints.push([parseFloat(query[latKey]), parseFloat(query[lngKey])]);
}
}
// 3. Extract Destination (toLat, toLng)
if (query.toLat && query.toLng) {
waypoints.push([parseFloat(query.toLat), parseFloat(query.toLng)]);
}
const profile = query.profile || 'car';
return this.mapsService.getRoute(waypoints, profile);
}
@Get('config')
+12 -5
View File
@@ -10,18 +10,25 @@ export class MapsService {
this.graphHopperUrl = this.configService.get('GRAPH_HOPPER_URL', 'http://routing:8080');
}
async getRoute(from: [number, number], to: [number, number]) {
async getRoute(waypoints: [number, number][], profile: string = 'car') {
if (waypoints.length < 2) {
throw new HttpException('At least two waypoints are required', HttpStatus.BAD_REQUEST);
}
try {
// GraphHopper expects [lng, lat] order
const ghPoints = waypoints.map(wp => [wp[1], wp[0]]);
const payload: any = {
points: [[from[1], from[0]], [to[1], to[0]]],
profile: 'car',
points: ghPoints,
profile: profile,
locale: 'en',
calc_points: true,
points_encoded: true,
};
console.log(`Routing Request: ${from} -> ${to} via ${this.graphHopperUrl}`);
const response = await axios.post(`${this.graphHopperUrl}/route`, payload, { timeout: 5000 });
console.log(`Routing Request: ${waypoints.length} points via ${profile} on ${this.graphHopperUrl}`);
const response = await axios.post(`${this.graphHopperUrl}/route`, payload, { timeout: 10000 });
console.log('Routing SUCCESS');
const route = response.data.paths[0];
@@ -0,0 +1,23 @@
import { Entity, Column, PrimaryColumn, Index, CreateDateColumn } from 'typeorm';
@Entity('road_speed_profiles')
@Index(['segmentId', 'hourOfDay', 'dayOfWeek'], { unique: true })
export class RoadSpeedProfile {
@PrimaryColumn()
segmentId: string;
@PrimaryColumn()
hourOfDay: number; // 0-23
@PrimaryColumn()
dayOfWeek: number; // 0-6 (0 = Sunday)
@Column('float', { default: 0 })
averageSpeed: number;
@Column('int', { default: 0 })
sampleCount: number;
@CreateDateColumn()
lastUpdated: Date;
}
-45
View File
@@ -1,45 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
/coverage/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
-30
View File
@@ -1,30 +0,0 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "90673a4eef275d1a6692c26ac80d6d746d41a73a"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 90673a4eef275d1a6692c26ac80d6d746d41a73a
base_revision: 90673a4eef275d1a6692c26ac80d6d746d41a73a
- platform: ios
create_revision: 90673a4eef275d1a6692c26ac80d6d746d41a73a
base_revision: 90673a4eef275d1a6692c26ac80d6d746d41a73a
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
-17
View File
@@ -1,17 +0,0 @@
# flutter_map_demo
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
@@ -1,28 +0,0 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>

Before

Width:  |  Height:  |  Size: 219 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#a855f7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-coffee"><path d="M10 2v2"/><path d="M14 2v2"/><path d="M18 8a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2h-1.08"/><path d="M6 13a7 7 0 1 1 14 0"/><path d="M16 8h-3c0-3 1-3 1-5h-4c0 2 1 2 1 5H6a4 4 0 0 0-4 4v1a4 4 0 0 0 4 4h12a4 4 0 0 0 4-4v-1a4 4 0 0 0-4-4Z"/><path d="M7 21h10"/><path d="M9 17v1"/><path d="M13 17v1"/><path d="M17 17v1"/></svg>

Before

Width:  |  Height:  |  Size: 528 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/><line x1="12" y1="5" x2="12" y2="13"/><line x1="8" y1="9" x2="16" y2="9"/></svg>

Before

Width:  |  Height:  |  Size: 405 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pill"><path d="m10.5 20.5 10-10a4.95 4.95 0 1 0-7-7l-10 10a4.95 4.95 0 1 0 7 7Z"/><path d="m8.5 8.5 7 7"/></svg>

Before

Width:  |  Height:  |  Size: 310 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><circle cx="12" cy="11" r="3"/><path d="M12 14v4"/></svg>

Before

Width:  |  Height:  |  Size: 289 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#f97316" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-utensils"><path d="M3 2v7c0 1.1.9 2 2 2h4a2 2 0 0 0 2-2V2"/><path d="M7 2v20"/><path d="M21 15V2a5 5 0 0 0-5 5v8c0 1.1.9 2 2 2h3Z"/><path d="M18 17v5"/></svg>

Before

Width:  |  Height:  |  Size: 356 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-shopping-bag"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>

Before

Width:  |  Height:  |  Size: 331 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#db2777" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-landmark"><line x1="3" y1="22" x2="21" y2="22"/><line x1="6" y1="18" x2="6" y2="11"/><line x1="10" y1="18" x2="10" y2="11"/><line x1="14" y1="18" x2="14" y2="11"/><line x1="18" y1="18" x2="18" y2="11"/><polygon points="12 2 20 7 4 7 12 2"/></svg>

Before

Width:  |  Height:  |  Size: 444 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-train-front"><path d="M8 3.1V7a4 4 0 0 0 8 0V3.1"/><path d="m9 15-1-1"/><path d="m15 15 1-1"/><path d="M9 19c-2.8 0-5-2.2-5-5V5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v9c0 2.8-2.2 5-5 5Z"/><path d="m8 19-2 3"/><path d="m16 19 2 3"/></svg>

Before

Width:  |  Height:  |  Size: 427 B

-655
View File
@@ -1,655 +0,0 @@
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Intaleq Premium Map V3 - خرائط انطلاقة الذكية</title>
<link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;800&family=Noto+Sans+Arabic:wght@400;700&display=swap');
:root {
--primary: #c0a048;
--primary-dark: #8a6e20;
--accent: #2563eb;
--bg-glass: rgba(255, 255, 255, 0.88);
--shadow: 0 12px 40px rgba(0,0,0,0.12);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Outfit', 'Noto Sans Arabic', sans-serif;
background: #F2EDE4;
overflow: hidden;
color: #342C20;
}
/* ── MAP ── */
#map { width: 100vw; height: 100vh; position: absolute; inset: 0; }
/* ── LOADING OVERLAY ── */
#loading {
display: none; position: fixed; inset: 0;
background: rgba(242,237,228,0.6);
z-index: 2000; align-items: center; justify-content: center;
backdrop-filter: blur(6px);
}
.spinner {
width: 40px; height: 40px;
border: 4px solid rgba(192,160,72,0.15);
border-top: 4px solid var(--primary);
border-radius: 50%;
animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* ── CONTROLS PANEL ── */
.controls {
position: absolute; top: 24px; right: 24px; z-index: 100;
background: var(--bg-glass);
backdrop-filter: blur(14px) saturate(180%);
-webkit-backdrop-filter: blur(14px) saturate(180%);
border-radius: 24px; padding: 28px; width: 380px;
box-shadow: var(--shadow);
border: 1px solid rgba(255,255,255,0.35);
}
.badge {
display: inline-block; padding: 4px 10px; border-radius: 6px;
font-size: 11px; font-weight: 800;
background: var(--primary); color: #fff;
margin-bottom: 12px; text-transform: uppercase; letter-spacing: 1px;
}
.panel-title { font-size: 22px; font-weight: 800; margin-bottom: 6px; color: #18100A; }
.panel-desc { font-size: 13px; color: #584840; margin-bottom: 20px; line-height: 1.55; }
/* ── SEARCH ── */
.search-wrap { position: relative; margin-bottom: 20px; }
.search-wrap input {
width: 100%; padding: 13px 60px 13px 16px;
border-radius: 12px; border: 1.5px solid #ddd;
font-family: inherit; font-size: 14px;
outline: none; transition: border-color 0.25s;
background: rgba(255,255,255,0.7);
}
.search-wrap input:focus { border-color: var(--primary); }
.search-wrap .search-btn {
position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
background: var(--primary); color: #fff;
border: none; padding: 6px 13px; border-radius: 8px;
cursor: pointer; font-size: 12px; font-weight: 700;
transition: background 0.2s;
}
.search-wrap .search-btn:hover { background: var(--primary-dark); }
#search-results {
display: none; max-height: 220px; overflow-y: auto;
background: #fff; border-radius: 12px;
border: 1px solid #eee;
box-shadow: 0 4px 14px rgba(0,0,0,0.06);
margin-top: 8px;
}
.result-item {
padding: 11px 16px; border-bottom: 1px solid #f5f5f5;
cursor: pointer; transition: background 0.15s;
}
.result-item:last-child { border-bottom: none; }
.result-item:hover { background: #fdfaf5; }
.result-item .name { font-weight: 700; font-size: 13px; }
.result-item .meta { font-size: 11px; color: #999; margin-top: 2px; }
/* ── ROUTE BUTTONS ── */
.btn-group { display: flex; flex-direction: column; gap: 10px; }
.btn {
padding: 15px 18px; border: none; border-radius: 14px;
font-size: 14px; font-weight: 700; cursor: pointer;
display: flex; align-items: center; justify-content: space-between;
transition: transform 0.25s, box-shadow 0.25s;
font-family: inherit;
}
.btn .label-sub { font-size: 11px; font-weight: 400; opacity: 0.75; margin-bottom: 2px; }
.btn .icon { font-size: 20px; }
.btn-gold {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
color: #fff;
box-shadow: 0 4px 16px rgba(192,160,72,0.28);
}
.btn-gold:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(192,160,72,0.38); }
.btn-white {
background: #fff; color: #342C20;
border: 1px solid rgba(0,0,0,0.06);
box-shadow: 0 3px 8px rgba(0,0,0,0.04);
}
.btn-white:hover { background: #fdfaf5; transform: translateY(-2px); }
/* ── STATUS BOX ── */
#status {
display: none; margin-top: 20px;
background: rgba(253,250,245,0.7);
border: 1.5px dashed var(--primary);
border-radius: 14px; padding: 16px; font-size: 13px;
line-height: 1.65;
animation: fadeUp 0.35s ease-out;
}
.status-row {
display: flex; justify-content: space-between; margin-top: 6px;
}
.status-row span:last-child { font-weight: 800; }
/* ── DB NAMES INDICATOR ── */
#db-status {
margin-top: 14px; padding: 10px 14px;
background: rgba(192,160,72,0.08);
border-radius: 10px; font-size: 12px; color: #7A5C10;
display: flex; align-items: center; gap: 8px;
}
.dot-gold {
width: 8px; height: 8px; border-radius: 50%;
background: var(--primary); flex-shrink: 0;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
@keyframes fadeUp {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
/* ── BRANDING ── */
.branding {
position: absolute; bottom: 28px; left: 28px; z-index: 100;
background: var(--bg-glass); backdrop-filter: blur(8px);
padding: 10px 18px; border-radius: 12px;
display: flex; align-items: center; gap: 10px;
box-shadow: 0 6px 20px rgba(0,0,0,0.09);
border: 1px solid rgba(255,255,255,0.4);
}
.branding span { font-size: 12px; font-weight: 800; color: #18100A; letter-spacing: 0.5px; }
/* ── CONTEXT MENU ── */
#context-menu {
display: none; position: fixed; z-index: 3000;
background: var(--bg-glass); backdrop-filter: blur(12px);
border-radius: 12px; min-width: 180px;
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
border: 1px solid rgba(255,255,255,0.4);
padding: 6px;
}
.menu-item {
padding: 10px 14px; border-radius: 8px; font-size: 13px; font-weight: 700;
cursor: pointer; display: flex; align-items: center; gap: 10px;
transition: background 0.2s;
}
.menu-item:hover { background: rgba(192,160,72,0.12); color: var(--primary-dark); }
.menu-item .icon { font-size: 16px; }
/* ── ADMIN PANEL ── */
#admin-panel {
position: absolute; bottom: 84px; right: 24px; z-index: 100;
background: var(--bg-glass); backdrop-filter: blur(14px);
border-radius: 20px; padding: 20px; width: 340px;
box-shadow: var(--shadow); border: 1px solid rgba(255,255,255,0.3);
display: none; animation: fadeUp 0.3s;
}
.admin-title { font-size: 16px; font-weight: 800; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
.admin-close { cursor: pointer; opacity: 0.5; margin-right: auto; font-size: 18px; }
.delete-group { margin-top: 15px; }
.delete-group label { display: block; font-size: 11px; font-weight: 700; margin-bottom: 6px; opacity: 0.7; }
.delete-group input, .delete-group select {
width: 100%; padding: 10px; border-radius: 8px; border: 1.5px solid #eee;
font-size: 13px; margin-bottom: 10px; outline: none;
}
.delete-group input:focus { border-color: #c0392b; }
.btn-delete {
width: 100%; padding: 10px; background: #c0392b; color: #fff; border: none;
border-radius: 10px; font-weight: 800; cursor: pointer;
}
#toggle-admin {
position: absolute; top: 110px; left: 10px; z-index: 100;
background: var(--bg-glass); border: none; border-radius: 50%;
width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
box-shadow: var(--shadow); cursor: pointer; font-size: 20px;
}
/* ── SCROLLBAR ── */
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--primary); border-radius: 10px; }
</style>
</head>
<body>
<!-- MAP -->
<div id="map"></div>
<!-- LOADING -->
<div id="loading">
<div style="text-align:center">
<div class="spinner" style="margin: 0 auto 14px;"></div>
<strong style="color:var(--primary-dark)">جاري حساب المسار الذكي...</strong>
</div>
</div>
<!-- BRANDING -->
<div class="branding">
<img src="/intaleq-logo.png" alt="Logo" style="height:22px" onerror="this.style.display='none'">
<span>INTALEQ PREMIUM MAPS</span>
</div>
<!-- CONTROLS -->
<div class="controls">
<div class="badge">v3.1.0</div>
<div class="panel-title">🗺️ خرائط انطلاقة الذكية</div>
<p class="panel-desc">حلول جغرافية متقدمة لمنطقة الشرق الأوسط وشمال أفريقيا — عرض ثلاثي الأبعاد وأسماء مباشرة من قاعدة البيانات.</p>
<!-- SEARCH -->
<div class="search-wrap">
<input id="search-input" type="text" placeholder="ابحث عن مكان... (مسجد، مستشفى، ...)" />
<button class="search-btn" onclick="performSearch()">بحث</button>
<div id="search-results"></div>
</div>
<!-- ROUTE BUTTONS -->
<div class="btn-group">
<button class="btn btn-gold" onclick="handleRoute('LEVANT')">
<div>
<div class="label-sub">مسار مقترح — سوريا</div>
<span>عمّان ← دمشق</span>
</div>
<span class="icon">🚀</span>
</button>
<button class="btn btn-white" onclick="handleRoute('EGYPT')">
<div>
<div class="label-sub">مسار مقترح — مصر</div>
<span>شبرا ← الزمالك</span>
</div>
<span class="icon">🇪🇬</span>
</button>
</div>
<!-- STATUS -->
<div id="status"></div>
<!-- DB NAMES INDICATOR -->
<div id="db-status">
<div class="dot-gold"></div>
<span id="db-status-text">جاري تحميل الأسماء من قاعدة البيانات...</span>
</div>
</div>
<!-- TOGGLE ADMIN -->
<button id="toggle-admin" onclick="toggleAdminPanel()" title="إدارة البيانات">⚙️</button>
<!-- CONTEXT MENU -->
<div id="context-menu">
<div class="menu-item" onclick="copyCoords()">
<span class="icon">📋</span> <span>نسخ الإحداثيات</span>
</div>
<div class="menu-item" id="menu-delete-btn" style="color:#c0392b" onclick="deleteFromContext()">
<span class="icon">🗑️</span> <span>حذف هذا الموقع</span>
</div>
</div>
<!-- ADMIN PANEL -->
<div id="admin-panel">
<div class="admin-title">
<span>🛡️ إدارة البيانات</span>
<span class="admin-close" onclick="toggleAdminPanel()">×</span>
</div>
<div class="delete-group">
<label>حذف موقع بواسطة الاسم</label>
<input type="text" id="admin-delete-name" placeholder="أدخل اسم الموقع..." />
<label>الدولة</label>
<select id="admin-delete-country">
<option value="syria">سوريا</option>
<option value="jordan">الأردن</option>
<option value="egypt">مصر</option>
</select>
<button class="btn-delete" onclick="handleAdminDelete()">حذف الموقع نهائياً</button>
</div>
<div id="admin-info" style="font-size:11px; margin-top:10px; opacity:0.6; text-align:center"></div>
</div>
<script>
/* ───────────────────────────────────────────
CONFIG
─────────────────────────────────────────── */
const API_BASE = 'https://map-saas.intaleqapp.com';
const API_KEY = 'intaleq_secret_2026';
const HEADERS = { 'x-api-key': API_KEY };
const ROUTES = {
LEVANT: {
from: [35.9106, 31.9539], // Amman
to: [36.2765, 33.5138], // Damascus
center: [36.09, 32.73],
zoom: 8,
color: '#c0a048'
},
EGYPT: {
from: [31.2427, 30.0931], // Shoubra
to: [31.2201, 30.0619], // Zamalek
center: [31.23, 30.07],
zoom: 13,
color: '#2563eb'
}
};
/* ───────────────────────────────────────────
MAP INIT
─────────────────────────────────────────── */
maplibregl.setRTLTextPlugin(
'https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.js',
null, true
);
const map = new maplibregl.Map({
container: 'map',
center: ROUTES.LEVANT.center,
zoom: ROUTES.LEVANT.zoom,
style: './style.json', // ← style.json fixed (no duplicate IDs)
pitch: 0,
bearing: 0,
attributionControl: false
});
map.addControl(new maplibregl.NavigationControl(), 'bottom-right');
/* ───────────────────────────────────────────
MAP LOAD — count DB names shown on map
─────────────────────────────────────────── */
map.on('load', () => {
console.log('[Intaleq] Map loaded — style v3.1.0');
loadDBNamesStatus();
});
/*
* Fetch the same GeoJSON the style uses for intaleq_dynamic_pois
* and report how many names were loaded on the map.
*/
async function loadDBNamesStatus() {
const statusEl = document.getElementById('db-status-text');
try {
const res = await fetch(`${API_BASE}/api/geocoding/geojson`, { headers: HEADERS });
const data = await res.json();
const count = data?.features?.length ?? 0;
statusEl.textContent = count > 0
? `✅ ${count} اسم مُحمَّل من قاعدة البيانات على الخريطة`
: '⚠️ لا توجد أسماء في قاعدة البيانات حتى الآن';
// Refresh the source in case MapLibre cached an empty response
if (count > 0 && map.getSource('intaleq_dynamic_pois')) {
map.getSource('intaleq_dynamic_pois').setData(data);
}
} catch (err) {
console.warn('[Intaleq] DB names fetch failed:', err);
statusEl.textContent = '⚠️ تعذّر الاتصال بقاعدة البيانات';
}
}
/* ───────────────────────────────────────────
POLYLINE DECODER
─────────────────────────────────────────── */
function decodePoly(str) {
let i = 0, lat = 0, lng = 0, out = [];
while (i < str.length) {
let byte, shift = 0, result = 0;
do { byte = str.charCodeAt(i++) - 63; result |= (byte & 0x1f) << shift; shift += 5; } while (byte >= 0x20);
lat += (result & 1) ? ~(result >> 1) : (result >> 1);
shift = 0; result = 0;
do { byte = str.charCodeAt(i++) - 63; result |= (byte & 0x1f) << shift; shift += 5; } while (byte >= 0x20);
lng += (result & 1) ? ~(result >> 1) : (result >> 1);
out.push([lng / 1e5, lat / 1e5]);
}
return out;
}
/* ───────────────────────────────────────────
ROUTING
─────────────────────────────────────────── */
async function handleRoute(region) {
const cfg = ROUTES[region];
const loading = document.getElementById('loading');
const status = document.getElementById('status');
loading.style.display = 'flex';
status.style.display = 'none';
try {
const url = `${API_BASE}/api/maps/route`
+ `?fromLat=${cfg.from[1]}&fromLng=${cfg.from[0]}`
+ `&toLat=${cfg.to[1]}&toLng=${cfg.to[0]}`;
const res = await fetch(url, { headers: HEADERS });
const data = await res.json();
if (data.statusCode >= 400) throw new Error(data.message || 'Routing error');
const coords = typeof data.points === 'string'
? decodePoly(data.points)
: data.points;
if (!coords?.length) throw new Error('No route points returned');
// Add or update route layer
const geojson = { type: 'Feature', geometry: { type: 'LineString', coordinates: coords } };
if (map.getSource('route')) {
map.getSource('route').setData(geojson);
map.setPaintProperty('route-line', 'line-color', cfg.color);
} else {
map.addSource('route', { type: 'geojson', data: geojson });
map.addLayer({
id: 'route-line', type: 'line', source: 'route',
layout: { 'line-join': 'round', 'line-cap': 'round' },
paint: { 'line-color': cfg.color, 'line-width': 7, 'line-opacity': 0.88 }
});
}
// Fit map to route
const bounds = coords.reduce(
(b, c) => b.extend(c),
new maplibregl.LngLatBounds(coords[0], coords[0])
);
map.fitBounds(bounds, { padding: 110, duration: 1800 });
// Show summary
setTimeout(() => {
status.style.display = 'block';
status.innerHTML = `
<div style="font-weight:700;color:var(--primary-dark);margin-bottom:8px">🏁 ملخص الرحلة</div>
<div class="status-row"><span>المسافة:</span><span>${(data.distance / 1000).toFixed(1)} كم</span></div>
<div class="status-row"><span>الوقت المتوقع:</span><span>${Math.round(data.duration / 60)} دقيقة</span></div>
`;
}, 600);
} catch (err) {
console.error('[Intaleq] Route error:', err);
status.style.display = 'block';
status.innerHTML = `<span style="color:#c0392b">⚠️ تعذّر تحميل المسار: ${err.message}</span>`;
} finally {
loading.style.display = 'none';
}
}
/* ───────────────────────────────────────────
SEARCH
─────────────────────────────────────────── */
let searchMarkers = [];
async function performSearch() {
const q = document.getElementById('search-input').value.trim();
const resultsEl = document.getElementById('search-results');
if (!q) return;
const center = map.getCenter();
const url = `${API_BASE}/api/geocoding/search`
+ `?q=${encodeURIComponent(q)}`
+ `&lat=${center.lat}&lng=${center.lng}&radius=20000`;
resultsEl.style.display = 'block';
resultsEl.innerHTML = '<div class="result-item"><span class="meta">جاري البحث...</span></div>';
// Clear old markers
searchMarkers.forEach(m => m.remove());
searchMarkers = [];
try {
const res = await fetch(url, { headers: HEADERS });
const data = await res.json();
if (!data.results?.length) {
resultsEl.innerHTML = '<div class="result-item"><span class="meta">لا توجد نتائج.</span></div>';
return;
}
resultsEl.innerHTML = '';
data.results.forEach(place => {
const lng = parseFloat(place.longitude);
const lat = parseFloat(place.latitude);
const name = place.name_ar || place.name;
const dist = place.distance ? `${(place.distance / 1000).toFixed(2)} كم` : '';
// Result row
const item = document.createElement('div');
item.className = 'result-item';
item.innerHTML = `
<div class="name">${name}</div>
<div class="meta">${place.category || ''} ${dist ? '• ' + dist : ''}</div>
`;
item.onclick = () => map.flyTo({ center: [lng, lat], zoom: 16 });
resultsEl.appendChild(item);
// Map marker — gold for DB entries, blue for OSM
const isDB = place.source === 'user_submitted' || place.source === 'intaleq_db';
const color = isDB ? '#c0a048' : '#2563eb';
let popupHTML = `<strong>${name}</strong><br><span style="font-size:12px;color:#888">${place.category || ''}</span>`;
if (isDB) {
popupHTML += `<hr style="margin:8px 0; border:0; border-top:1px solid #eee">
<button onclick="directDelete(${place.id})" style="background:#c0392b; color:#fff; border:0; padding:4px 8px; border-radius:4px; font-size:10px; cursor:pointer; width:100%">حذف القيد</button>`;
}
const marker = new maplibregl.Marker({ color })
.setLngLat([lng, lat])
.setPopup(new maplibregl.Popup({ offset: 25 })
.setHTML(popupHTML))
.addTo(map);
searchMarkers.push(marker);
});
} catch (err) {
console.error('[Intaleq] Search error:', err);
resultsEl.innerHTML = '<div class="result-item" style="color:#c0392b">⚠️ فشل الاتصال بخدمة البحث.</div>';
}
}
// Enter key triggers search
document.getElementById('search-input').addEventListener('keydown', e => {
if (e.key === 'Enter') performSearch();
});
/* ───────────────────────────────────────────
INTERACTIVE MANAGEMENT
─────────────────────────────────────────── */
let lastRightClick = null;
map.on('contextmenu', (e) => {
lastRightClick = e.lngLat;
const menu = document.getElementById('context-menu');
menu.style.display = 'block';
menu.style.left = e.point.x + 'px';
menu.style.top = e.point.y + 'px';
});
document.addEventListener('click', () => {
document.getElementById('context-menu').style.display = 'none';
});
function copyCoords() {
if (!lastRightClick) return;
const txt = `${lastRightClick.lat.toFixed(7)}, ${lastRightClick.lng.toFixed(7)}`;
navigator.clipboard.writeText(txt);
alert('تم نسخ الإحداثيات: ' + txt);
}
async function deleteFromContext() {
if (!lastRightClick) return;
const country = prompt('يرجى كتابة الدولة للتأكيد (syria, jordan, egypt):', 'syria');
if (!country) return;
const name = prompt('يرجى كتابة اسم الموقع لحذفه نهائياً:');
if (!name) return;
await apiDelete(name, country);
}
function toggleAdminPanel() {
const p = document.getElementById('admin-panel');
p.style.display = p.style.display === 'block' ? 'none' : 'block';
}
async function handleAdminDelete() {
const name = document.getElementById('admin-delete-name').value.trim();
const country = document.getElementById('admin-delete-country').value;
if (!name) return alert('يرجى إدخال الاسم');
if (!confirm(`هل أنت متأكد من حذف 모든 المواقع المسمى "${name}" في ${country}؟`)) return;
await apiDelete(name, country);
}
async function directDelete(id) {
const country = prompt('يرجى تحديد الدولة (syria, jordan, egypt):', 'syria');
if (!country) return;
if (!confirm('هل أنت متأكد من حذف هذا القيد؟')) return;
try {
const res = await fetch(`${API_BASE}/api/geocoding/places?id=${id}&country=${country}`, {
method: 'DELETE',
headers: HEADERS
});
const data = await res.json();
if (data.success) {
alert('تم الحذف بنجاح');
location.reload();
}
} catch (err) {
alert('فشل الحذف');
}
}
async function apiDelete(name, country) {
const info = document.getElementById('admin-info');
info.textContent = 'جاري الحذف...';
try {
const res = await fetch(`${API_BASE}/api/geocoding/places?name=${encodeURIComponent(name)}&country=${country}`, {
method: 'DELETE',
headers: HEADERS
});
const data = await res.json();
if (data.success) {
info.textContent = `✅ تم حذف ${data.affected} قيد بنجاح.`;
setTimeout(() => location.reload(), 2000);
} else {
info.textContent = '❌ فشل الحذف.';
}
} catch (err) {
info.textContent = '❌ خطأ في الاتصال بالسيرفر.';
}
}
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
-34
View File
@@ -1,34 +0,0 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>
@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
-43
View File
@@ -1,43 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
-29
View File
@@ -1,29 +0,0 @@
PODS:
- Flutter (1.0.0)
- MapLibre (6.19.1)
- maplibre_gl (0.25.0):
- Flutter
- MapLibre (= 6.19.1)
DEPENDENCIES:
- Flutter (from `Flutter`)
- maplibre_gl (from `.symlinks/plugins/maplibre_gl/ios`)
SPEC REPOS:
trunk:
- MapLibre
EXTERNAL SOURCES:
Flutter:
:path: Flutter
maplibre_gl:
:path: ".symlinks/plugins/maplibre_gl/ios"
SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
MapLibre: 7f24faba45439f80ccb0f83393c29fa32cb81952
maplibre_gl: a2114567cbd1065866614fbd34dfb75ab782aaa2
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
COCOAPODS: 1.16.2
@@ -1,735 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
4BE23B066A13A014157E904D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058CD2C6B2C8A85A2BDF62A5 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
B5FECC95BFE8757C114347E9 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 874CE6A5A1A624AFBD9361F4 /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
058CD2C6B2C8A85A2BDF62A5 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4195AF675A461A4213E377AC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
62C8E72C74592E2BF38F3056 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
874CE6A5A1A624AFBD9361F4 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9D97D2B0A74C620EE26B686D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
A1401E12C06CD482F4321CED /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
D7B0A18DAD95D31108F46FD2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
FCC00A86E01908E02E2ADC63 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5D5633A59A3A5FE0F880CD2C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B5FECC95BFE8757C114347E9 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4BE23B066A13A014157E904D /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
09BB6ABAEA8119095A906E43 /* Frameworks */ = {
isa = PBXGroup;
children = (
058CD2C6B2C8A85A2BDF62A5 /* Pods_Runner.framework */,
874CE6A5A1A624AFBD9361F4 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
09F0900B6F1C12DF0C6D5DEE /* Pods */ = {
isa = PBXGroup;
children = (
9D97D2B0A74C620EE26B686D /* Pods-Runner.debug.xcconfig */,
4195AF675A461A4213E377AC /* Pods-Runner.release.xcconfig */,
FCC00A86E01908E02E2ADC63 /* Pods-Runner.profile.xcconfig */,
A1401E12C06CD482F4321CED /* Pods-RunnerTests.debug.xcconfig */,
D7B0A18DAD95D31108F46FD2 /* Pods-RunnerTests.release.xcconfig */,
62C8E72C74592E2BF38F3056 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
09F0900B6F1C12DF0C6D5DEE /* Pods */,
09BB6ABAEA8119095A906E43 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
DF8661F6819655F3745949C5 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
5D5633A59A3A5FE0F880CD2C /* Frameworks */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
AAC69DE719C09702E07493F4 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
FB2BB4545B8EC3C32C5AFC5D /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
AAC69DE719C09702E07493F4 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
DF8661F6819655F3745949C5 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
FB2BB4545B8EC3C32C5AFC5D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 63CVT8G5P8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterMapDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A1401E12C06CD482F4321CED /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterMapDemo.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D7B0A18DAD95D31108F46FD2 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterMapDemo.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 62C8E72C74592E2BF38F3056 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterMapDemo.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 63CVT8G5P8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterMapDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 63CVT8G5P8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterMapDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -1,27 +0,0 @@
import Flutter
import UIKit
import MapLibre
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Increase Ambient Cache Size to 5GB (5 * 1024 * 1024 * 1024 bytes)
// This allows the app to store more map tiles locally after the first fetch.
Task {
do {
try await MLNOfflineStorage.shared.setMaximumAmbientCacheSize(5368709120)
} catch {
NSLog("Failed to set ambient cache size: %s", String(describing: error))
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
}
@@ -1,122 +0,0 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

@@ -1,5 +0,0 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Flutter Map Demo</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>flutter_map_demo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -1 +0,0 @@
#import "GeneratedPluginRegistrant.h"
@@ -1,6 +0,0 @@
import Flutter
import UIKit
class SceneDelegate: FlutterSceneDelegate {
}
@@ -1,12 +0,0 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
-556
View File
@@ -1,556 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart' show kIsWeb;
void main() {
runApp(
const MaterialApp(home: MapScreen(), debugShowCheckedModeBanner: false),
);
}
class MapScreen extends StatefulWidget {
const MapScreen({super.key});
@override
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
MapLibreMapController? mapController;
bool isLoading = false;
String info = '📍 نظام انطلق المتكامل';
bool styleLoaded = false;
bool isSyncing = false;
bool isContinuousSyncEnabled = true; // Default to ON for premium experience
double syncProgress = 0.0;
// --- Feature: Custom Car Marker ---
Future<void> _addCarMarker() async {
if (!styleLoaded || mapController == null) return;
try {
// Load the car icon image (from network for quick demo)
final ByteData bytes = await NetworkAssetBundle(
Uri.parse(
'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Car_icon_blue.png/64px-Car_icon_blue.png',
),
).load('');
final Uint8List list = bytes.buffer.asUint8List();
await mapController!.addImage("car-icon", list);
await mapController!.addSymbol(
SymbolOptions(
geometry: const LatLng(33.513, 36.276), // Damascus city center
iconImage: "car-icon",
iconSize: 0.5,
textField: "سيارة انطلاقة #101",
textOffset: const Offset(0, 2),
textColor: "#3b82f6",
textHaloColor: "#ffffff",
textHaloWidth: 2,
),
);
setState(() => info = '✅ تمت إضافة علامة السيارة');
} catch (e) {
setState(() => info = 'خطأ في إضافة العلامة: $e');
}
}
// --- Feature: Polylines (Lines) ---
Future<void> _addSampleLine() async {
if (!styleLoaded || mapController == null) return;
await mapController!.addLine(
LineOptions(
geometry: [
const LatLng(33.515, 36.270),
const LatLng(33.520, 36.280),
const LatLng(33.510, 36.290),
],
lineColor: "#f59e0b",
lineWidth: 5.0,
lineOpacity: 0.8,
),
);
setState(() => info = '✅ تمت إضافة خط مسار');
}
// --- Feature: Polygons (Geofence) ---
Future<void> _addSamplePolygon() async {
if (!styleLoaded || mapController == null) return;
await mapController!.addFill(
FillOptions(
geometry: [
[
const LatLng(33.518, 36.273),
const LatLng(33.522, 36.273),
const LatLng(33.522, 36.3),
const LatLng(33.518, 36.4),
const LatLng(33.518, 36.273),
],
],
fillColor: "#10b981",
fillOpacity: 0.3,
fillOutlineColor: "#065f46",
),
);
setState(() => info = '✅ تمت إضافة سياج جغرافي');
}
// --- Feature: Circles ---
Future<void> _addSampleCircle() async {
if (!styleLoaded || mapController == null) return;
await mapController!.addCircle(
CircleOptions(
geometry: const LatLng(33.512, 36.280),
circleColor: "#ef4444",
circleRadius: 15.0,
circleOpacity: 0.6,
circleStrokeColor: "#ffffff",
circleStrokeWidth: 2.0,
),
);
setState(() => info = '✅ تمت إضافة نقطة محيطية');
}
// --- Feature: Routing ---
Future<void> computeRoute() async {
if (!styleLoaded || mapController == null) return;
setState(() {
isLoading = true;
info = '⚡ جاري حساب المسار...';
});
try {
final res = await http.get(
Uri.parse(
'https://map-saas.intaleqapp.com/api/maps/route?fromLat=33.513&fromLng=36.276&toLat=33.530&toLng=36.310',
),
headers: {'x-api-key': 'intaleq_secret_2026'},
);
final data = json.decode(res.body);
final pts = _decodePoly(data['points']);
await mapController?.clearLines();
await mapController?.addLine(
LineOptions(geometry: pts, lineColor: "#3b82f6", lineWidth: 6.0),
);
final latList = pts.map((p) => p.latitude).toList()..sort();
final lngList = pts.map((p) => p.longitude).toList()..sort();
mapController?.animateCamera(
CameraUpdate.newLatLngBounds(
LatLngBounds(
southwest: LatLng(latList.first, lngList.first),
northeast: LatLng(latList.last, lngList.last),
),
left: 50,
right: 50,
top: 100,
bottom: 100,
),
);
setState(
() => info =
'🏁 ${(data['distance'] / 1000).toStringAsFixed(1)} كم | ${(data['duration'] / 60).toStringAsFixed(0)} دقيقة',
);
} catch (e) {
setState(() => info = 'خطأ: $e');
} finally {
setState(() => isLoading = false);
}
}
// --- Feature: Fetch and Display Saved Places ---
Future<void> _fetchUserPlaces() async {
if (!styleLoaded || mapController == null) return;
try {
final res = await http.get(
Uri.parse('https://map-saas.intaleqapp.com/api/geocoding/places'),
headers: {'x-api-key': 'intaleq_secret_2026'},
);
if (res.statusCode == 200) {
final List<dynamic> data = json.decode(res.body);
await mapController?.clearSymbols();
for (var place in data) {
final lat = double.tryParse(place['latitude'].toString());
final lng = double.tryParse(place['longitude'].toString());
if (lat != null && lng != null) {
await mapController?.addSymbol(
SymbolOptions(
geometry: LatLng(lat, lng),
iconImage:
"marker-15", // Default MapLibre icon if using standard style
iconSize: 1.5,
textField: place['name_ar'] ?? place['name'],
textOffset: const Offset(0, 1.5),
textColor: "#1e293b",
textHaloColor: "#ffffff",
textHaloWidth: 2,
),
);
}
}
setState(() => info = '📍 تم تحميل ${data.length} موقع من النظام');
}
} catch (e) {
debugPrint('Error fetching places: $e');
}
}
// --- Feature: Offline Map Caching (Mobile Only) ---
Future<void> _downloadCurrentRegion() async {
if (kIsWeb) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'التحميل اليدوي غير متاح على المتصفح (المتصفح يستخدم التخزين المؤقت للمتصفح تلقائياً)',
),
),
);
return;
}
if (mapController == null) return;
final region = await mapController!.getVisibleRegion();
final zoom = mapController!.cameraPosition?.zoom ?? 14.0;
setState(() {
isLoading = true;
info = '⬇️ جاري بدء التحميل...';
});
try {
// Create an offline region for current view
// Zoom levels from current zoom -1 to +2
await downloadOfflineRegion(
OfflineRegionDefinition(
bounds: region,
// تم التعديل هنا: محرك iOS يتطلب رابط إنترنت (URL) حقيقي لعملية الـ Offline
mapStyleUrl:
"https://map-saas.intaleqapp.com/styles/style.json", // يرجى التأكد من رفع ملف الستايل الخاص بك على هذا الرابط
minZoom: zoom.floor() - 1.0,
maxZoom: zoom.floor() + 2.0,
),
metadata: {
'name': 'Manual Download ${DateTime.now().toIso8601String()}',
},
);
setState(() => info = '✅ بدأ تحميل الخرائط لجهازك (Mobile Only)');
} catch (e) {
setState(() => info = '❌ خطأ في التحميل: $e');
} finally {
setState(() => isLoading = false);
}
}
Future<void> _clearMapCache() async {
if (kIsWeb) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'الرجاء مسح بيانات المتصفح (Browser Cache) لإفراغ الذاكرة',
),
),
);
return;
}
// On mobile, we can list and delete regions
// For now, simple info update
setState(() => info = '🗑️ تم إرسال طلب مسح الذاكرة المؤقتة');
}
// --- Feature: Automatic Damascus Sync (Mobile Only) ---
Future<void> _initAutoOfflineSync() async {
if (kIsWeb) return;
try {
// Damascus City Center Bounds roughly +/- 0.1 deg
final damascusBounds = LatLngBounds(
southwest: const LatLng(33.473, 36.226),
northeast: const LatLng(33.583, 36.356),
);
setState(() {
isSyncing = true;
info = '🔄 جاري تأمين خريطة دمشق (Offline)...';
});
await downloadOfflineRegion(
OfflineRegionDefinition(
bounds: damascusBounds,
mapStyleUrl: "https://map-saas.intaleqapp.com/styles/style.json",
minZoom: 0.0,
maxZoom: 16.0, // High detail for Damascus
),
metadata: {'name': 'Damascus_Auto_Sync'},
// onHttpError: (error) => debugPrint('Sync HTTP Error: $error'),
// onTileError: (error) => debugPrint('Sync Tile Error: $error'),
);
setState(() {
isSyncing = false;
info = '✅ تم تأمين دمشق بالكامل للعمل أوفلاين';
});
} catch (e) {
debugPrint('Sync failed: $e');
setState(() => isSyncing = false);
}
}
// --- Feature: Continuous Background Sync (on move) ---
Future<void> _handleCameraIdleSync() async {
if (kIsWeb || !isContinuousSyncEnabled || mapController == null) return;
final bounds = await mapController!.getVisibleRegion();
final zoom = mapController!.cameraPosition?.zoom ?? 14.0;
debugPrint('Continuous Sync: Triggering for new view at zoom $zoom');
// Silent download for the current region
// We don't update 'info' here to keep it subtle, or just use a small indicator
try {
await downloadOfflineRegion(
OfflineRegionDefinition(
bounds: bounds,
mapStyleUrl: "https://map-saas.intaleqapp.com/styles/style.json",
minZoom: zoom.floor() - 1.0,
maxZoom: zoom.floor() + 2.0,
),
metadata: {'name': 'Auto_Area_${DateTime.now().millisecondsSinceEpoch}'},
);
} catch (e) {
debugPrint('Silent sync error (normal if redundant): $e');
}
}
List<LatLng> _decodePoly(dynamic p) {
if (p is String) {
var l = <LatLng>[];
int index = 0, lat = 0, lng = 0;
while (index < p.length) {
int b, shift = 0, res = 0;
do {
b = p.codeUnitAt(index++) - 63;
res |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
lat += (res & 1) != 0 ? ~(res >> 1) : (res >> 1);
shift = 0;
res = 0;
do {
b = p.codeUnitAt(index++) - 63;
res |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
lng += (res & 1) != 0 ? ~(res >> 1) : (res >> 1);
l.add(LatLng(lat / 1e5, lng / 1e5));
}
return l;
} else if (p is List) {
return (p as List)
.map<LatLng>((e) => LatLng(e[1].toDouble(), e[0].toDouble()))
.toList();
}
return [];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Intaleq Advanced Maps',
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
),
centerTitle: true,
backgroundColor: const Color(0xFF0f172a),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(color: Color(0xFF0f172a)),
child: Center(
child: Text(
'أدوات انطلاقة المتقدمة',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
ListTile(
leading: const Icon(Icons.location_on, color: Colors.blue),
title: const Text('إضافة علامة سيارة'),
onTap: () {
Navigator.pop(context);
_addCarMarker();
},
),
ListTile(
leading: const Icon(Icons.timeline, color: Colors.orange),
title: const Text('رسم خط مسار (Line)'),
onTap: () {
Navigator.pop(context);
_addSampleLine();
},
),
ListTile(
leading: const Icon(Icons.layers, color: Colors.green),
title: const Text('رسم سياج جغرافي (Polygon)'),
onTap: () {
Navigator.pop(context);
_addSamplePolygon();
},
),
ListTile(
leading: const Icon(
Icons.radio_button_checked,
color: Colors.red,
),
title: const Text('رسم دائرة (Circle)'),
onTap: () {
Navigator.pop(context);
_addSampleCircle();
},
),
const Divider(),
ListTile(
leading: const Icon(Icons.refresh, color: Colors.blue),
title: const Text('تحديث المواقع المسجلة'),
onTap: () {
Navigator.pop(context);
_fetchUserPlaces();
},
),
ListTile(
leading: const Icon(Icons.directions, color: Colors.blueAccent),
title: const Text('اختبار المسار التلقائي'),
onTap: () {
Navigator.pop(context);
computeRoute();
},
),
const Divider(),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
'إدارة الخرائط (Offline)',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey,
),
),
),
ListTile(
leading: Icon(
Icons.download_for_offline,
color: kIsWeb ? Colors.grey : Colors.green,
),
title: const Text('تحميل النطاق الحالي للجهاز'),
onTap: () {
Navigator.pop(context);
_downloadCurrentRegion();
},
),
SwitchListTile(
secondary: Icon(Icons.sync, color: kIsWeb ? Colors.grey : Colors.blue),
title: const Text('المزامنة المستمرة (Dynamic Sync)'),
subtitle: const Text('حفظ أي منطقة يتم استكشافها تلقائياً', style: TextStyle(fontSize: 10)),
value: isContinuousSyncEnabled,
onChanged: kIsWeb ? null : (val) => setState(() => isContinuousSyncEnabled = val),
),
ListTile(
leading: Icon(
Icons.delete_sweep,
color: kIsWeb ? Colors.grey : Colors.redAccent,
),
title: const Text('مسح الذاكرة المؤقتة'),
onTap: () {
Navigator.pop(context);
_clearMapCache();
},
),
const Divider(),
ListTile(
leading: const Icon(Icons.delete_forever, color: Colors.grey),
title: const Text('مسح كافة البيانات (UI)'),
onTap: () {
Navigator.pop(context);
mapController?.clearLines();
mapController?.clearSymbols();
mapController?.clearFills();
mapController?.clearCircles();
},
),
],
),
),
body: Stack(
children: [
MapLibreMap(
styleString: "assets/style.json",
initialCameraPosition: const CameraPosition(
target: LatLng(33.513, 36.276),
zoom: 14,
),
onMapCreated: (MapLibreMapController c) => mapController = c,
onStyleLoadedCallback: () async {
setState(() => styleLoaded = true);
// Load Premium Icons into the Map Controller
final icons = ['hospital', 'police', 'pharmacy', 'restaurant', 'cafe', 'shop', 'tourist', 'train', 'arrow'];
for (final icon in icons) {
try {
final ByteData bytes = await rootBundle.load('assets/icons/$icon.svg');
await mapController?.addImage(icon, bytes.buffer.asUint8List());
} catch (e) {
debugPrint('Error loading asset icon $icon: $e');
}
}
_fetchUserPlaces();
_initAutoOfflineSync();
},
onCameraIdle: _handleCameraIdleSync, // Trigger continuous sync when movement stops
),
if (!styleLoaded)
Container(
color: const Color(0xFFf8f9fa),
child: const Center(child: CircularProgressIndicator()),
),
Positioned(
top: 10,
left: 10,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(30),
),
child: Text(
info,
style: const TextStyle(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.bold,
),
),
),
),
if (isLoading) const Center(child: CircularProgressIndicator()),
],
),
);
}
}
-338
View File
@@ -1,338 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff
url: "https://pub.dev"
source: hosted
version: "4.0.9"
async:
dependency: transitive
description:
name: async
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
url: "https://pub.dev"
source: hosted
version: "2.13.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted
version: "1.4.1"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
url: "https://pub.dev"
source: hosted
version: "1.0.9"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
ffi:
dependency: transitive
description:
name: ffi
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: "direct main"
description:
name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
image:
dependency: transitive
description:
name: image
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
url: "https://pub.dev"
source: hosted
version: "4.8.0"
intl:
dependency: transitive
description:
name: intl
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
url: "https://pub.dev"
source: hosted
version: "0.20.2"
latlong2:
dependency: "direct main"
description:
name: latlong2
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
url: "https://pub.dev"
source: hosted
version: "0.9.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
lints:
dependency: transitive
description:
name: lints
sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
maplibre_gl:
dependency: "direct main"
description:
name: maplibre_gl
sha256: d9773555ae4ebab94bbc3ae2176b077cfda486ec729eefe01e1613f164cb8410
url: "https://pub.dev"
source: hosted
version: "0.25.0"
maplibre_gl_platform_interface:
dependency: transitive
description:
name: maplibre_gl_platform_interface
sha256: bd7de401dea24dd7e8a6f2fa736ddee7dbbee3e24a9027f0afdd619994702047
url: "https://pub.dev"
source: hosted
version: "0.25.0"
maplibre_gl_web:
dependency: transitive
description:
name: maplibre_gl_web
sha256: af0e48bf96e8dd99f8b958a1953126971eb8a0527b9735441d4f24df3913f5a2
url: "https://pub.dev"
source: hosted
version: "0.25.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.13.0"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
url: "https://pub.dev"
source: hosted
version: "7.0.2"
posix:
dependency: transitive
description:
name: posix
sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07"
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
url: "https://pub.dev"
source: hosted
version: "1.10.2"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.9"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.2.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
xml:
dependency: transitive
description:
name: xml
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
url: "https://pub.dev"
source: hosted
version: "6.6.1"
sdks:
dart: ">=3.11.0 <4.0.0"
flutter: ">=3.22.0"
-91
View File
@@ -1,91 +0,0 @@
name: flutter_map_demo
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.11.0
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
latlong2: ^0.9.1
http: ^1.6.0
maplibre_gl: ^0.25.0
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^6.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/style.json
- assets/icons/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
@@ -1,30 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_map_demo/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

-28
View File
@@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="Intaleq Premium Mapping.">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Intaleq Maps">
<link rel="icon" type="image/png" href="favicon.png"/>
<title>Intaleq Premium Maps</title>
<link rel="manifest" href="manifest.json">
<link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
<script>
// Enable RTL support for Arabic labels
maplibregl.setRTLTextPlugin(
'./rtl-plugin.js',
null,
true // Lazy load the plugin
);
</script>
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>
-35
View File
@@ -1,35 +0,0 @@
{
"name": "flutter_map_demo",
"short_name": "flutter_map_demo",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
File diff suppressed because one or more lines are too long
-46
View File
@@ -1,46 +0,0 @@
{
"version": 8,
"name": "Intaleq Modern Premium",
"metadata": {},
"center": [35.9106, 31.9539],
"zoom": 12,
"glyphs": "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf",
"sprite": "https://demotiles.maplibre.org/styles/osm-bright-gl-style/sprite",
"sources": {
"local-osm-polygons": {
"type": "vector",
"tiles": ["https://tiles.intaleqapp.com/planet_osm_polygon/{z}/{x}/{y}"],
"maxzoom": 14,
"attribution": "© Intaleq Mapping Solutions"
},
"local-osm-lines": {
"type": "vector",
"tiles": ["https://tiles.intaleqapp.com/planet_osm_line/{z}/{x}/{y}"],
"maxzoom": 14
},
"local-osm-points": {
"type": "vector",
"tiles": ["https://tiles.intaleqapp.com/planet_osm_point/{z}/{x}/{y}"],
"maxzoom": 14
}
},
"layers": [
{ "id": "background", "type": "background", "paint": { "background-color": "#f8f9fa" } },
{ "id": "water-layer", "type": "fill", "source": "local-osm-polygons", "source-layer": "planet_osm_polygon", "filter": ["in", "natural", "water", "lake", "riverbank"], "paint": { "fill-color": "#a3ccff" } },
{ "id": "park-layer", "type": "fill", "source": "local-osm-polygons", "source-layer": "planet_osm_polygon", "filter": ["in", "leisure", "park", "garden", "nature_reserve", "pitch"], "paint": { "fill-color": "#dcedc8" } },
{ "id": "landuse-layer", "type": "fill", "source": "local-osm-polygons", "source-layer": "planet_osm_polygon", "filter": ["in", "landuse", "residential", "commercial", "industrial", "cemetery"], "paint": { "fill-color": ["match", ["get", "landuse"], "residential", "#f1f3f4", "commercial", "#f8f9fa", "industrial", "#f1f3f4", "cemetery", "#dcedc8", "#f1f3f4"] } },
{ "id": "building-3d", "type": "fill-extrusion", "source": "local-osm-polygons", "source-layer": "planet_osm_polygon", "minzoom": 15, "filter": ["has", "building"], "paint": { "fill-extrusion-color": "#e8eaed", "fill-extrusion-height": 20, "fill-extrusion-base": 0, "fill-extrusion-opacity": 0.8 } },
{ "id": "road-casing-minor", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "residential", "service", "unclassified", "living_street", "pedestrian", "path", "track"], "paint": { "line-color": "#d4d4d4", "line-width": ["interpolate", ["linear"], ["zoom"], 13, 1, 16, 8] } },
{ "id": "road-core-minor", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "residential", "service", "unclassified", "living_street", "pedestrian", "path", "track"], "paint": { "line-color": "#ffffff", "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.5, 16, 6] } },
{ "id": "road-casing-tertiary", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "tertiary", "tertiary_link"], "paint": { "line-color": "#e0e0e0", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 1.5, 16, 12] } },
{ "id": "road-core-tertiary", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "tertiary", "tertiary_link"], "paint": { "line-color": "#ffffff", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 1, 16, 9] } },
{ "id": "road-casing-secondary", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "secondary", "secondary_link"], "paint": { "line-color": "#cfd8dc", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 2, 16, 14] } },
{ "id": "road-core-secondary", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "secondary", "secondary_link"], "paint": { "line-color": "#f1f5f9", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 1.5, 16, 11] } },
{ "id": "road-casing-primary", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "primary", "primary_link"], "paint": { "line-color": "#facc15", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 3, 16, 16] } },
{ "id": "road-core-primary", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "primary", "primary_link"], "paint": { "line-color": "#fefce8", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 2, 16, 12] } },
{ "id": "road-casing-motorway-trunk", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "motorway", "motorway_link", "trunk", "trunk_link"], "paint": { "line-color": "#fb923c", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 4, 16, 18] } },
{ "id": "road-core-motorway-trunk", "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", "filter": ["in", "highway", "motorway", "motorway_link", "trunk", "trunk_link"], "paint": { "line-color": "#ffedd5", "line-width": ["interpolate", ["linear"], ["zoom"], 12, 2.5, 16, 14] } },
{ "id": "road-labels", "type": "symbol", "source": "local-osm-lines", "source-layer": "planet_osm_line", "minzoom": 15, "layout": { "text-field": "{name}", "text-font": ["Noto Sans Regular"], "text-size": 13, "symbol-placement": "line", "text-letter-spacing": 0.05, "text-padding": 5, "text-allow-overlap": false }, "paint": { "text-color": "#3c4043", "text-halo-color": "rgba(255, 255, 255, 0.8)", "text-halo-width": 2 } },
{ "id": "place-labels", "type": "symbol", "source": "local-osm-points", "source-layer": "planet_osm_point", "minzoom": 13, "layout": { "text-field": "{name}", "text-font": ["Noto Sans Regular"], "text-size": ["interpolate", ["linear"], ["zoom"], 13, 12, 16, 16], "text-offset": [0, 1.5], "text-anchor": "top" }, "paint": { "text-color": "#3c4043", "text-halo-color": "rgba(255, 255, 255, 0.9)", "text-halo-width": 2 } }
]
}
+7
View File
@@ -93,6 +93,13 @@ services:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- REDIS_URL=redis://redis:6379
- API_PORT=${API_PORT}
- MAP_API_KEY=${MAP_API_KEY}
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
- LOCATION_SERVER_URL=${LOCATION_SERVER_URL}
- LOCATION_SERVER_API_KEY=${LOCATION_SERVER_API_KEY}
- GRAPH_HOPPER_URL=${GRAPH_HOPPER_URL}
- TILE_SERVER_URL=${TILE_SERVER_URL}
depends_on:
db:
condition: service_healthy
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# Download Existing Syria Data from Server to Mac
# To be run on the Mac terminal
SERVER_IP="188.68.36.205"
SERVER_USER="hamzadoctor"
REMOTE_PATH="/home/hamzadoctor/app"
KEY_PATH="/Users/hamzaaleghwairyeen/.ssh/doctory-key"
echo "🌍 Connecting to server to dump existing Syria landmarks..."
# 1. Generate dump on server
ssh -i "$KEY_PATH" "$SERVER_USER@$SERVER_IP" "docker exec -t map-db pg_dump -U mapuser -d mapdb -t places_syria --data-only --inserts > $REMOTE_PATH/existing_syria_data.sql"
# 2. Download the dump to local Mac
echo "📥 Downloading dump to Mac..."
rsync -avz -e "ssh -i $KEY_PATH" "$SERVER_USER@$SERVER_IP:$REMOTE_PATH/existing_syria_data.sql" infrastructure/docker/postgis/
echo "✅ Download complete: infrastructure/docker/postgis/existing_syria_data.sql"
echo "Now run ./infrastructure/scripts/local_db_prep.sh to merge."
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
# Script to execute Syria data import on the server
# To be run from /home/hamzadoctor/app
APP_DIR="/home/hamzadoctor/app"
CSV_FILE="syria_final_complete.csv"
SQL_FILE="infrastructure/docker/postgis/import_syria_csv.sql"
echo "📦 Transferring CSV to PostGIS container..."
docker cp "$APP_DIR/$CSV_FILE" map-db:/tmp/syria_data.csv
echo "💾 Running SQL import script..."
# We use docker compose exec db psql to run the logic
# First, update the SQL logic to use the /tmp path for COPY
# We'll create a temporary SQL wrapper to handle the COPY command with the correct path
docker exec -i map-db psql -U mapuser -d mapdb <<EOF
-- Load schema
\i /home/hamzadoctor/app/$SQL_FILE
-- Perform COPY (must be done in the container pointing to /tmp/syria_data.csv)
CREATE TEMP TABLE staging_syria_temp (
name TEXT,
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
category TEXT,
address TEXT,
description TEXT,
created_at TIMESTAMP
);
COPY staging_syria_temp(name, latitude, longitude, category, address, description, created_at)
FROM '/tmp/syria_data.csv'
WITH (FORMAT csv, HEADER false, QUOTE '"', ENCODING 'UTF8');
INSERT INTO staging_syria SELECT * FROM staging_syria_temp;
DROP TABLE staging_syria_temp;
-- Final merge logic is already in the SQL file loaded via \i
EOF
echo "✅ Import completed successfully!"
+110
View File
@@ -0,0 +1,110 @@
#!/bin/bash
# Local Database Preparation & Merge Script
# To be run on the Mac terminal after download_server_data.sh
set -e
echo "🚀 Starting local database merge and preparation..."
# 1. Start the DB container
echo "📦 Starting PostGIS container..."
docker compose up -d db
# 2. Wait for DB to be ready
echo "⏳ Waiting for database to be ready..."
until docker compose exec -T db pg_isready -U mapuser -d mapdb; do
sleep 2
done
# 3. Initialize Schema & Import Existing Server Data
echo "🛠️ Initializing schema and loading server data..."
docker compose exec -T db psql -U mapuser -d mapdb -c "
DROP TABLE IF EXISTS places_syria;
CREATE TABLE places_syria (
id SERIAL PRIMARY KEY,
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
name TEXT,
name_ar TEXT,
name_en TEXT,
address TEXT,
category TEXT,
neighbourhood TEXT,
city TEXT,
description TEXT,
created_at TIMESTAMP DEFAULT NOW(),
source TEXT,
location GEOMETRY(Point, 4326)
);
CREATE OR REPLACE FUNCTION sync_place_location() RETURNS trigger AS \$\$
BEGIN
IF NEW.latitude IS NOT NULL AND NEW.longitude IS NOT NULL THEN
NEW.location := ST_SetSRID(ST_MakePoint(CAST(NEW.longitude AS FLOAT), CAST(NEW.latitude AS FLOAT)), 4326);
END IF;
RETURN NEW;
END;
\$\$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_sync_place_location ON places_syria;
CREATE TRIGGER trg_sync_place_location
BEFORE INSERT OR UPDATE ON places_syria
FOR EACH ROW EXECUTE FUNCTION sync_place_location();
"
# Load existing data if available
if [ -f "infrastructure/docker/postgis/existing_syria_data.sql" ]; then
echo "📥 Loading existing server data..."
docker compose exec -T db psql -U mapuser -d mapdb < infrastructure/docker/postgis/existing_syria_data.sql
fi
# 4. Import New CSV Data
echo "📥 Importing new CSV landmark data..."
docker cp infrastructure/docker/postgis/syria_final_complete.csv map-db:/tmp/syria_data.csv
docker compose exec -T db psql -U mapuser -d mapdb -c "
DROP TABLE IF EXISTS staging_syria;
CREATE TABLE staging_syria (
name TEXT,
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
category TEXT,
address TEXT,
description TEXT,
created_at TIMESTAMP
);
-- HEADER true fixes the 'invalid input syntax' error
COPY staging_syria(name, latitude, longitude, category, address, description, created_at)
FROM '/tmp/syria_data.csv'
WITH (FORMAT csv, HEADER true, QUOTE '\"', ENCODING 'UTF8');
-- Merge into places_syria while avoiding duplicates
-- We check for name + spatial proximity (approx 50m)
INSERT INTO places_syria (name, name_ar, latitude, longitude, category, address, description, source, created_at)
SELECT
name,
name,
latitude,
longitude,
category,
address,
description,
'csv_import_2026_04',
COALESCE(created_at, NOW())
FROM staging_syria s
WHERE NOT EXISTS (
SELECT 1 FROM places_syria p
WHERE (p.name = s.name OR p.name_ar = s.name)
AND ST_DWithin(
ST_SetSRID(ST_MakePoint(CAST(p.longitude AS FLOAT), CAST(p.latitude AS FLOAT)), 4326)::geography,
ST_SetSRID(ST_MakePoint(CAST(s.longitude AS FLOAT), CAST(s.latitude AS FLOAT)), 4326)::geography,
50
)
);
DROP TABLE staging_syria;
"
echo "✅ Local database merge complete."
echo "Run ./infrastructure/scripts/local_verify.sh to review the results."
+37
View File
@@ -0,0 +1,37 @@
#!/bin/bash
# Local Verification Script for Syria Landmarks
# To be run on the Mac terminal
set -e
echo "📊 --- Local Syria Data Audit ---"
# 1. Total Count
TOTAL=$(docker compose exec -T db psql -U mapuser -d mapdb -t -c "SELECT count(*) FROM places_syria;")
echo "📍 Total Landmarks: $TOTAL"
# 2. Category Distribution
echo "🗂️ Category Distribution:"
docker compose exec -T db psql -U mapuser -d mapdb -c "
SELECT category, count(*) as count
FROM places_syria
GROUP BY category
ORDER BY count DESC
LIMIT 10;
"
# 3. Spatial Bounds Check (Damascus region)
echo "🌍 Spatial Check (Damascus):"
DM_COUNT=$(docker compose exec -T db psql -U mapuser -d mapdb -t -c "
SELECT count(*) FROM places_syria
WHERE latitude BETWEEN 33.4 AND 33.6 AND longitude BETWEEN 36.2 AND 36.4;
")
echo "🏙️ Landmarks in Damascus area: $DM_COUNT"
# 4. Generate Export if user is satisfied
echo "💾 Generating SQL Export..."
docker compose exec -T db pg_dump -U mapuser -d mapdb -t places_syria --data-only --inserts > infrastructure/docker/postgis/syria_export.sql
echo "--------------------------------"
echo "✅ Verification complete. Export saved to: infrastructure/docker/postgis/syria_export.sql"
echo "If you are happy with the results, run sync_to_server.sh to push the data."
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
# Server Restoration Script for Syria Landmarks
# To be run on the server terminal
set -e
APP_DIR="/home/hamzadoctor/app"
EXPORT_FILE="infrastructure/docker/postgis/syria_export.sql"
echo "🔄 Restoring Syria landmarks to production database..."
# 1. Clean existing manual imports to avoid PK conflicts
echo "🧹 Clearing existing manual entries..."
docker exec -i map-db psql -U mapuser -d mapdb -c "DELETE FROM places_syria WHERE source = 'manual_import_2026_04';"
# 2. Inject the SQL dump
echo "📥 Injecting SQL dump..."
docker exec -i map-db psql -U mapuser -d mapdb < "$APP_DIR/$EXPORT_FILE"
# 3. Refresh API cache
echo "🧹 Flushing Redis..."
docker exec -i map-redis redis-cli flushall
echo "✅ Restoration complete! Syria landmarks are live."
+98
View File
@@ -0,0 +1,98 @@
import csv
import os
def parse_jordan_csv(csv_file):
print(f"Parsing {csv_file}...")
records = []
if not os.path.exists(csv_file):
print(f"CSV file {csv_file} not found!")
return []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
# Column names: الاسم,latitude,longitude,الفئة الرئيسية,المحافظة,الرابط المباشر,تاريخ الرصد
name_ar = row['الاسم'].strip()
lat = float(row['latitude'])
lng = float(row['longitude'])
category = row['الفئة الرئيسية'].strip()
city = row['المحافظة'].strip()
link = row['الرابط المباشر'].strip()
created_at = row['تاريخ الرصد'].strip()
records.append({
'name_ar': name_ar,
'name': name_ar, # Use Arabic name for both as no English name provided
'lat': lat,
'lng': lng,
'category': category,
'city': city,
'link': link,
'created_at': created_at,
'source': 'csv'
})
except Exception as e:
# print(f"Error parsing row: {e}")
continue
return records
def merge_and_deduplicate(csv_records):
final_records = []
seen_points = set()
new_added = 0
for r in csv_records:
if not r['name_ar']: continue
# Creating a key for de-duplication based on name and rounded coordinates
key = (r['name_ar'].lower().strip(), round(r['lat'], 5), round(r['lng'], 5))
if key not in seen_points:
final_records.append(r)
seen_points.add(key)
new_added += 1
print(f"CSV records parsed: {len(csv_records)}")
print(f"Unique records: {new_added}")
return final_records
def write_final_sql(merged_records, output_file):
print(f"Writing final SQL to {output_file}...")
with open(output_file, 'w', encoding='utf-8') as f:
f.write("-- Jordan Location Data Combined\n")
f.write("TRUNCATE TABLE places_jordan RESTART IDENTITY;\n\n")
batch_size = 500
for i in range(0, len(merged_records), batch_size):
batch = merged_records[i:i+batch_size]
f.write('INSERT INTO "places_jordan" (name, name_ar, latitude, longitude, category, city, link, created_at, location) VALUES\n')
values_list = []
for r in batch:
name = r['name'].replace("'", "''")
name_ar = r['name_ar'].replace("'", "''")
category = r['category'].replace("'", "''")
city = r['city'].replace("'", "''")
link = r['link'].replace("'", "''")
created_at = r['created_at']
lat = r['lat']
lng = r['lng']
# ST_SetSRID(ST_MakePoint(lon, lat), 4326)
val = f"('{name}', '{name_ar}', {lat}, {lng}, '{category}', '{city}', '{link}', '{created_at}', ST_SetSRID(ST_MakePoint({lng}, {lat}), 4326))"
values_list.append(val)
f.write(",\n".join(values_list))
f.write(";\n\n")
if __name__ == "__main__":
csv_file = 'infrastructure/docker/postgis/jordan_data.csv'
output_file = 'jordan_combined_final.sql'
# If running on server, adjust path if needed
if not os.path.exists(csv_file):
csv_file = 'jordan_data.csv'
csv_records = parse_jordan_csv(csv_file)
merged = merge_and_deduplicate(csv_records)
write_final_sql(merged, output_file)
print(f"Generation complete! File: {output_file}")
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
# Configuration
SERVER_IP="188.68.36.205"
SERVER_USER="hamzadoctor"
REMOTE_PATH="/home/hamzadoctor/app"
KEY_PATH="/Users/hamzaaleghwairyeen/.ssh/doctory-key"
echo "🚀 Starting sync to server: $SERVER_IP..."
# Verify if the key exists
if [ ! -f "$KEY_PATH" ]; then
echo "⚠️ Warning: Identity file $KEY_PATH not found locally."
echo "Attempting sync using default SSH configuration..."
KEY_FLAG=""
else
KEY_FLAG="-i $KEY_PATH"
fi
# Sync files using rsync (surgical sync)
rsync -avz --progress $KEY_FLAG \
--exclude 'infrastructure/osm-data' \
--exclude 'osm-data' \
--exclude 'venv' \
--exclude '.git' \
--exclude 'node_modules' \
--exclude '.DS_Store' \
.env \
docker-compose.yml \
apps \
packages \
infrastructure \
$SERVER_USER@$SERVER_IP:$REMOTE_PATH/
if [ $? -eq 0 ]; then
echo "✅ Sync successful!"
echo "------------------------------------------------"
echo "Now run the following on your SERVER terminal:"
echo "cd $REMOTE_PATH"
echo "docker-compose up -d --build api"
echo "------------------------------------------------"
else
echo "❌ Sync failed. Please check your SSH connection or manually update the files."
fi