From 5e6aeb790862c44b3d32b2bba36cf5733486ec33 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Thu, 9 Jul 2026 15:09:02 +0300 Subject: [PATCH] refactor: unify device analysis and performance testing logic for improved module consistency --- .../controller/functions/device_analyzer.dart | 87 ++++++++++++------- .../functions/performance_test.dart | 65 +++++++++----- 2 files changed, 99 insertions(+), 53 deletions(-) diff --git a/siro_driver/lib/controller/functions/device_analyzer.dart b/siro_driver/lib/controller/functions/device_analyzer.dart index 82c3fa06..1e96fa59 100644 --- a/siro_driver/lib/controller/functions/device_analyzer.dart +++ b/siro_driver/lib/controller/functions/device_analyzer.dart @@ -8,6 +8,12 @@ import 'performance_test.dart'; // Make sure this path is correct class DeviceAnalyzer { final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin(); + // نتيجة الفحص لا تتغير عمليا خلال جلسة واحدة، فنخزنها مؤقتا + // كي لا تُعاد الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) كل مرة تُفتح الصفحة. + static List>? _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 _readTotalRamMB() async { @@ -53,9 +59,12 @@ class DeviceAnalyzer { } /// The main analysis function that runs all checks. - Future> analyzeDevice() async { - List> details = []; - + /// + /// البنود من 1 إلى 7 تقيس قدرة الجهاز الثابتة (لا تتغير خلال الجلسة) وتُخزَّن + /// مؤقتا لتفادي إعادة تشغيل الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) في كل + /// مرة تُفتح فيها الصفحة. أما بند ضغط الذاكرة الحالي (#8) فيُقاس دائما بشكل فوري + /// لأنه رقم متغير باستمرار ولا يصح تجميده مع بقية النتيجة. + Future> analyzeDevice({bool forceRefresh = false}) async { if (!Platform.isAndroid) { return { 'score': 0, @@ -70,6 +79,50 @@ class DeviceAnalyzer { }; } + List> 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( + 0, (sum, item) => sum + (item['achieved_score'] as int)); + + return { + 'score': totalScore.clamp(0, 100), + 'details': details, + }; + } + + Future>> _computeStaticDetails() async { + List> details = []; + final info = await _deviceInfo.androidInfo; final data = info.data; final features = List.from(data['systemFeatures'] ?? []); @@ -174,32 +227,6 @@ class DeviceAnalyzer { 'max_score': 20, }); - // 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; - } - details.add({ - 'label': 'استخدام الرام الحالي (${usedPercent.toStringAsFixed(0)}%)', - 'status': memScore >= 10, - 'achieved_score': memScore, - 'max_score': 15, - }); - - // Calculate the final total score by summing up the achieved scores. - final totalScore = details.fold( - 0, (sum, item) => sum + (item['achieved_score'] as int)); - - return { - 'score': totalScore.clamp(0, 100), - 'details': details, - }; + return details; } } diff --git a/siro_driver/lib/controller/functions/performance_test.dart b/siro_driver/lib/controller/functions/performance_test.dart index de868283..2db9f573 100644 --- a/siro_driver/lib/controller/functions/performance_test.dart +++ b/siro_driver/lib/controller/functions/performance_test.dart @@ -1,40 +1,59 @@ import 'dart:io'; +import 'dart:isolate'; class PerformanceTester { /// ✅ فحص سرعة الكتابة إلى التخزين (Storage Write Speed) بوحدة MB/s - static Future testStorageWriteSpeed() async { - try { - final tempDir = Directory.systemTemp; - final testFile = File('${tempDir.path}/speed_test.txt'); - final data = List.filled(1024 * 1024 * 5, 0); // 5MB + /// يكرر القياس عدة مرات ويأخذ المتوسط الوسيط لتقليل تأثير الحمل العرضي على الجهاز. + static Future testStorageWriteSpeed({int samples = 3}) async { + final List speeds = []; + for (int i = 0; i < samples; i++) { + try { + final tempDir = Directory.systemTemp; + final testFile = File('${tempDir.path}/speed_test_$i.txt'); + final data = List.filled(1024 * 1024 * 5, 0); // 5MB - final stopwatch = Stopwatch()..start(); - await testFile.writeAsBytes(data, flush: true); - stopwatch.stop(); + final stopwatch = Stopwatch()..start(); + await testFile.writeAsBytes(data, flush: true); + stopwatch.stop(); - await testFile.delete(); + await testFile.delete(); - double seconds = stopwatch.elapsedMilliseconds / 1000; - if (seconds == 0) seconds = 0.001; + double seconds = stopwatch.elapsedMilliseconds / 1000; + if (seconds == 0) seconds = 0.001; - final speed = 5 / seconds; - return double.parse(speed.toStringAsFixed(2)); - } catch (e) { - print("❌ Storage write error: $e"); - return 0.0; + speeds.add(5 / seconds); + } catch (e) { + print("❌ Storage write error: $e"); + } } + if (speeds.isEmpty) return 0.0; + speeds.sort(); + final median = speeds[speeds.length ~/ 2]; + return double.parse(median.toStringAsFixed(2)); + } + + /// عملية حسابية مكثفة تُنفَّذ داخل isolate منفصل حتى لا تجمّد واجهة المستخدم. + static double _cpuBurn(int iterations) { + double x = 0; + for (int i = 0; i < iterations; i++) { + x += i * 0.000001; + } + return x; } /// ✅ فحص سرعة المعالج (CPU Compute Speed) بوحدة الثواني - static Future testCPUSpeed() async { + /// يعمل في isolate منفصل (لا يجمّد الواجهة) ويكرر القياس ويأخذ الوسيط. + static Future testCPUSpeed({int samples = 3}) async { try { - final stopwatch = Stopwatch()..start(); - double x = 0; - for (int i = 0; i < 100000000; i++) { - x += i * 0.000001; + final List times = []; + for (int i = 0; i < samples; i++) { + final stopwatch = Stopwatch()..start(); + await Isolate.run(() => _cpuBurn(100000000)); + stopwatch.stop(); + times.add(stopwatch.elapsedMilliseconds / 1000.0); } - stopwatch.stop(); - return stopwatch.elapsedMilliseconds / 1000.0; + times.sort(); + return times[times.length ~/ 2]; } catch (e) { print("❌ CPU compute error: $e"); return 999.0;