Update Saqel Platform: 2026-09-04 02:57:19
This commit is contained in:
+47
-27
@@ -50,7 +50,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
'word': 'العِلْمَ',
|
||||
'role': 'اسم إنَّ',
|
||||
'case': 'منصوب وعلامة نصبه الفتحة الظاهرة على آخره',
|
||||
'explanation': 'هو المسند إليه في الأصل، نُصب لدخول الحرف الناسخ عليه.',
|
||||
'explanation':
|
||||
'هو المسند إليه في الأصل، نُصب لدخول الحرف الناسخ عليه.',
|
||||
'tag': 'اسم منصوب',
|
||||
},
|
||||
{
|
||||
@@ -64,7 +65,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
'word': 'يَهْدِي',
|
||||
'role': 'فعل مضارع مرفوع (وجملة فعلية في محل رفع نعت)',
|
||||
'case': 'مرفوع بالضمة المقدرة على الياء للثقل، والفاعل ضمير مستتر',
|
||||
'explanation': 'الجمل بعد النكرات صفات؛ فجملة (يهدي) نعت لكلمة (نور).',
|
||||
'explanation':
|
||||
'الجمل بعد النكرات صفات؛ فجملة (يهدي) نعت لكلمة (نور).',
|
||||
'tag': 'فعل + نعت',
|
||||
},
|
||||
{
|
||||
@@ -84,7 +86,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
],
|
||||
},
|
||||
{
|
||||
'fullText': 'قَرَأَ الطَّالِبُ المُجْتَهِدُ كِتَابَيْنِ مُفِيدَيْنِ صَبَاحاً',
|
||||
'fullText':
|
||||
'قَرَأَ الطَّالِبُ المُجْتَهِدُ كِتَابَيْنِ مُفِيدَيْنِ صَبَاحاً',
|
||||
'type': 'جملة فعلية تامة',
|
||||
'rootNode': 'الجملة الفعلية (فعل + فاعل + مفعول به + فضلات)',
|
||||
'words': [
|
||||
@@ -92,35 +95,40 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
'word': 'قَرَأَ',
|
||||
'role': 'فعل ماضٍ مبني',
|
||||
'case': 'مبني على الفتح الظاهر على آخره',
|
||||
'explanation': 'فعل ماضٍ مجرد، مبني للمعلوم، يدل على حدث في الزمن الماضي.',
|
||||
'explanation':
|
||||
'فعل ماضٍ مجرد، مبني للمعلوم، يدل على حدث في الزمن الماضي.',
|
||||
'tag': 'فعل ماضٍ',
|
||||
},
|
||||
{
|
||||
'word': 'الطَّالِبُ',
|
||||
'role': 'فاعل مرفوع',
|
||||
'case': 'مرفوع وعلامة رفعه الضمة الظاهرة',
|
||||
'explanation': 'من قام بالفعل، معرف بأل، ركن أساسي في الجملة الفعلية.',
|
||||
'explanation':
|
||||
'من قام بالفعل، معرف بأل، ركن أساسي في الجملة الفعلية.',
|
||||
'tag': 'فاعل مرفوع',
|
||||
},
|
||||
{
|
||||
'word': 'المُجْتَهِدُ',
|
||||
'role': 'نعت (صفة) للطالب',
|
||||
'case': 'مرفوع وعلامة رفعه الضمة الظاهرة',
|
||||
'explanation': 'طابق المنعوت في التعريف، الإفراد، التذكير، وحركة الإعراب.',
|
||||
'explanation':
|
||||
'طابق المنعوت في التعريف، الإفراد، التذكير، وحركة الإعراب.',
|
||||
'tag': 'نعت / صفة',
|
||||
},
|
||||
{
|
||||
'word': 'كِتَابَيْنِ',
|
||||
'role': 'مفعول به منصوب',
|
||||
'case': 'منصوب وعلامة نصبه الياء لأنه مثنى',
|
||||
'explanation': 'وقع عليه فعل القراءة، والمثنى يُنصب بالياء وتُكسر نونه.',
|
||||
'explanation':
|
||||
'وقع عليه فعل القراءة، والمثنى يُنصب بالياء وتُكسر نونه.',
|
||||
'tag': 'مثنى منصوب',
|
||||
},
|
||||
{
|
||||
'word': 'مُفِيدَيْنِ',
|
||||
'role': 'نعت لكتابين',
|
||||
'case': 'منصوب وعلامة نصبه الياء لأنه مثنى',
|
||||
'explanation': 'صفة تابعة للمفعول به في التثنية والتنكير والنصب بالياء.',
|
||||
'explanation':
|
||||
'صفة تابعة للمفعول به في التثنية والتنكير والنصب بالياء.',
|
||||
'tag': 'نعت مثنى',
|
||||
},
|
||||
{
|
||||
@@ -142,8 +150,10 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
final List<Map<String, dynamic>> _poetryMeters = [
|
||||
{
|
||||
'name': 'البحر البسيط',
|
||||
'key': 'إِنَّ البَسِيطَ لَدَيْهِ يُبْسَطُ الأَمَلُ .. مُسْتَفْعِلُنْ فاعِلُنْ مُسْتَفْعِلُنْ فَعِلُ',
|
||||
'verse': 'لِكُلِّ شَيْءٍ إِذَا مَا تَمَّ نُقْصَانُ .. فَلَا يُغَرَّ بِطِيبِ العَيْشِ إِنْسَانُ',
|
||||
'key':
|
||||
'إِنَّ البَسِيطَ لَدَيْهِ يُبْسَطُ الأَمَلُ .. مُسْتَفْعِلُنْ فاعِلُنْ مُسْتَفْعِلُنْ فَعِلُ',
|
||||
'verse':
|
||||
'لِكُلِّ شَيْءٍ إِذَا مَا تَمَّ نُقْصَانُ .. فَلَا يُغَرَّ بِطِيبِ العَيْشِ إِنْسَانُ',
|
||||
'poet': 'أبو البقاء الرندي',
|
||||
'pattern': ['مُسْتَفْعِلُنْ', 'فَاعِلُنْ', 'مُسْتَفْعِلُنْ', 'فَعِلُنْ'],
|
||||
'scansion': ['//0//0', '/0//0', '//0//0', '///0'],
|
||||
@@ -151,8 +161,10 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
},
|
||||
{
|
||||
'name': 'البحر الوافر',
|
||||
'key': 'بُحُورُ الشِّعْرِ وَافِرُهَا جَمِيلُ .. مُفَاعَلَتُنْ مُفَاعَلَتُنْ فَعُولُ',
|
||||
'verse': 'إِذَا غَامَرْتَ فِي شَرَفٍ مَرُومِ .. فَلَا تَقْنَعْ بِمَا دُونَ النُّجُومِ',
|
||||
'key':
|
||||
'بُحُورُ الشِّعْرِ وَافِرُهَا جَمِيلُ .. مُفَاعَلَتُنْ مُفَاعَلَتُنْ فَعُولُ',
|
||||
'verse':
|
||||
'إِذَا غَامَرْتَ فِي شَرَفٍ مَرُومِ .. فَلَا تَقْنَعْ بِمَا دُونَ النُّجُومِ',
|
||||
'poet': 'المتنبي',
|
||||
'pattern': ['مُفَاعَلَتُنْ', 'مُفَاعَلَتُنْ', 'فَعُولُنْ'],
|
||||
'scansion': ['//0///0', '//0///0', '//0/0'],
|
||||
@@ -160,8 +172,10 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
},
|
||||
{
|
||||
'name': 'البحر الكامل',
|
||||
'key': 'كَمُلَ الجَمَالُ مِنَ البُحُورِ الكَامِلُ .. مُتَفَاعِلُنْ مُتَفَاعِلُنْ مُتَفَاعِلُ',
|
||||
'verse': 'وَإِذَا صَحَوْتُ فَمَا أُقَصِّرُ عَنْ نَدَى .. وَكَمَا عَلِمْتِ شَمَائِلِي وَتَكَرُّمِي',
|
||||
'key':
|
||||
'كَمُلَ الجَمَالُ مِنَ البُحُورِ الكَامِلُ .. مُتَفَاعِلُنْ مُتَفَاعِلُنْ مُتَفَاعِلُ',
|
||||
'verse':
|
||||
'وَإِذَا صَحَوْتُ فَمَا أُقَصِّرُ عَنْ نَدَى .. وَكَمَا عَلِمْتِ شَمَائِلِي وَتَكَرُّمِي',
|
||||
'poet': 'عنترة بن شداد',
|
||||
'pattern': ['مُتَفَاعِلُنْ', 'مُتَفَاعِلُنْ', 'مُتَفَاعِلُنْ'],
|
||||
'scansion': ['///0//0', '///0//0', '///0//0'],
|
||||
@@ -241,7 +255,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? const Color(0xFF10B981) : const Color(0xFF1E293B),
|
||||
color:
|
||||
isSelected ? const Color(0xFF10B981) : const Color(0xFF1E293B),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
@@ -293,14 +308,15 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
color: Colors.white),
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF10B981).withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
widget.customSentences != null ? 'أمثلة الكتاب + ذكاء اصطناعي' : 'وزاري · التوجيهي 2008',
|
||||
widget.customSentences != null
|
||||
? 'أمثلة الكتاب + ذكاء اصطناعي'
|
||||
: 'وزاري · التوجيهي 2008',
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -347,10 +363,9 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@@ -555,11 +570,13 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Role
|
||||
_infoRow('الموقع الإعرابي', wordData['role'], const Color(0xFF38BDF8)),
|
||||
_infoRow(
|
||||
'الموقع الإعرابي', wordData['role'], const Color(0xFF38BDF8)),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Case & Sign
|
||||
_infoRow('الحالة والعلامة', wordData['case'], const Color(0xFFFBBF24)),
|
||||
_infoRow(
|
||||
'الحالة والعلامة', wordData['case'], const Color(0xFFFBBF24)),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Pedagogical Socratic explanation
|
||||
@@ -619,7 +636,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
_isPlayingBeat = false;
|
||||
}),
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(left: idx < _poetryMeters.length - 1 ? 8 : 0),
|
||||
margin: EdgeInsets.only(
|
||||
left: idx < _poetryMeters.length - 1 ? 8 : 0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: isCur
|
||||
@@ -714,7 +732,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
final scan = scansions[idx];
|
||||
return Expanded(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(left: idx < patterns.length - 1 ? 8 : 0),
|
||||
margin:
|
||||
EdgeInsets.only(left: idx < patterns.length - 1 ? 8 : 0),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
@@ -778,7 +797,8 @@ class _ArabicInteractiveLabViewState extends State<ArabicInteractiveLabView>
|
||||
_isPlayingBeat
|
||||
? 'إيقاف الإيقاع العروضي التفاعلي'
|
||||
: 'عزف الإيقاع العروضي الموزون (${meter['speedBpm']} نقرة/دقيقة) 🥁',
|
||||
style: const TextStyle(fontSize: 13.5, fontWeight: FontWeight.w700),
|
||||
style:
|
||||
const TextStyle(fontSize: 13.5, fontWeight: FontWeight.w700),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _isPlayingBeat
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../../../logic/cubits/auth_cubit.dart';
|
||||
import '../../../logic/cubits/dashboard_cubits.dart';
|
||||
import '../../widgets/luxury_widgets.dart';
|
||||
import '../curriculum/subjects_grid_screen.dart';
|
||||
import '../notebook/smart_error_notebook_screen.dart';
|
||||
|
||||
class UnifiedHomeScreen extends StatefulWidget {
|
||||
final UserModel user;
|
||||
@@ -316,7 +317,79 @@ class _UnifiedHomeScreenState extends State<UnifiedHomeScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Smart Error Notebook & Remediation Pathway Gateway
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => const SmartErrorNotebookScreen()),
|
||||
);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF1E1B4B), Color(0xFF0F172A)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: const Color(0xFF8B5CF6).withOpacity(0.4), width: 1.5),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFF8B5CF6).withOpacity(0.15),
|
||||
blurRadius: 15,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF8B5CF6), Color(0xFF38BDF8)],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Icon(CupertinoIcons.book_circle_fill, color: Colors.white, size: 24),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
const Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'دفتر الأخطاء الذكي والمسار العلاجي 📓',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 14),
|
||||
),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'· نشط',
|
||||
style: TextStyle(color: Color(0xFF34D399), fontWeight: FontWeight.w700, fontSize: 11),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 3),
|
||||
Text(
|
||||
'رصد الأسئلة المتعثرة وسد الفجوات التراكمية بالذكاء الاصطناعي',
|
||||
style: TextStyle(color: Color(0xFF94A3B8), fontSize: 11.5),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(CupertinoIcons.chevron_back, color: Color(0xFF8B5CF6), size: 18),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Real Readiness Score Card
|
||||
LuxuryCard(
|
||||
|
||||
@@ -0,0 +1,969 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../data/models/error_notebook_model.dart';
|
||||
import '../../../data/repositories/error_notebook_repository.dart';
|
||||
|
||||
/// ==============================================================================
|
||||
/// SAQEL ENTERPRISE - SMART ERROR NOTEBOOK & ADAPTIVE REMEDIATION SCREEN
|
||||
/// ==============================================================================
|
||||
class SmartErrorNotebookScreen extends StatefulWidget {
|
||||
const SmartErrorNotebookScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SmartErrorNotebookScreen> createState() =>
|
||||
_SmartErrorNotebookScreenState();
|
||||
}
|
||||
|
||||
class _SmartErrorNotebookScreenState extends State<SmartErrorNotebookScreen> {
|
||||
final ErrorNotebookRepository _repository = ErrorNotebookRepository();
|
||||
|
||||
bool _isLoading = true;
|
||||
ErrorNotebookSummary? _summary;
|
||||
List<ErrorNotebookItem> _items = [];
|
||||
|
||||
// Filters
|
||||
String _activeStatusFilter = 'all'; // 'all', 'pending_remediation', 'mastered'
|
||||
String _activeSubjectFilter = 'all'; // 'all' or subject name
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadNotebookData();
|
||||
}
|
||||
|
||||
Future<void> _loadNotebookData() async {
|
||||
setState(() => _isLoading = true);
|
||||
final data = await _repository.getErrorNotebook();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_summary = data['summary'] as ErrorNotebookSummary?;
|
||||
_items = (data['items'] as List<ErrorNotebookItem>?) ?? [];
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
List<ErrorNotebookItem> get _filteredItems {
|
||||
return _items.where((item) {
|
||||
if (_activeStatusFilter != 'all' && item.status != _activeStatusFilter) {
|
||||
return false;
|
||||
}
|
||||
if (_activeSubjectFilter != 'all' &&
|
||||
item.subjectName != _activeSubjectFilter) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
void _startRemediation(ErrorNotebookItem errorItem) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (ctx) => _RemediationModalSheet(
|
||||
errorItem: errorItem,
|
||||
repository: _repository,
|
||||
onRemediationCompleted: () {
|
||||
setState(() {
|
||||
// Optimistically update local item
|
||||
final idx = _items.indexWhere((it) => it.uuid == errorItem.uuid);
|
||||
if (idx != -1) {
|
||||
_items[idx] = _items[idx].copyWith(
|
||||
status: 'mastered',
|
||||
masteredAt: 'الآن',
|
||||
remediationAttemptsCount: _items[idx].remediationAttemptsCount + 1,
|
||||
);
|
||||
}
|
||||
// Update summary
|
||||
if (_summary != null) {
|
||||
final newMastered = _summary!.masteredCount + 1;
|
||||
final newPending = (_summary!.pendingCount - 1).clamp(0, 999);
|
||||
final newRate = _summary!.totalErrors > 0
|
||||
? (newMastered / _summary!.totalErrors) * 100
|
||||
: 100.0;
|
||||
|
||||
_summary = ErrorNotebookSummary(
|
||||
totalErrors: _summary!.totalErrors,
|
||||
masteredCount: newMastered,
|
||||
pendingCount: newPending,
|
||||
masteryPercentage: newRate,
|
||||
bySubject: _summary!.bySubject,
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFF070B12),
|
||||
appBar: AppBar(
|
||||
backgroundColor: const Color(0xFF0E1626),
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(CupertinoIcons.back, color: Colors.white),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
title: const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.book_circle_fill,
|
||||
color: Color(0xFF38BDF8), size: 22),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'دفتر الأخطاء الذكي والمسار العلاجي',
|
||||
style: TextStyle(
|
||||
fontSize: 16.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(CupertinoIcons.arrow_clockwise, color: Colors.white70),
|
||||
onPressed: _loadNotebookData,
|
||||
tooltip: 'تحديث السجل',
|
||||
),
|
||||
],
|
||||
),
|
||||
body: _isLoading
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(color: Color(0xFF38BDF8)),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: _loadNotebookData,
|
||||
color: const Color(0xFF38BDF8),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
if (_summary != null) _buildSummaryHeader(_summary!),
|
||||
const SizedBox(height: 18),
|
||||
_buildStatusTabs(),
|
||||
const SizedBox(height: 12),
|
||||
_buildSubjectFilterChips(),
|
||||
const SizedBox(height: 16),
|
||||
_buildItemsList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSummaryHeader(ErrorNotebookSummary summary) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(18),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF0F172A), Color(0xFF1E293B)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: const Color(0xFF334155)),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x22000000),
|
||||
blurRadius: 15,
|
||||
offset: Offset(0, 6),
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'مؤشر الشفاء والتمكن المعرفي',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
Text(
|
||||
'رصد الفجوات وسدها قبل امتحان التوجيهي الوزاري',
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
color: Color(0xFF94A3B8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: summary.masteryPercentage >= 70
|
||||
? const Color(0xFF10B981).withOpacity(0.2)
|
||||
: const Color(0xFFF59E0B).withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'${summary.masteryPercentage.toStringAsFixed(0)}% تمكن',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: summary.masteryPercentage >= 70
|
||||
? const Color(0xFF34D399)
|
||||
: const Color(0xFFFBBF24),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Progress Bar
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: LinearProgressIndicator(
|
||||
value: (summary.masteryPercentage / 100).clamp(0.0, 1.0),
|
||||
minHeight: 8,
|
||||
backgroundColor: const Color(0xFF0F172A),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
summary.masteryPercentage >= 70
|
||||
? const Color(0xFF10B981)
|
||||
: const Color(0xFFF59E0B),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// KPI Stats Row
|
||||
Row(
|
||||
children: [
|
||||
_metricBox(
|
||||
title: 'إجمالي الفجوات',
|
||||
value: '${summary.totalErrors}',
|
||||
color: const Color(0xFF94A3B8),
|
||||
icon: CupertinoIcons.scope,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_metricBox(
|
||||
title: 'بحاجة إلى علاج',
|
||||
value: '${summary.pendingCount}',
|
||||
color: const Color(0xFFEF4444),
|
||||
icon: CupertinoIcons.exclamationmark_triangle_fill,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_metricBox(
|
||||
title: 'تم الإتقان 🏆',
|
||||
value: '${summary.masteredCount}',
|
||||
color: const Color(0xFF10B981),
|
||||
icon: CupertinoIcons.checkmark_seal_fill,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _metricBox({
|
||||
required String title,
|
||||
required String value,
|
||||
required Color color,
|
||||
required IconData icon,
|
||||
}) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0B111E),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: const Color(0xFF1E293B)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(icon, size: 16, color: color),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(fontSize: 10.5, color: Color(0xFF64748B)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusTabs() {
|
||||
return Row(
|
||||
children: [
|
||||
_statusFilterButton('all', 'جميع الأخطاء (${_items.length})'),
|
||||
const SizedBox(width: 8),
|
||||
_statusFilterButton(
|
||||
'pending_remediation',
|
||||
'بحاجة لعلاج (${_items.where((e) => !e.isMastered).length})',
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_statusFilterButton(
|
||||
'mastered',
|
||||
'تم إتقانها (${_items.where((e) => e.isMastered).length})',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _statusFilterButton(String filterKey, String title) {
|
||||
final isSel = _activeStatusFilter == filterKey;
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () => setState(() => _activeStatusFilter = filterKey),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSel ? const Color(0xFF38BDF8) : const Color(0xFF1E293B),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: isSel ? FontWeight.w800 : FontWeight.w600,
|
||||
color: isSel ? Colors.black : const Color(0xFF94A3B8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSubjectFilterChips() {
|
||||
final subjects = ['all', ..._items.map((e) => e.subjectName).toSet()];
|
||||
return SizedBox(
|
||||
height: 34,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: subjects.length,
|
||||
itemBuilder: (ctx, idx) {
|
||||
final sub = subjects[idx];
|
||||
final isSel = _activeSubjectFilter == sub;
|
||||
final title = sub == 'all' ? 'جميع المواد' : sub;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => setState(() => _activeSubjectFilter = sub),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(left: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: isSel ? const Color(0xFF10B981) : const Color(0xFF0F172A),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: isSel ? const Color(0xFF34D399) : const Color(0xFF1E293B),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: isSel ? FontWeight.w800 : FontWeight.w600,
|
||||
color: isSel ? Colors.black : const Color(0xFF94A3B8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemsList() {
|
||||
final items = _filteredItems;
|
||||
|
||||
if (items.isEmpty) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: const Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(CupertinoIcons.sparkles, size: 48, color: Color(0xFF10B981)),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
'دفتر الأخطاء نظيف تماماً! أحسنت 🌟',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'لم يتم رصد أي فجوات غير معالجة في هذا المبحث.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFF64748B)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: items.map((it) => _buildErrorCard(it)).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildErrorCard(ErrorNotebookItem item) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 14),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0F172A),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: item.isMastered
|
||||
? const Color(0xFF10B981).withOpacity(0.3)
|
||||
: const Color(0xFFEF4444).withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header: Subject & Category Badge
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF1E293B),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
item.subjectName,
|
||||
style: const TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Color(0xFF38BDF8),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
item.topicName,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF94A3B8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: item.categoryColor.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
item.categoryArabicName,
|
||||
style: TextStyle(
|
||||
fontSize: 10.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: item.categoryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Question Text
|
||||
Text(
|
||||
item.questionText,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Comparison Box (Wrong vs Correct)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF161F30),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(CupertinoIcons.xmark_circle_fill,
|
||||
size: 15, color: Color(0xFFEF4444)),
|
||||
const SizedBox(width: 8),
|
||||
const Text('إجابتك السابقة: ',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFF94A3B8))),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.studentWrongAnswer,
|
||||
style: const TextStyle(
|
||||
fontSize: 12.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Color(0xFFF87171),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(color: Color(0xFF1E293B), height: 16),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(CupertinoIcons.checkmark_circle_fill,
|
||||
size: 15, color: Color(0xFF10B981)),
|
||||
const SizedBox(width: 8),
|
||||
const Text('الإجابة الصحيحة: ',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFF94A3B8))),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.correctAnswer,
|
||||
style: const TextStyle(
|
||||
fontSize: 12.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Color(0xFF34D399),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Socratic Hint Box
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF451A03),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: const Color(0xFFF59E0B).withOpacity(0.3)),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(CupertinoIcons.lightbulb_fill,
|
||||
size: 16, color: Color(0xFFFBBF24)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.socraticHint,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFFFEF3C7),
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Action Button
|
||||
if (!item.isMastered)
|
||||
ElevatedButton.icon(
|
||||
onPressed: () => _startRemediation(item),
|
||||
icon: const Icon(CupertinoIcons.bolt_horizontal_circle_fill, size: 17),
|
||||
label: const Text(
|
||||
'بدء المسار العلاجي لسد هذه الفجوة (3 أسئلة تفريدية) 🚀',
|
||||
style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.w800),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0284C7),
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: const Size(double.infinity, 42),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF064E3B).withOpacity(0.3),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFF10B981).withOpacity(0.4)),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(CupertinoIcons.checkmark_seal_fill,
|
||||
color: Color(0xFF34D399), size: 16),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'تم إتقان المهارة وسد الفجوة المعرفية بنجاح 🏆',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Color(0xFF6EE7B7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// ==============================================================================
|
||||
/// REMEDIATION MODAL SHEET (3 TARGETED DRILL QUESTIONS)
|
||||
/// ==============================================================================
|
||||
class _RemediationModalSheet extends StatefulWidget {
|
||||
final ErrorNotebookItem errorItem;
|
||||
final ErrorNotebookRepository repository;
|
||||
final VoidCallback onRemediationCompleted;
|
||||
|
||||
const _RemediationModalSheet({
|
||||
required this.errorItem,
|
||||
required this.repository,
|
||||
required this.onRemediationCompleted,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_RemediationModalSheet> createState() => _RemediationModalSheetState();
|
||||
}
|
||||
|
||||
class _RemediationModalSheetState extends State<_RemediationModalSheet> {
|
||||
bool _isLoadingQuiz = true;
|
||||
List<RemedialQuestion> _questions = [];
|
||||
int _currentQuestionIndex = 0;
|
||||
int? _selectedOptionIndex;
|
||||
bool _hasAnsweredCurrent = false;
|
||||
int _correctAnswersCount = 0;
|
||||
bool _isCompleted = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fetchQuiz();
|
||||
}
|
||||
|
||||
Future<void> _fetchQuiz() async {
|
||||
final qs = await widget.repository.getRemediationQuiz(
|
||||
errorUuid: widget.errorItem.uuid,
|
||||
topicName: widget.errorItem.topicName,
|
||||
);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_questions = qs;
|
||||
_isLoadingQuiz = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _submitAnswer() {
|
||||
if (_selectedOptionIndex == null || _hasAnsweredCurrent) return;
|
||||
|
||||
final q = _questions[_currentQuestionIndex];
|
||||
final isCorrect = _selectedOptionIndex == q.correctIndex;
|
||||
|
||||
setState(() {
|
||||
_hasAnsweredCurrent = true;
|
||||
if (isCorrect) {
|
||||
_correctAnswersCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _nextQuestion() async {
|
||||
if (_currentQuestionIndex < _questions.length - 1) {
|
||||
setState(() {
|
||||
_currentQuestionIndex++;
|
||||
_selectedOptionIndex = null;
|
||||
_hasAnsweredCurrent = false;
|
||||
});
|
||||
} else {
|
||||
// Completed drill
|
||||
setState(() => _isCompleted = true);
|
||||
if (_correctAnswersCount >= 2) {
|
||||
await widget.repository.resolveError(widget.errorItem.uuid);
|
||||
widget.onRemediationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Container(
|
||||
height: MediaQuery.of(context).size.height * 0.85,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF0F172A),
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
border: Border(top: BorderSide(color: Color(0xFF38BDF8), width: 2)),
|
||||
),
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: _isLoadingQuiz
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(color: Color(0xFF38BDF8)),
|
||||
)
|
||||
: _isCompleted
|
||||
? _buildCompletionState()
|
||||
: _buildQuestionState(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQuestionState() {
|
||||
final q = _questions[_currentQuestionIndex];
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Top Handle & Progress Header
|
||||
Center(
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF334155),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'المسار العلاجي (${_currentQuestionIndex + 1} من ${_questions.length})',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Color(0xFF38BDF8),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(CupertinoIcons.xmark, color: Colors.white70),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
Text(
|
||||
q.question,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Options
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: q.options.length,
|
||||
itemBuilder: (ctx, idx) {
|
||||
final optText = q.options[idx];
|
||||
final isSel = _selectedOptionIndex == idx;
|
||||
final isCorrectOpt = idx == q.correctIndex;
|
||||
|
||||
Color borderCol = const Color(0xFF1E293B);
|
||||
Color bgCol = const Color(0xFF161F30);
|
||||
|
||||
if (_hasAnsweredCurrent) {
|
||||
if (isCorrectOpt) {
|
||||
borderCol = const Color(0xFF10B981);
|
||||
bgCol = const Color(0xFF064E3B);
|
||||
} else if (isSel) {
|
||||
borderCol = const Color(0xFFEF4444);
|
||||
bgCol = const Color(0xFF7F1D1D);
|
||||
}
|
||||
} else if (isSel) {
|
||||
borderCol = const Color(0xFF38BDF8);
|
||||
bgCol = const Color(0xFF0369A1);
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: _hasAnsweredCurrent
|
||||
? null
|
||||
: () => setState(() => _selectedOptionIndex = idx),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(bottom: 10),
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: bgCol,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: borderCol, width: 1.5),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 26,
|
||||
height: 26,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'${idx + 1}',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
optText,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// Explanation if answered
|
||||
if (_hasAnsweredCurrent)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF1E293B),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
q.explanation,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFFCBD5E1),
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Action Button
|
||||
ElevatedButton(
|
||||
onPressed: !_hasAnsweredCurrent
|
||||
? (_selectedOptionIndex != null ? _submitAnswer : null)
|
||||
: _nextQuestion,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _hasAnsweredCurrent
|
||||
? const Color(0xFF10B981)
|
||||
: const Color(0xFF38BDF8),
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
!_hasAnsweredCurrent
|
||||
? 'تأكيد الإجابة'
|
||||
: (_currentQuestionIndex < _questions.length - 1
|
||||
? 'السؤال التالي ➔'
|
||||
: 'إنهاء المسار العلاجي 🏆'),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w800),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCompletionState() {
|
||||
final passed = _correctAnswersCount >= 2;
|
||||
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
passed
|
||||
? CupertinoIcons.check_mark_circled_solid
|
||||
: CupertinoIcons.exclamationmark_triangle_fill,
|
||||
size: 64,
|
||||
color: passed ? const Color(0xFF10B981) : const Color(0xFFF59E0B),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
passed
|
||||
? 'مبارك! تم إتقان المهارة وسد الفجوة بنجاح 🎉'
|
||||
: 'أحسنت المحاولة، راجع الشرح وأعد الاختبار',
|
||||
style: const TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
passed
|
||||
? 'أجبت عن $_correctAnswersCount من ${_questions.length} أسئلة بشكل سليم. تم ترحيل الخطأ إلى أرشيف المتقنات.'
|
||||
: 'أجبت عن $_correctAnswersCount من ${_questions.length}. حاول مجدداً لضمان إتقان السؤال في الامتحان الوزاري.',
|
||||
style: const TextStyle(fontSize: 13, color: Color(0xFF94A3B8)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: passed ? const Color(0xFF10B981) : const Color(0xFF38BDF8),
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'العودة إلى دفتر الأخطاء',
|
||||
style: TextStyle(fontWeight: FontWeight.w800),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user