refactor: unify device analysis and performance testing logic for improved module consistency

This commit is contained in:
Hamza-Ayed
2026-07-09 15:09:02 +03:00
parent d94808c380
commit 5e6aeb7908
2 changed files with 99 additions and 53 deletions
@@ -8,6 +8,12 @@ import 'performance_test.dart'; // Make sure this path is correct
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 {
@@ -53,9 +59,12 @@ class DeviceAnalyzer {
}
/// The main analysis function that runs all checks.
Future<Map<String, dynamic>> analyzeDevice() async {
List<Map<String, dynamic>> details = [];
///
/// البنود من 1 إلى 7 تقيس قدرة الجهاز الثابتة (لا تتغير خلال الجلسة) وتُخزَّن
/// مؤقتا لتفادي إعادة تشغيل الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) في كل
/// مرة تُفتح فيها الصفحة. أما بند ضغط الذاكرة الحالي (#8) فيُقاس دائما بشكل فوري
/// لأنه رقم متغير باستمرار ولا يصح تجميده مع بقية النتيجة.
Future<Map<String, dynamic>> analyzeDevice({bool forceRefresh = false}) async {
if (!Platform.isAndroid) {
return {
'score': 0,
@@ -70,6 +79,50 @@ class DeviceAnalyzer {
};
}
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'] ?? []);
@@ -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<int>(
0, (sum, item) => sum + (item['achieved_score'] as int));
return {
'score': totalScore.clamp(0, 100),
'details': details,
};
return details;
}
}
@@ -1,40 +1,59 @@
import 'dart:io';
import 'dart:isolate';
class PerformanceTester {
/// ✅ فحص سرعة الكتابة إلى التخزين (Storage Write Speed) بوحدة MB/s
static Future<double> testStorageWriteSpeed() async {
try {
final tempDir = Directory.systemTemp;
final testFile = File('${tempDir.path}/speed_test.txt');
final data = List<int>.filled(1024 * 1024 * 5, 0); // 5MB
/// يكرر القياس عدة مرات ويأخذ المتوسط الوسيط لتقليل تأثير الحمل العرضي على الجهاز.
static Future<double> testStorageWriteSpeed({int samples = 3}) async {
final List<double> 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<int>.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<double> testCPUSpeed() async {
/// يعمل في isolate منفصل (لا يجمّد الواجهة) ويكرر القياس ويأخذ الوسيط.
static Future<double> 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<double> 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;