feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ. الخريطة: backend · payment_server · loction_server · ride_server · passenger_server · docker · dashboard · stress_test → الجذر siro_rider → apps/rider siro_driver → apps/driver siro_admin → dashboards/admin siro_service → dashboards/service android_bot → apps/android_bot socialBot → apps/socialBot نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب) لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً: كل ما يلي يصير فرقاً مقروءاً مقابل المصدر. لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز، سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh (ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و dashboards/transit-web). ⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة: 1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر): كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner. 2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist) يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً. 3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع → يجب ضمّ الحزم داخله أسوة بـ apps/rider. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9909d9b4c1
commit
4d8414c96b
@@ -0,0 +1,232 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'performance_test.dart'; // Make sure this path is correct
|
||||
|
||||
/// Analyzes various device hardware and software aspects to generate a compatibility score.
|
||||
/// This class provides a standardized output for the UI to consume easily.
|
||||
class DeviceAnalyzer {
|
||||
final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin();
|
||||
|
||||
// نتيجة الفحص لا تتغير عمليا خلال جلسة واحدة، فنخزنها مؤقتا
|
||||
// كي لا تُعاد الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) كل مرة تُفتح الصفحة.
|
||||
static List<Map<String, dynamic>>? _cachedResult;
|
||||
static DateTime? _cachedAt;
|
||||
static const Duration _cacheTtl = Duration(minutes: 30);
|
||||
|
||||
/// Reads the total RAM from the system's meminfo file.
|
||||
/// Returns the value in Megabytes (MB).
|
||||
Future<double> _readTotalRamMB() async {
|
||||
try {
|
||||
final file = File('/proc/meminfo');
|
||||
if (!await file.exists()) return 0.0;
|
||||
final lines = await file.readAsLines();
|
||||
for (var line in lines) {
|
||||
if (line.startsWith('MemTotal')) {
|
||||
// Extracts the numeric value from the line.
|
||||
final kb = int.tryParse(RegExp(r'\d+').stringMatch(line) ?? '0') ?? 0;
|
||||
return kb / 1024.0; // Convert from Kilobytes to Megabytes
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('❌ Error reading total RAM: $e');
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/// Reads the current RAM usage percentage from the system's meminfo file.
|
||||
Future<double> _readUsedRamPercent() async {
|
||||
try {
|
||||
final file = File('/proc/meminfo');
|
||||
if (!await file.exists()) return 0.0;
|
||||
final lines = await file.readAsLines();
|
||||
int? total, available;
|
||||
for (var line in lines) {
|
||||
if (line.startsWith('MemTotal')) {
|
||||
total = int.tryParse(RegExp(r'\d+').stringMatch(line) ?? '');
|
||||
} else if (line.startsWith('MemAvailable')) {
|
||||
available = int.tryParse(RegExp(r'\d+').stringMatch(line) ?? '');
|
||||
}
|
||||
}
|
||||
if (total != null && available != null && total > 0) {
|
||||
final used = total - available;
|
||||
return (used / total) * 100.0;
|
||||
}
|
||||
} catch (e) {
|
||||
print('❌ Error reading used RAM: $e');
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/// The main analysis function that runs all checks.
|
||||
///
|
||||
/// البنود من 1 إلى 7 تقيس قدرة الجهاز الثابتة (لا تتغير خلال الجلسة) وتُخزَّن
|
||||
/// مؤقتا لتفادي إعادة تشغيل الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) في كل
|
||||
/// مرة تُفتح فيها الصفحة. أما بند ضغط الذاكرة الحالي (#8) فيُقاس دائما بشكل فوري
|
||||
/// لأنه رقم متغير باستمرار ولا يصح تجميده مع بقية النتيجة.
|
||||
Future<Map<String, dynamic>> analyzeDevice({bool forceRefresh = false}) async {
|
||||
if (!Platform.isAndroid) {
|
||||
return {
|
||||
'score': 0,
|
||||
'details': [
|
||||
{
|
||||
'label': 'النظام غير مدعوم',
|
||||
'status': false,
|
||||
'achieved_score': 0,
|
||||
'max_score': 100
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> staticDetails;
|
||||
if (!forceRefresh &&
|
||||
_cachedResult != null &&
|
||||
_cachedAt != null &&
|
||||
DateTime.now().difference(_cachedAt!) < _cacheTtl) {
|
||||
staticDetails = _cachedResult!;
|
||||
} else {
|
||||
staticDetails = await _computeStaticDetails();
|
||||
_cachedResult = staticDetails;
|
||||
_cachedAt = DateTime.now();
|
||||
}
|
||||
|
||||
// 8. Memory Pressure (Max: 15 points) — يُقاس دائما بشكل فوري، لا يُخزَّن مؤقتا.
|
||||
final usedPercent = await _readUsedRamPercent();
|
||||
int memScore;
|
||||
if (usedPercent <= 60) {
|
||||
memScore = 15;
|
||||
} else if (usedPercent <= 80) {
|
||||
memScore = 10;
|
||||
} else if (usedPercent <= 90) {
|
||||
memScore = 5;
|
||||
} else {
|
||||
memScore = 0;
|
||||
}
|
||||
final memDetail = {
|
||||
'label': 'استخدام الرام الحالي (${usedPercent.toStringAsFixed(0)}%)',
|
||||
'status': memScore >= 10,
|
||||
'achieved_score': memScore,
|
||||
'max_score': 15,
|
||||
};
|
||||
|
||||
final details = [...staticDetails, memDetail];
|
||||
final totalScore = details.fold<int>(
|
||||
0, (sum, item) => sum + (item['achieved_score'] as int));
|
||||
|
||||
return {
|
||||
'score': totalScore.clamp(0, 100),
|
||||
'details': details,
|
||||
};
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> _computeStaticDetails() async {
|
||||
List<Map<String, dynamic>> details = [];
|
||||
|
||||
final info = await _deviceInfo.androidInfo;
|
||||
final data = info.data;
|
||||
final features = List<String>.from(data['systemFeatures'] ?? []);
|
||||
|
||||
// 1. Android Version (Max: 10 points)
|
||||
final version =
|
||||
int.tryParse(info.version.release?.split('.').first ?? '0') ?? 0;
|
||||
final int androidScore = version >= 9 ? 10 : 0;
|
||||
details.add({
|
||||
'label': 'إصدار أندرويد ${info.version.release}',
|
||||
'status': androidScore > 0,
|
||||
'achieved_score': androidScore,
|
||||
'max_score': 10,
|
||||
});
|
||||
|
||||
// 2. Total RAM (Max: 10 points)
|
||||
final totalRam = await _readTotalRamMB();
|
||||
int ramScore;
|
||||
if (totalRam >= 8000) {
|
||||
ramScore = 10;
|
||||
} else if (totalRam >= 4000) {
|
||||
ramScore = 5;
|
||||
} else if (totalRam >= 3000) {
|
||||
ramScore = 3;
|
||||
} else {
|
||||
ramScore = 0;
|
||||
}
|
||||
details.add({
|
||||
'label': 'إجمالي الرام ${totalRam.toStringAsFixed(0)} ميجابايت',
|
||||
'status': ramScore >= 5,
|
||||
'achieved_score': ramScore,
|
||||
'max_score': 10,
|
||||
});
|
||||
|
||||
// 3. CPU Cores (Max: 10 points)
|
||||
final cores = Platform.numberOfProcessors;
|
||||
int coreScore = cores >= 6 ? 10 : (cores >= 4 ? 5 : 0);
|
||||
details.add({
|
||||
'label': 'أنوية المعالج ($cores)',
|
||||
'status': coreScore >= 5,
|
||||
'achieved_score': coreScore,
|
||||
'max_score': 10,
|
||||
});
|
||||
|
||||
// 4. Free Storage (Max: 5 points)
|
||||
final freeBytes = data['freeDiskSize'] ?? 0;
|
||||
final freeGB = freeBytes / (1024 * 1024 * 1024);
|
||||
int storeScore = freeGB >= 5 ? 5 : (freeGB >= 2 ? 3 : 0);
|
||||
details.add({
|
||||
'label': 'المساحة الحرة ${freeGB.toStringAsFixed(1)} جيجابايت',
|
||||
'status': storeScore >= 3,
|
||||
'achieved_score': storeScore,
|
||||
'max_score': 5,
|
||||
});
|
||||
|
||||
// 5. GPS + Gyroscope Sensors (Max: 10 points)
|
||||
bool okSensors = features.contains('android.hardware.location.gps') &&
|
||||
features.contains('android.hardware.sensor.gyroscope');
|
||||
final int sensorScore = okSensors ? 10 : 0;
|
||||
details.add({
|
||||
'label': 'حساسات GPS و Gyroscope',
|
||||
'status': okSensors,
|
||||
'achieved_score': sensorScore,
|
||||
'max_score': 10,
|
||||
});
|
||||
|
||||
// 6. Storage Write Speed (Max: 20 points)
|
||||
final writeSpeed = await PerformanceTester.testStorageWriteSpeed();
|
||||
int writeScore;
|
||||
if (writeSpeed >= 30) {
|
||||
writeScore = 20;
|
||||
} else if (writeSpeed >= 15) {
|
||||
writeScore = 15;
|
||||
} else if (writeSpeed >= 5) {
|
||||
writeScore = 10;
|
||||
} else {
|
||||
writeScore = 5;
|
||||
}
|
||||
details.add({
|
||||
'label': 'سرعة الكتابة (${writeSpeed.toStringAsFixed(1)} MB/s)',
|
||||
'status': writeScore >= 10,
|
||||
'achieved_score': writeScore,
|
||||
'max_score': 20,
|
||||
});
|
||||
|
||||
// 7. CPU Compute Speed (Max: 20 points)
|
||||
final cpuTime = await PerformanceTester.testCPUSpeed();
|
||||
int cpuScore;
|
||||
if (cpuTime <= 1.0) {
|
||||
cpuScore = 20;
|
||||
} else if (cpuTime <= 2.5) {
|
||||
cpuScore = 15;
|
||||
} else if (cpuTime <= 4.0) {
|
||||
cpuScore = 10;
|
||||
} else {
|
||||
cpuScore = 5;
|
||||
}
|
||||
details.add({
|
||||
'label': 'سرعة المعالجة (${cpuTime.toStringAsFixed(2)} ثانية)',
|
||||
'status': cpuScore >= 10,
|
||||
'achieved_score': cpuScore,
|
||||
'max_score': 20,
|
||||
});
|
||||
|
||||
return details;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user