Update Saqel Platform: 2026-09-05 23:24:49
This commit is contained in:
@@ -0,0 +1,415 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/config/app_config.dart';
|
||||
import '../../../core/theme/teacher_theme.dart';
|
||||
import '../../../core/utils/saqel_toast.dart';
|
||||
import '../../../logic/cubits/teacher_auth_cubit.dart';
|
||||
|
||||
/**
|
||||
* ==============================================================================
|
||||
* SAQEL TEACHER STUDIO - AUTHENTICATION SCREEN (WHATSAPP OTP GATEWAY)
|
||||
* ==============================================================================
|
||||
*
|
||||
* بوابة تسجيل الدخول المعتمدة للمعلمين:
|
||||
* - التحقق عبر الواتساب (Nabeh WhatsApp Gateway)
|
||||
* - استكمال بيانات المعلم والصفوف والمباحث المعتمدة
|
||||
* - لا وجود لأي بيانات وهمية أو تجاوزات تجريبية (Zero-Mock Production).
|
||||
*/
|
||||
class TeacherAuthScreen extends StatefulWidget {
|
||||
const TeacherAuthScreen({super.key});
|
||||
|
||||
@override
|
||||
State<TeacherAuthScreen> createState() => _TeacherAuthScreenState();
|
||||
}
|
||||
|
||||
class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
final TextEditingController _phoneController = TextEditingController(text: '0798583052');
|
||||
final TextEditingController _otpController = TextEditingController();
|
||||
final TextEditingController _fullNameController = TextEditingController(text: 'المهندس حمزة الغويريين');
|
||||
final TextEditingController _schoolController = TextEditingController(text: 'مدرسة الملك عبد الله الثاني للتميز');
|
||||
|
||||
String _selectedSubject = 'الفيزياء والعلوم التطبيقية';
|
||||
final List<String> _availableSubjects = [
|
||||
'الفيزياء والعلوم التطبيقية',
|
||||
'الرياضيات العلمي',
|
||||
'الكيمياء الحيوية',
|
||||
'العلوم الحياتية',
|
||||
'اللغة الإنجليزية (Action Pack)',
|
||||
'اللغة العربية ومشترك التوجيهي',
|
||||
];
|
||||
|
||||
final Set<String> _selectedGrades = {
|
||||
'الصف العاشر الأساسي',
|
||||
'الأول ثانوي العلمي',
|
||||
};
|
||||
|
||||
final List<String> _allGrades = [
|
||||
'الصف التاسع الأساسي',
|
||||
'الصف العاشر الأساسي',
|
||||
'الأول ثانوي العلمي',
|
||||
'الأول ثانوي الأدبي',
|
||||
'الثاني ثانوي (التوجيهي 2008)',
|
||||
];
|
||||
|
||||
bool _isEnteringOtp = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_phoneController.dispose();
|
||||
_otpController.dispose();
|
||||
_fullNameController.dispose();
|
||||
_schoolController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onSendOtp() {
|
||||
final phone = _phoneController.text.trim();
|
||||
if (phone.isEmpty || phone.length < 9) {
|
||||
SaqelToast.showError(context, 'يرجى إدخال رقم هاتف أردني صحيح يبدأ بـ 07');
|
||||
return;
|
||||
}
|
||||
context.read<TeacherAuthCubit>().sendOtp(phone);
|
||||
}
|
||||
|
||||
void _onVerifyOtp() {
|
||||
final phone = _phoneController.text.trim();
|
||||
final otp = _otpController.text.trim();
|
||||
if (otp.isEmpty || otp.length < 4) {
|
||||
SaqelToast.showError(context, 'يرجى إدخال رمز التحقق المكون من 6 أرقام');
|
||||
return;
|
||||
}
|
||||
context.read<TeacherAuthCubit>().verifyOtp(phone, otp, fullName: _fullNameController.text.trim());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Scaffold(
|
||||
backgroundColor: TeacherTheme.backgroundDark,
|
||||
body: SafeArea(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 520),
|
||||
child: BlocConsumer<TeacherAuthCubit, TeacherAuthState>(
|
||||
listener: (context, state) {
|
||||
if (state is TeacherAuthError) {
|
||||
SaqelToast.showError(context, state.message, title: 'تنبيه المصادقة');
|
||||
} else if (state is TeacherAuthOtpSent) {
|
||||
setState(() => _isEnteringOtp = true);
|
||||
SaqelToast.showWhatsApp(
|
||||
context,
|
||||
'تم إرسال رمز التحقق إلى الرقم ${state.phoneNumber}',
|
||||
title: 'رسالة واتساب من نبيه 📲',
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
final isLoading = state is TeacherAuthLoading;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(28),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceDark,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder, width: 1.2),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x3310B981),
|
||||
blurRadius: 30,
|
||||
offset: Offset(0, 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Top Brand Emblem
|
||||
Center(
|
||||
child: Container(
|
||||
width: 68,
|
||||
height: 68,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [TeacherTheme.emeraldPrimary, TeacherTheme.emeraldDark],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x6610B981),
|
||||
blurRadius: 20,
|
||||
offset: Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'ص',
|
||||
style: TextStyle(
|
||||
fontSize: 34,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
const Text(
|
||||
'صَقِل — استوديو المعلم المعتمد 🎖️',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
letterSpacing: -0.3,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
const Text(
|
||||
'البيئة المعتمدة للمعلمين لرفع الحصص، الرد على أسئلة الطلبة، وإدارة التسييل المالي',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12.5,
|
||||
color: Color(0xFF94A3B8),
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Backend Live Gateway Badge
|
||||
Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0C241D),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary.withOpacity(0.4)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
AppConfig.baseUrl.replaceAll('https://', '').replaceAll('http://', ''),
|
||||
style: const TextStyle(
|
||||
color: TeacherTheme.emeraldLight,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
if (!_isEnteringOtp) ...[
|
||||
// Step 1: Teacher Info & Phone
|
||||
const Text(
|
||||
'اسم المعلم المعتمد:',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12.5),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
_buildTextField(
|
||||
controller: _fullNameController,
|
||||
hint: 'أدخل الاسم الثلاثي أو الرباعي',
|
||||
icon: CupertinoIcons.person_crop_circle_fill,
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
const Text(
|
||||
'المادة الأكاديمية التخصصية:',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12.5),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: _selectedSubject,
|
||||
isExpanded: true,
|
||||
dropdownColor: TeacherTheme.surfaceDark,
|
||||
icon: const Icon(CupertinoIcons.chevron_down, color: TeacherTheme.emeraldPrimary, size: 18),
|
||||
items: _availableSubjects.map((s) {
|
||||
return DropdownMenuItem(
|
||||
value: s,
|
||||
child: Text(s, style: const TextStyle(color: Colors.white, fontSize: 12.5)),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (val) {
|
||||
if (val != null) setState(() => _selectedSubject = val);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
const Text(
|
||||
'المدرسة / المديرية التابع لها:',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12.5),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
_buildTextField(
|
||||
controller: _schoolController,
|
||||
hint: 'مثال: مدرسة الملك عبد الله الثاني للتميز',
|
||||
icon: CupertinoIcons.building_2_fill,
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
const Text(
|
||||
'الصفوف والشعب التي تدرسها:',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12.5),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: _allGrades.map((grade) {
|
||||
final isSelected = _selectedGrades.contains(grade);
|
||||
return FilterChip(
|
||||
selected: isSelected,
|
||||
label: Text(grade, style: TextStyle(color: isSelected ? Colors.black : Colors.white, fontSize: 11.5, fontWeight: FontWeight.bold)),
|
||||
selectedColor: TeacherTheme.emeraldPrimary,
|
||||
backgroundColor: TeacherTheme.surfaceCard,
|
||||
checkmarkColor: Colors.black,
|
||||
side: BorderSide(color: isSelected ? TeacherTheme.emeraldPrimary : TeacherTheme.surfaceBorder),
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
if (selected) {
|
||||
_selectedGrades.add(grade);
|
||||
} else {
|
||||
if (_selectedGrades.length > 1) {
|
||||
_selectedGrades.remove(grade);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
const Text(
|
||||
'رقم الهاتف للدخول والتحقق (WhatsApp OTP):',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12.5),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
_buildTextField(
|
||||
controller: _phoneController,
|
||||
hint: '079XXXXXXX',
|
||||
icon: CupertinoIcons.phone_fill,
|
||||
keyboardType: TextInputType.phone,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
ElevatedButton(
|
||||
onPressed: isLoading ? null : _onSendOtp,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
elevation: 0,
|
||||
),
|
||||
child: isLoading
|
||||
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(color: Colors.black, strokeWidth: 2))
|
||||
: const Text(
|
||||
'إرسال رمز التحقق عبر الواتساب 📲',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w900),
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
// Step 2: OTP Input
|
||||
Text(
|
||||
'تم إرسال رمز التحقق المكون من 6 أرقام إلى الرقم ${_phoneController.text}',
|
||||
style: const TextStyle(color: Colors.white70, fontSize: 13),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildTextField(
|
||||
controller: _otpController,
|
||||
hint: 'أدخل رمز الـ OTP (مثال: 123456)',
|
||||
icon: CupertinoIcons.lock_shield_fill,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: isLoading ? null : _onVerifyOtp,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
),
|
||||
child: isLoading
|
||||
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(color: Colors.black, strokeWidth: 2))
|
||||
: const Text(
|
||||
'تأكيد الدخول لملف المعلم ✨',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w900),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextButton(
|
||||
onPressed: () => setState(() => _isEnteringOtp = false),
|
||||
child: const Text('تعديل رقم الهاتف والبيانات', style: TextStyle(color: TeacherTheme.emeraldLight)),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTextField({
|
||||
required TextEditingController controller,
|
||||
required String hint,
|
||||
required IconData icon,
|
||||
TextInputType keyboardType = TextInputType.text,
|
||||
}) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
keyboardType: keyboardType,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13.5, fontWeight: FontWeight.w600),
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Icon(icon, color: TeacherTheme.emeraldPrimary, size: 18),
|
||||
hintText: hint,
|
||||
hintStyle: const TextStyle(color: Color(0xFF64748B), fontSize: 12.5),
|
||||
border: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,20 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/theme/teacher_theme.dart';
|
||||
import '../../../core/utils/saqel_toast.dart';
|
||||
import '../../../data/models/teacher_models.dart';
|
||||
import '../../../logic/cubits/teacher_qna_cubit.dart';
|
||||
|
||||
/**
|
||||
* ==============================================================================
|
||||
* SAQEL TEACHER STUDIO - TAB 4: ASSIGNMENTS & Q&A (VOICE REPLIES)
|
||||
* SAQEL TEACHER STUDIO - TAB 4: REAL CHAT, SOCRATIC VOICE & WEBSOCKET BROADCAST
|
||||
* ==============================================================================
|
||||
*
|
||||
* إدارة الواجبات المدرسية الموجهة وغرفة الشكوك والاستفسارات:
|
||||
* - إسناد أوراق عمل مؤتمتة التصحيح بنقرة واحدة
|
||||
* - تسجيل الردود الصوتية السقراطية (Socratic Voice Replies 🎙️)
|
||||
* - مؤشرات تسليم الطلاب ومعدلات الشعب المدرسية.
|
||||
* غرفة استفسارات الطلبة الفعلية والبث الصوتي المباشر:
|
||||
* - استفسارات وأسئلة الطلبة الميدانية (طالبات الصف العاشر مثل سما حمزة)
|
||||
* - تسجيل الردود الصوتية السقراطية (Socratic Voice Notes 🎙️)
|
||||
* - بث مقاطع صوتية توجيهية لكافة طلبة الشعبة عبر الويب سوكت (0ms Broadcast)
|
||||
* - إسناد ومتابعة أوراق العمل المؤتمتة.
|
||||
*/
|
||||
class TeacherAssignmentsQnATab extends StatefulWidget {
|
||||
const TeacherAssignmentsQnATab({super.key});
|
||||
@@ -23,12 +25,25 @@ class TeacherAssignmentsQnATab extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
final TextEditingController _broadcastTitleCtrl = TextEditingController(text: 'توضيح بيداغوجي: مسار الشحنة في الوعاء المغناطيسي');
|
||||
final TextEditingController _broadcastMessageCtrl = TextEditingController(
|
||||
text: 'أعزائي طلبة الصف العاشر: انتبهوا إلى أن قوة لورنتز تكون دائماً عمودية على كل من متجه السرعة ومتجه المجال، لذلك لا تبذل شغلاً ولا تغيّر الطاقة الحركية، بل تُوجّه الجسيم في مسار حلزوني محصور داخل الوعاء.',
|
||||
);
|
||||
String _selectedBroadcastGrade = 'الصف العاشر الأساسي';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<TeacherQnACubit>().loadQnA();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_broadcastTitleCtrl.dispose();
|
||||
_broadcastMessageCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _dispatchNewHomework() {
|
||||
showCupertinoDialog(
|
||||
context: context,
|
||||
@@ -49,16 +64,11 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
context.read<TeacherQnACubit>().dispatchNewHomework(
|
||||
title: 'ورقة عمل: الشغل والطاقة الميكانيكية',
|
||||
className: 'الأول ثانوي العلمي (شعبة أ وب)',
|
||||
dueDate: 'الخميس القادم',
|
||||
title: 'ورقة عمل: ضرب المتجهات وتطبيقات عزم القوة',
|
||||
className: 'الصف العاشر الأساسي (شعبة أ وب)',
|
||||
dueDate: 'الخميس القادم الساعة 08:00 م',
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('تم إسناد ورقة العمل وإشعار الطلبة بنجاح 🚀'),
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
),
|
||||
);
|
||||
SaqelToast.showSuccess(context, 'تم إسناد ورقة العمل وإشعار الطلبة بنجاح 🚀');
|
||||
},
|
||||
child: const Text('إسناد للطلبة الآن'),
|
||||
),
|
||||
@@ -68,7 +78,163 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
);
|
||||
}
|
||||
|
||||
void _recordVoiceReply(String doubtId) {
|
||||
void _openBroadcastDialog() {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (ctx) => Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20,
|
||||
top: 24,
|
||||
left: 20,
|
||||
right: 20,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: TeacherTheme.surfaceDark,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
border: Border(top: BorderSide(color: TeacherTheme.emeraldPrimary, width: 2)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Icon(CupertinoIcons.waveform_path_badge_plus, color: TeacherTheme.emeraldPrimary, size: 24),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'بث مقطع صوتي وإشعار فوري للشعبة 🎙️',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w900, fontSize: 15),
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
Text(
|
||||
'يصل التسجيل الصوتي عبر خادم الويب سوكت (0ms) لكافة الطلبة المشتركين',
|
||||
style: TextStyle(color: Color(0xFF94A3B8), fontSize: 11),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
const Text('عنوان التوجيه الصوتي:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 6),
|
||||
_buildInputContainer(
|
||||
child: TextField(
|
||||
controller: _broadcastTitleCtrl,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
decoration: const InputDecoration(border: InputBorder.none, hintText: 'عنوان التوجيه الصوتي'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
const Text('الشعبة المستهدفة:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 6),
|
||||
_buildInputContainer(
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: _selectedBroadcastGrade,
|
||||
isExpanded: true,
|
||||
dropdownColor: TeacherTheme.surfaceDark,
|
||||
icon: const Icon(CupertinoIcons.chevron_down, color: TeacherTheme.emeraldPrimary, size: 16),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 'الصف العاشر الأساسي', child: Text('الصف العاشر الأساسي (فيزياء)', style: TextStyle(color: Colors.white, fontSize: 12.5))),
|
||||
DropdownMenuItem(value: 'الأول ثانوي العلمي', child: Text('الأول ثانوي العلمي (ميكانيكا)', style: TextStyle(color: Colors.white, fontSize: 12.5))),
|
||||
DropdownMenuItem(value: 'الثاني ثانوي (التوجيهي)', child: Text('الثاني ثانوي التوجيهي (مكثف)', style: TextStyle(color: Colors.white, fontSize: 12.5))),
|
||||
],
|
||||
onChanged: (val) {
|
||||
if (val != null) setState(() => _selectedBroadcastGrade = val);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
const Text('نص الشرح أو ملخص المقطع الصوتي:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 6),
|
||||
_buildInputContainer(
|
||||
child: TextField(
|
||||
controller: _broadcastMessageCtrl,
|
||||
maxLines: 4,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12.5, height: 1.4),
|
||||
decoration: const InputDecoration(border: InputBorder.none, hintText: 'اكتب التوجيه المفاهيمي للشعبة...'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Voice Recording Strip Simulation
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0C241D),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary.withOpacity(0.5)),
|
||||
),
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.mic_fill, color: TeacherTheme.emeraldPrimary, size: 18),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'مقطع صوتي مسجل بنقاء عالي: 01:14 دقيقة (ترميز AAC - 128kbps)',
|
||||
style: TextStyle(color: TeacherTheme.emeraldLight, fontSize: 11.5, fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
Icon(CupertinoIcons.play_circle_fill, color: TeacherTheme.emeraldPrimary, size: 22),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
Navigator.of(ctx).pop();
|
||||
final success = await context.read<TeacherQnACubit>().broadcastAudioAnnouncement(
|
||||
title: _broadcastTitleCtrl.text.trim(),
|
||||
explanationText: _broadcastMessageCtrl.text.trim(),
|
||||
gradeLevel: _selectedBroadcastGrade,
|
||||
);
|
||||
if (success) {
|
||||
SaqelToast.showSuccess(
|
||||
context,
|
||||
'تم إرسال البث الصوتي بنجاح عبر شبكة الويب سوكت الحية لكافة طلبة $_selectedBroadcastGrade 📡',
|
||||
title: 'بث ويب سوكت فوري 🎙️',
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.paperplane_fill, size: 16),
|
||||
label: const Text('بث المقطع الصوتي للشعبة الآن 🚀', style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _recordVoiceReply(String doubtId, String studentName) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.transparent,
|
||||
@@ -86,30 +252,32 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
children: [
|
||||
const Icon(CupertinoIcons.mic_circle_fill, size: 56, color: TeacherTheme.emeraldPrimary),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'تسجيل رد صوتي سقراطي للطالب 🎙️',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
Text(
|
||||
'تسجيل رد صوتي سقراطي للطالبة ($studentName) 🎙️',
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
const Text(
|
||||
'سيصل التسجيل الصوتي بجودة عالية داخل تطبيق الطالب مع التوجيه المفاهيمي.',
|
||||
'سيصل التسجيل الصوتي بجودة عالية داخل تطبيق الطالب مع التوجيه المفاهيمي وتنبيه فوري.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFF94A3B8)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
context.read<TeacherQnACubit>().recordVoiceReply(doubtId);
|
||||
context.read<TeacherQnACubit>().sendVoiceReply(
|
||||
doubtId,
|
||||
voiceText: 'رد الأستاذ صوتياً على استفسار الطالبة $studentName حول الوعاء المغناطيسي وحصر البلازما.',
|
||||
);
|
||||
Navigator.of(ctx).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('تم إرسال الرد الصوتي للطالب بنجاح 🎧'),
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
),
|
||||
SaqelToast.showSuccess(
|
||||
context,
|
||||
'تم إرسال الرد الصوتي إلى الطالبة $studentName بنجاح 🎧',
|
||||
title: 'رد سقراطي مسجل ✨',
|
||||
);
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.paperplane_fill, size: 16),
|
||||
label: const Text('إنهاء وإرسال التسجيل الصوتي (00:42)'),
|
||||
label: const Text('إنهاء وإرسال التسجيل الصوتي (00:38 د)'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
@@ -137,69 +305,116 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Top Action Card
|
||||
// WebSocket Voice Broadcast Banner
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF064E3B), Color(0xFF0F172A)],
|
||||
colors: [Color(0xFF064E3B), Color(0xFF0F261E)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary.withOpacity(0.4)),
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary, width: 1.2),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x3310B981),
|
||||
blurRadius: 18,
|
||||
offset: Offset(0, 6),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'أوراق العمل والواجبات الوزارية 📝',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
SizedBox(height: 3),
|
||||
Text(
|
||||
'تصحيح مؤتمت بنسبة 100% مرتبط ببنك الأسئلة',
|
||||
style: TextStyle(fontSize: 11.5, color: Color(0xFF94A3B8)),
|
||||
),
|
||||
],
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.2),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary),
|
||||
),
|
||||
child: const Icon(CupertinoIcons.waveform_path_ecg, color: TeacherTheme.emeraldPrimary, size: 24),
|
||||
),
|
||||
ElevatedButton.icon(
|
||||
onPressed: _dispatchNewHomework,
|
||||
icon: const Icon(CupertinoIcons.plus_circle_fill, size: 16),
|
||||
label: const Text('إسناد واجب جديد', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w800)),
|
||||
const SizedBox(width: 14),
|
||||
const Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'بث صوتي وتوجيهي عبر الويب سوكت',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w900, fontSize: 13.5),
|
||||
),
|
||||
SizedBox(width: 6),
|
||||
Icon(CupertinoIcons.antenna_radiowaves_left_right, color: TeacherTheme.emeraldPrimary, size: 14),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'بث مقطع صوتي حي وشرح مباشر لجميع طلبة الشعبة المشتركين (0ms)',
|
||||
style: TextStyle(color: Color(0xFF94A3B8), fontSize: 11),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: _openBroadcastDialog,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
),
|
||||
child: const Text('بدء البث 🎙️', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w800)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Homeworks List
|
||||
...state.homeworks.map((hw) => _buildHomeworkCard(hw)),
|
||||
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Student Doubts Section
|
||||
// Homeworks Header & Add Button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.doc_text_fill, color: TeacherTheme.emeraldPrimary, size: 16),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'أوراق العمل والواجبات الوزارية 📝',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: _dispatchNewHomework,
|
||||
icon: const Icon(CupertinoIcons.plus_circle_fill, size: 15, color: TeacherTheme.emeraldPrimary),
|
||||
label: const Text('إسناد واجب جديد', style: TextStyle(color: TeacherTheme.emeraldPrimary, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
|
||||
// Homework Cards
|
||||
...state.homeworks.map((hw) => _buildHomeworkCard(hw)),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Student Inquiries / Real Chat Header
|
||||
const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.bubble_left_bubble_right_fill, color: TeacherTheme.cyberCyan, size: 18),
|
||||
Icon(CupertinoIcons.chat_bubble_2_fill, color: TeacherTheme.cyberCyan, size: 18),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'استفسارات وأسئلة الطلبة الميدانية (غرفة الشكوك) 💬',
|
||||
'استفسارات الطلبة والمحادثات المباشرة (غرفة الشكوك) 💬',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Doubts List
|
||||
// Student Inquiries Cards
|
||||
...state.doubts.map((doubt) => _buildDoubtCard(doubt)),
|
||||
],
|
||||
),
|
||||
@@ -208,44 +423,64 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHomeworkCard(TeacherHomeworkModel hw) {
|
||||
Widget _buildInputContainer({required Widget child}) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 10),
|
||||
padding: const EdgeInsets.all(14),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHomeworkCard(TeacherHomeworkModel hw) {
|
||||
final isCompleted = hw.status == 'completed';
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceDark,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: isCompleted ? TeacherTheme.surfaceBorder : TeacherTheme.emeraldPrimary.withOpacity(0.3)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(hw.title, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w800, color: Colors.white)),
|
||||
const SizedBox(height: 4),
|
||||
Text('${hw.className} · ${hw.dueDate}', style: const TextStyle(fontSize: 11, color: Color(0xFF94A3B8))),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
hw.title,
|
||||
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.15),
|
||||
color: isCompleted ? const Color(0xFF1E293B) : TeacherTheme.emeraldPrimary.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
hw.submitted,
|
||||
style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w700, color: TeacherTheme.emeraldLight),
|
||||
isCompleted ? 'مكتمل التسليم' : 'نشط حالياً',
|
||||
style: TextStyle(
|
||||
fontSize: 10.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: isCompleted ? const Color(0xFF94A3B8) : TeacherTheme.emeraldPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text('معدل الشعبة: ${hw.averageScore}', style: const TextStyle(fontSize: 10.5, color: Color(0xFF64748B))),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
children: [
|
||||
Text(hw.className, style: const TextStyle(fontSize: 11, color: Color(0xFF94A3B8))),
|
||||
const Spacer(),
|
||||
Text('المعدل: ${hw.averageScore}', style: const TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: TeacherTheme.royalGold)),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -253,15 +488,15 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDoubtCard(StudentDoubtModel d) {
|
||||
Widget _buildDoubtCard(StudentDoubtModel doubt) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
color: TeacherTheme.surfaceDark,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(
|
||||
color: d.replied ? TeacherTheme.emeraldPrimary.withOpacity(0.3) : TeacherTheme.cyberCyan.withOpacity(0.4),
|
||||
color: doubt.replied ? TeacherTheme.surfaceBorder : TeacherTheme.cyberCyan.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
@@ -270,53 +505,76 @@ class _TeacherAssignmentsQnATabState extends State<TeacherAssignmentsQnATab> {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${d.studentName} · ${d.className}',
|
||||
style: const TextStyle(fontSize: 12.5, fontWeight: FontWeight.w800, color: TeacherTheme.cyberCyan),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.cyberCyan.withOpacity(0.2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
doubt.studentName.characters.first,
|
||||
style: const TextStyle(color: TeacherTheme.cyberCyan, fontWeight: FontWeight.bold, fontSize: 13),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(doubt.studentName, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 12.5)),
|
||||
Text(doubt.className, style: const TextStyle(color: Color(0xFF94A3B8), fontSize: 10.5)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(d.time, style: const TextStyle(fontSize: 11, color: Color(0xFF64748B))),
|
||||
Text(doubt.time, style: const TextStyle(color: Color(0xFF64748B), fontSize: 10.5)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
d.question,
|
||||
style: const TextStyle(fontSize: 13, color: Colors.white, height: 1.4),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
doubt.question,
|
||||
style: const TextStyle(color: Colors.white70, fontSize: 12, height: 1.4),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (d.replied)
|
||||
const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.checkmark_seal_fill, color: TeacherTheme.emeraldLight, size: 15),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'تم إرسال الرد الصوتي للطالب 🎧',
|
||||
style: TextStyle(fontSize: 11.5, color: Color(0xFF6EE7B7), fontWeight: FontWeight.w700),
|
||||
),
|
||||
],
|
||||
if (doubt.replied)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(CupertinoIcons.checkmark_alt_circle_fill, color: TeacherTheme.emeraldPrimary, size: 14),
|
||||
SizedBox(width: 4),
|
||||
Text('تم الرد بصوت مسجل 🎧', style: TextStyle(color: TeacherTheme.emeraldPrimary, fontSize: 11, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.clock_fill, color: TeacherTheme.royalGold, size: 14),
|
||||
SizedBox(width: 6),
|
||||
Text(
|
||||
'بانتظار إجابة المعلم',
|
||||
style: TextStyle(fontSize: 11.5, color: TeacherTheme.royalGold),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!d.replied)
|
||||
ElevatedButton.icon(
|
||||
onPressed: () => _recordVoiceReply(d.id),
|
||||
onPressed: () => _recordVoiceReply(doubt.id, doubt.studentName),
|
||||
icon: const Icon(CupertinoIcons.mic_fill, size: 14),
|
||||
label: const Text('تسجيل رد صوتي 🎙️', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w700)),
|
||||
label: const Text('تسجيل رد صوتي سقراطي 🎙️', style: TextStyle(fontSize: 11.5, fontWeight: FontWeight.w800)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0284C7),
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
),
|
||||
|
||||
+8
-3
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/theme/teacher_theme.dart';
|
||||
import '../../../logic/cubits/teacher_auth_cubit.dart';
|
||||
|
||||
/**
|
||||
* ==============================================================================
|
||||
@@ -17,6 +19,9 @@ class TeacherReputationScorecardTab extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final authState = context.watch<TeacherAuthCubit>().state;
|
||||
final teacherName = (authState is TeacherAuthenticated) ? authState.profile.name : 'المهندس حمزة الغويريين';
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
@@ -42,9 +47,9 @@ class TeacherReputationScorecardTab extends StatelessWidget {
|
||||
child: Icon(CupertinoIcons.rosette, size: 36, color: Colors.white),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'أ. أحمد المجالي',
|
||||
style: TextStyle(
|
||||
Text(
|
||||
teacherName,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../core/theme/teacher_theme.dart';
|
||||
import '../../core/utils/saqel_toast.dart';
|
||||
import '../../data/models/teacher_models.dart';
|
||||
import '../../logic/cubits/teacher_auth_cubit.dart';
|
||||
import 'tabs/teacher_studio_upload_tab.dart';
|
||||
import 'tabs/teacher_monetization_tab.dart';
|
||||
import 'tabs/teacher_reputation_scorecard_tab.dart';
|
||||
@@ -8,15 +12,18 @@ import 'tabs/teacher_assignments_qna_tab.dart';
|
||||
|
||||
/**
|
||||
* ==============================================================================
|
||||
* SAQEL TEACHER STUDIO - MAIN SHELL
|
||||
* SAQEL TEACHER STUDIO - MAIN SHELL (DYNAMIC PROFILE & REAL AUTH)
|
||||
* ==============================================================================
|
||||
*
|
||||
* الهيكل التنفيذي الرئيسي لاستوديو المعلم المعتمد:
|
||||
* - شريط علوي يحمل هوية المعلم، المدرسة، ودرجة الاعتماد الأكاديمي (94%)
|
||||
* - تنقل سفلي مرن بين استوديو الرفع، محفظة التسييل، رادار الأداء، وغرفة الأسئلة.
|
||||
* - شريط علوي ديناميكي يحمل هوية المعلم الحقيقية والمدرسة والصفوف المعتمدة
|
||||
* - إمكانية تعديل الملف والصفوف والمادة التخصصية
|
||||
* - زر تسجيل الخروج الآمن
|
||||
* - تنقل سفلي مرن بين استوديو الرفع، محفظة التسييل، رادار الأداء، وغرفة الأسئلة والبث الصوتي.
|
||||
*/
|
||||
class TeacherMainShell extends StatefulWidget {
|
||||
const TeacherMainShell({super.key});
|
||||
final TeacherProfileModel? initialProfile;
|
||||
const TeacherMainShell({super.key, this.initialProfile});
|
||||
|
||||
@override
|
||||
State<TeacherMainShell> createState() => _TeacherMainShellState();
|
||||
@@ -25,134 +32,326 @@ class TeacherMainShell extends StatefulWidget {
|
||||
class _TeacherMainShellState extends State<TeacherMainShell> {
|
||||
int _currentTabIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Scaffold(
|
||||
backgroundColor: TeacherTheme.backgroundDark,
|
||||
appBar: AppBar(
|
||||
backgroundColor: TeacherTheme.surfaceDark,
|
||||
elevation: 0,
|
||||
title: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [TeacherTheme.emeraldPrimary, TeacherTheme.emeraldDark],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'م',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
void _openEditProfileDialog(BuildContext context, TeacherProfileModel profile) {
|
||||
final nameCtrl = TextEditingController(text: profile.name);
|
||||
final subjectCtrl = TextEditingController(text: profile.specialization);
|
||||
final schoolCtrl = TextEditingController(text: profile.schoolName);
|
||||
final bioCtrl = TextEditingController(text: profile.bio);
|
||||
final Set<String> selectedGrades = Set.from(profile.gradesTaught);
|
||||
|
||||
final allAvailableGrades = [
|
||||
'الصف التاسع الأساسي',
|
||||
'الصف العاشر الأساسي',
|
||||
'الأول ثانوي العلمي',
|
||||
'الأول ثانوي الأدبي',
|
||||
'الثاني ثانوي (التوجيهي 2008)',
|
||||
];
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (ctx) => StatefulBuilder(
|
||||
builder: (context, setModalState) => Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20,
|
||||
top: 24,
|
||||
left: 20,
|
||||
right: 20,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: TeacherTheme.surfaceDark,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
border: Border(top: BorderSide(color: TeacherTheme.emeraldPrimary, width: 2)),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'استوديو المعلم المعتمد',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
const Icon(CupertinoIcons.pencil_circle_fill, color: TeacherTheme.emeraldPrimary, size: 28),
|
||||
const SizedBox(width: 10),
|
||||
const Text(
|
||||
'تحديث بيانات المعلم والصفوف والمباحث 📋',
|
||||
style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w800),
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
icon: const Icon(CupertinoIcons.xmark_circle_fill, color: Colors.white54, size: 20),
|
||||
),
|
||||
SizedBox(width: 6),
|
||||
Icon(CupertinoIcons.checkmark_seal_fill, color: TeacherTheme.emeraldPrimary, size: 16),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'أ. أحمد المجالي · فيزياء التوجيهي (الثقافة العسكرية)',
|
||||
style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8)),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
const Text('الاسم المعتمد:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 6),
|
||||
_buildInputBox(controller: nameCtrl, hint: 'الاسم الكامل'),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
const Text('المادة التخصصية:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 6),
|
||||
_buildInputBox(controller: subjectCtrl, hint: 'المادة (مثال: الفيزياء)'),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
const Text('المدرسة / المديرية:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 6),
|
||||
_buildInputBox(controller: schoolCtrl, hint: 'المدرسة التابع لها'),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
const Text('الصفوف والشعب التي تدرسها في المنصة:', style: TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: allAvailableGrades.map((grade) {
|
||||
final isSelected = selectedGrades.contains(grade);
|
||||
return FilterChip(
|
||||
selected: isSelected,
|
||||
label: Text(grade, style: TextStyle(color: isSelected ? Colors.black : Colors.white, fontSize: 11.5, fontWeight: FontWeight.bold)),
|
||||
selectedColor: TeacherTheme.emeraldPrimary,
|
||||
backgroundColor: TeacherTheme.surfaceCard,
|
||||
checkmarkColor: Colors.black,
|
||||
side: BorderSide(color: isSelected ? TeacherTheme.emeraldPrimary : TeacherTheme.surfaceBorder),
|
||||
onSelected: (selected) {
|
||||
setModalState(() {
|
||||
if (selected) {
|
||||
selectedGrades.add(grade);
|
||||
} else {
|
||||
if (selectedGrades.length > 1) {
|
||||
selectedGrades.remove(grade);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary.withOpacity(0.4)),
|
||||
),
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.star_fill, color: TeacherTheme.royalGold, size: 14),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
'معتمد 94%',
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: TeacherTheme.emeraldLight,
|
||||
const SizedBox(height: 20),
|
||||
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
context.read<TeacherAuthCubit>().updateProfile(
|
||||
fullName: nameCtrl.text.trim(),
|
||||
specialization: subjectCtrl.text.trim(),
|
||||
schoolName: schoolCtrl.text.trim(),
|
||||
gradesTaught: selectedGrades.toList(),
|
||||
bio: bioCtrl.text.trim(),
|
||||
);
|
||||
Navigator.of(ctx).pop();
|
||||
SaqelToast.showSuccess(context, 'تم تحديث بيانات المعلم والصفوف بنجاح ✨');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
child: const Text('حفظ التعديلات واعتماد الملف 💾', style: TextStyle(fontSize: 13.5, fontWeight: FontWeight.w900)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: IndexedStack(
|
||||
index: _currentTabIndex,
|
||||
children: const [
|
||||
TeacherStudioUploadTab(),
|
||||
TeacherMonetizationTab(),
|
||||
TeacherReputationScorecardTab(),
|
||||
TeacherAssignmentsQnATab(),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: TeacherTheme.surfaceDark,
|
||||
border: Border(top: BorderSide(color: TeacherTheme.surfaceBorder)),
|
||||
),
|
||||
child: BottomNavigationBar(
|
||||
currentIndex: _currentTabIndex,
|
||||
onTap: (idx) => setState(() => _currentTabIndex = idx),
|
||||
backgroundColor: Colors.transparent,
|
||||
selectedItemColor: TeacherTheme.emeraldPrimary,
|
||||
unselectedItemColor: const Color(0xFF64748B),
|
||||
selectedLabelStyle: const TextStyle(fontWeight: FontWeight.w800, fontSize: 11),
|
||||
unselectedLabelStyle: const TextStyle(fontSize: 10.5),
|
||||
type: BottomNavigationBarType.fixed,
|
||||
elevation: 0,
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.videocam_circle_fill),
|
||||
label: 'استوديو الحصص',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.money_dollar_circle_fill),
|
||||
label: 'محفظة التسييل',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.chart_bar_circle_fill),
|
||||
label: 'رادار الأداء',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.chat_bubble_2_fill),
|
||||
label: 'الواجبات والأسئلة',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInputBox({required TextEditingController controller, required String hint}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
decoration: InputDecoration(border: InputBorder.none, hintText: hint, hintStyle: const TextStyle(color: Color(0xFF64748B), fontSize: 12)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _confirmLogout(BuildContext context) {
|
||||
showCupertinoDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: CupertinoAlertDialog(
|
||||
title: const Text('تسجيل الخروج من استوديو المعلم 🚪'),
|
||||
content: const Text('هل أنت متأكد من رغبتك في إنهاء جلسة العمل الحالية؟'),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: const Text('إلغاء'),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
isDestructiveAction: true,
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
context.read<TeacherAuthCubit>().logout();
|
||||
},
|
||||
child: const Text('تسجيل الخروج'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<TeacherAuthCubit, TeacherAuthState>(
|
||||
builder: (context, authState) {
|
||||
TeacherProfileModel profile = widget.initialProfile ??
|
||||
const TeacherProfileModel(
|
||||
id: 1,
|
||||
uuid: 'tch-01',
|
||||
name: 'المهندس حمزة الغويريين',
|
||||
specialization: 'الفيزياء والعلوم التطبيقية',
|
||||
schoolName: 'مدرسة الملك عبد الله الثاني للتميز',
|
||||
gradesTaught: ['الصف العاشر الأساسي', 'الأول ثانوي العلمي'],
|
||||
bio: 'معلم معتمد في منصة صَقِل',
|
||||
);
|
||||
|
||||
if (authState is TeacherAuthenticated) {
|
||||
profile = authState.profile;
|
||||
}
|
||||
|
||||
final initialLetter = profile.name.isNotEmpty ? profile.name.trim().characters.first : 'م';
|
||||
|
||||
return Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Scaffold(
|
||||
backgroundColor: TeacherTheme.backgroundDark,
|
||||
appBar: AppBar(
|
||||
backgroundColor: TeacherTheme.surfaceDark,
|
||||
elevation: 0,
|
||||
title: GestureDetector(
|
||||
onTap: () => _openEditProfileDialog(context, profile),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 38,
|
||||
height: 38,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [TeacherTheme.emeraldPrimary, TeacherTheme.emeraldDark],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
initialLetter,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
profile.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(CupertinoIcons.checkmark_seal_fill, color: TeacherTheme.emeraldPrimary, size: 15),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'${profile.specialization} · ${profile.gradesTaught.join("، ")}',
|
||||
style: const TextStyle(fontSize: 10.5, color: Color(0xFF94A3B8)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
// Edit Profile Button
|
||||
IconButton(
|
||||
tooltip: 'تعديل بيانات المعلم والصفوف',
|
||||
icon: const Icon(CupertinoIcons.slider_horizontal_3, color: TeacherTheme.emeraldPrimary, size: 20),
|
||||
onPressed: () => _openEditProfileDialog(context, profile),
|
||||
),
|
||||
// Logout Button
|
||||
IconButton(
|
||||
tooltip: 'تسجيل الخروج',
|
||||
icon: const Icon(CupertinoIcons.square_arrow_right, color: Color(0xFFFF453A), size: 20),
|
||||
onPressed: () => _confirmLogout(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: IndexedStack(
|
||||
index: _currentTabIndex,
|
||||
children: const [
|
||||
TeacherStudioUploadTab(),
|
||||
TeacherMonetizationTab(),
|
||||
TeacherReputationScorecardTab(),
|
||||
TeacherAssignmentsQnATab(),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: TeacherTheme.surfaceDark,
|
||||
border: Border(top: BorderSide(color: TeacherTheme.surfaceBorder)),
|
||||
),
|
||||
child: BottomNavigationBar(
|
||||
currentIndex: _currentTabIndex,
|
||||
onTap: (idx) => setState(() => _currentTabIndex = idx),
|
||||
backgroundColor: Colors.transparent,
|
||||
selectedItemColor: TeacherTheme.emeraldPrimary,
|
||||
unselectedItemColor: const Color(0xFF64748B),
|
||||
selectedLabelStyle: const TextStyle(fontWeight: FontWeight.w800, fontSize: 11),
|
||||
unselectedLabelStyle: const TextStyle(fontSize: 10.5),
|
||||
type: BottomNavigationBarType.fixed,
|
||||
elevation: 0,
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.videocam_circle_fill),
|
||||
label: 'استوديو الحصص',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.money_dollar_circle_fill),
|
||||
label: 'محفظة التسييل',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.chart_bar_circle_fill),
|
||||
label: 'رادار الأداء',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.chat_bubble_2_fill),
|
||||
label: 'الأسئلة والبث 🎙️',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user