Update Saqel Platform: 2026-09-08 13:43:36
This commit is contained in:
@@ -79,7 +79,14 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
SaqelToast.showError(context, 'يرجى إدخال رمز التحقق المكون من 6 أرقام');
|
||||
return;
|
||||
}
|
||||
context.read<TeacherAuthCubit>().verifyOtp(phone, otp, fullName: _fullNameController.text.trim());
|
||||
context.read<TeacherAuthCubit>().verifyOtp(
|
||||
phone,
|
||||
otp,
|
||||
fullName: _fullNameController.text.trim(),
|
||||
specialization: _selectedSubject,
|
||||
schoolName: _schoolController.text.trim(),
|
||||
gradesTaught: _selectedGrades.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -109,6 +116,7 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
},
|
||||
builder: (context, state) {
|
||||
final isLoading = state is TeacherAuthLoading;
|
||||
final isOtpStep = _isEnteringOtp || state is TeacherAuthOtpSent;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(28),
|
||||
@@ -217,7 +225,7 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
if (!_isEnteringOtp) ...[
|
||||
if (!isOtpStep) ...[
|
||||
// Step 1: Teacher Info & Phone
|
||||
const Text(
|
||||
'اسم المعلم المعتمد:',
|
||||
@@ -338,20 +346,46 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
// Step 2: OTP Input
|
||||
Text(
|
||||
'تم إرسال رمز التحقق المكون من 6 أرقام إلى الرقم ${_phoneController.text}',
|
||||
style: const TextStyle(color: Colors.white70, fontSize: 13),
|
||||
textAlign: TextAlign.center,
|
||||
// Step 2: OTP Input (WhatsApp Gateway)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0C241D),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: const Color(0xFF25D366).withOpacity(0.5)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
Icon(CupertinoIcons.chat_bubble_2_fill, color: Color(0xFF25D366), size: 20),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'تم إرسال الرمز عبر الواتساب بنجاح 📲',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
'أدخل رمز التحقق المرسل إلى: ${_phoneController.text}',
|
||||
style: const TextStyle(color: TeacherTheme.emeraldLight, fontSize: 13, fontWeight: FontWeight.w700),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildTextField(
|
||||
controller: _otpController,
|
||||
hint: 'أدخل رمز الـ OTP (مثال: 123456)',
|
||||
icon: CupertinoIcons.lock_shield_fill,
|
||||
keyboardType: TextInputType.number,
|
||||
const SizedBox(height: 22),
|
||||
|
||||
const Text(
|
||||
'رمز التحقق المعتمد (OTP):',
|
||||
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildOtpField(controller: _otpController),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
ElevatedButton(
|
||||
onPressed: isLoading ? null : _onVerifyOtp,
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -359,6 +393,7 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
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))
|
||||
@@ -367,10 +402,25 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w900),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextButton(
|
||||
onPressed: () => setState(() => _isEnteringOtp = false),
|
||||
child: const Text('تعديل رقم الهاتف والبيانات', style: TextStyle(color: TeacherTheme.emeraldLight)),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
onPressed: isLoading ? null : _onSendOtp,
|
||||
icon: const Icon(CupertinoIcons.refresh_circled, size: 16, color: Color(0xFF25D366)),
|
||||
label: const Text('إعادة إرسال الرمز 📲', style: TextStyle(color: Color(0xFF25D366), fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () {
|
||||
setState(() => _isEnteringOtp = false);
|
||||
context.read<TeacherAuthCubit>().resetToPhone();
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.pencil_ellipsis_rectangle, size: 16, color: Color(0xFF94A3B8)),
|
||||
label: const Text('تعديل رقم الهاتف ✏️', style: TextStyle(color: Color(0xFF94A3B8), fontSize: 12)),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -412,4 +462,47 @@ class _TeacherAuthScreenState extends State<TeacherAuthScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOtpField({
|
||||
required TextEditingController controller,
|
||||
}) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary.withOpacity(0.6), width: 1.5),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x2210B981),
|
||||
blurRadius: 16,
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.center,
|
||||
maxLength: 6,
|
||||
style: const TextStyle(
|
||||
color: TeacherTheme.emeraldLight,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w900,
|
||||
letterSpacing: 10,
|
||||
),
|
||||
decoration: const InputDecoration(
|
||||
counterText: '',
|
||||
prefixIcon: Icon(CupertinoIcons.lock_shield_fill, color: TeacherTheme.emeraldPrimary, size: 22),
|
||||
hintText: '• • • • • •',
|
||||
hintStyle: TextStyle(
|
||||
color: Color(0xFF475569),
|
||||
fontSize: 20,
|
||||
letterSpacing: 6,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import '../../../logic/cubits/teacher_qna_cubit.dart';
|
||||
* ==============================================================================
|
||||
*
|
||||
* غرفة استفسارات الطلبة الفعلية والبث الصوتي المباشر:
|
||||
* - استفسارات وأسئلة الطلبة الميدانية (طالبات الصف العاشر مثل سما حمزة)
|
||||
* - استفسارات وأسئلة الطلبة الميدانية المرتبطة بالحسابات الحقيقية
|
||||
* - تسجيل الردود الصوتية السقراطية (Socratic Voice Notes 🎙️)
|
||||
* - بث مقاطع صوتية توجيهية لكافة طلبة الشعبة عبر الويب سوكت (0ms Broadcast)
|
||||
* - إسناد ومتابعة أوراق العمل المؤتمتة.
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/theme/teacher_theme.dart';
|
||||
import '../../../data/models/teacher_models.dart';
|
||||
import '../../../logic/cubits/teacher_monetization_cubit.dart';
|
||||
|
||||
/**
|
||||
@@ -30,9 +31,13 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
context.read<TeacherMonetizationCubit>().loadMonetization();
|
||||
}
|
||||
|
||||
void _showCliqPayoutDialog(BuildContext ctx, double availableBalance) {
|
||||
final TextEditingController cliqController = TextEditingController(text: 'AHMAD@CLIQ');
|
||||
final TextEditingController amountController = TextEditingController(text: availableBalance.toInt().toString());
|
||||
void _showCliqPayoutDialog(BuildContext ctx, double availableBalance, String defaultAlias) {
|
||||
final TextEditingController cliqController = TextEditingController(
|
||||
text: defaultAlias.isNotEmpty ? defaultAlias : '0798583052@CLIQ',
|
||||
);
|
||||
final TextEditingController amountController = TextEditingController(
|
||||
text: availableBalance > 0 ? availableBalance.toInt().toString() : '50',
|
||||
);
|
||||
|
||||
showModalBottomSheet(
|
||||
context: ctx,
|
||||
@@ -109,7 +114,7 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
final double? amt = double.tryParse(amountController.text);
|
||||
if (amt != null && amt > 0) {
|
||||
ctx.read<TeacherMonetizationCubit>().submitCliqPayout(
|
||||
cliqAlias: cliqController.text,
|
||||
cliqAlias: cliqController.text.trim(),
|
||||
amountJod: amt,
|
||||
);
|
||||
}
|
||||
@@ -136,6 +141,114 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
);
|
||||
}
|
||||
|
||||
void _showIbanPayoutDialog(BuildContext ctx, double availableBalance) {
|
||||
final TextEditingController ibanController = TextEditingController(text: 'JO94MEPA0000000000000000000000');
|
||||
final TextEditingController amountController = TextEditingController(
|
||||
text: availableBalance > 0 ? availableBalance.toInt().toString() : '100',
|
||||
);
|
||||
|
||||
showModalBottomSheet(
|
||||
context: ctx,
|
||||
backgroundColor: TeacherTheme.surfaceCard,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
),
|
||||
builder: (bCtx) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(bCtx).viewInsets.bottom + 20,
|
||||
left: 20,
|
||||
right: 20,
|
||||
top: 24,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.building_2_fill, color: TeacherTheme.cyberCyan, size: 22),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'طلب تحويل بنكي رسمي (IBAN Transfer)',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(bCtx),
|
||||
icon: const Icon(CupertinoIcons.xmark_circle_fill, color: Color(0xFF64748B)),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
const Text(
|
||||
'يتم التحويل المباشر لحسابك المصرفي المعتمد خلال يوم عمل رسمي.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFF94A3B8)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: ibanController,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
decoration: InputDecoration(
|
||||
labelText: 'رقم الحساب المصرفي الدولي (IBAN)',
|
||||
labelStyle: const TextStyle(color: Color(0xFF94A3B8), fontSize: 12),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFF1E293B),
|
||||
prefixIcon: const Icon(CupertinoIcons.creditcard, color: TeacherTheme.cyberCyan, size: 20),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: amountController,
|
||||
keyboardType: TextInputType.number,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
decoration: InputDecoration(
|
||||
labelText: 'المبلغ المطلوب تحويله (دينار أردني)',
|
||||
labelStyle: const TextStyle(color: Color(0xFF94A3B8), fontSize: 12),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFF1E293B),
|
||||
prefixIcon: const Icon(CupertinoIcons.money_dollar, color: TeacherTheme.cyberCyan, size: 20),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
final double? amt = double.tryParse(amountController.text);
|
||||
if (amt != null && amt > 0) {
|
||||
ctx.read<TeacherMonetizationCubit>().submitCliqPayout(
|
||||
cliqAlias: ibanController.text.trim(),
|
||||
amountJod: amt,
|
||||
);
|
||||
}
|
||||
Navigator.pop(bCtx);
|
||||
ScaffoldMessenger.of(ctx).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('تم تسجيل أمر التحويل المصرفي بمبلغ ${amountController.text} د.أ بنجاح 🏦'),
|
||||
backgroundColor: TeacherTheme.cyberCyan,
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.checkmark_seal_fill, size: 16),
|
||||
label: const Text('تأكيد أمر التحويل البنكي'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.cyberCyan,
|
||||
foregroundColor: Colors.black,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<TeacherMonetizationCubit, TeacherMonetizationState>(
|
||||
@@ -177,10 +290,10 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary.withOpacity(0.3)),
|
||||
),
|
||||
child: const Row(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
@@ -195,8 +308,8 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'1,420 طالباً 🎖️',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w900, color: TeacherTheme.emeraldLight),
|
||||
'${state.institutionalStudents.toInt()} طالباً 🎖️',
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w900, color: TeacherTheme.emeraldLight),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -286,7 +399,7 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${state.teacherShare.toStringAsFixed(0)} دينار أردني',
|
||||
'${state.availableBalance.toStringAsFixed(1)} دينار أردني',
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.w900,
|
||||
@@ -294,13 +407,20 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
if (state.totalWithdrawn > 0) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'إجمالي المبالغ المسحوبة سابقاً: ${state.totalWithdrawn.toStringAsFixed(0)} د.أ',
|
||||
style: const TextStyle(fontSize: 11.5, color: Color(0xFF6EE7B7)),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 14),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
_showCliqPayoutDialog(context, state.teacherShare);
|
||||
_showCliqPayoutDialog(context, state.availableBalance, state.cliqAlias);
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.bolt_fill, size: 16),
|
||||
label: const Text(
|
||||
@@ -318,12 +438,7 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
const SizedBox(width: 8),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('تم تقديم طلب التحويل لحسابك البنكي IBAN بنجاح.'),
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
),
|
||||
);
|
||||
_showIbanPayoutDialog(context, state.availableBalance);
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.building_2_fill, size: 16, color: Colors.white),
|
||||
label: const Text('تحويل بنكي', style: TextStyle(fontSize: 12, color: Colors.white)),
|
||||
@@ -419,17 +534,39 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
_courseEarningCard(
|
||||
title: 'الفيزياء للتوجيهي العلمي (الفصل الأول)',
|
||||
students: 240,
|
||||
revenue: '2,640 د.أ',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_courseEarningCard(
|
||||
title: 'المكثف الشامل لقوانين نيوتن وحفظ الطاقة',
|
||||
students: 140,
|
||||
revenue: '1,540 د.أ',
|
||||
),
|
||||
if (state.courses.isNotEmpty)
|
||||
...state.courses.map((course) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _courseEarningCard(
|
||||
title: course.title,
|
||||
students: course.militaryStudents + course.externalSubscribers,
|
||||
revenue: '${(course.priceJod * (course.externalSubscribers > 0 ? course.externalSubscribers : 1) * 0.55).toStringAsFixed(0)} د.أ',
|
||||
),
|
||||
)).toList()
|
||||
else ...[
|
||||
_courseEarningCard(
|
||||
title: 'الفيزياء والعلوم التطبيقية — الصف العاشر الأساسي',
|
||||
students: state.institutionalStudents.toInt(),
|
||||
revenue: '${state.teacherShare.toStringAsFixed(0)} د.أ',
|
||||
),
|
||||
],
|
||||
|
||||
// Real CliQ & IBAN Payout History Queue
|
||||
if (state.payoutRequests.isNotEmpty) ...[
|
||||
const SizedBox(height: 18),
|
||||
const Row(
|
||||
children: [
|
||||
Icon(CupertinoIcons.arrow_right_arrow_left, size: 16, color: TeacherTheme.emeraldPrimary),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'سجل عمليات وسحوبات كليك (CliQ & IBAN Queue):',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
...state.payoutRequests.map((p) => _payoutRow(p)).toList(),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -437,6 +574,70 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _payoutRow(TeacherPayoutRequestModel payout) {
|
||||
final isDone = payout.status == 'completed' || payout.status == 'approved';
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: isDone ? TeacherTheme.emeraldPrimary.withOpacity(0.3) : TeacherTheme.surfaceBorder,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
isDone ? CupertinoIcons.checkmark_circle_fill : CupertinoIcons.clock_fill,
|
||||
size: 20,
|
||||
color: isDone ? TeacherTheme.emeraldPrimary : TeacherTheme.royalGold,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
payout.cliqAlias,
|
||||
style: const TextStyle(fontSize: 12.5, fontWeight: FontWeight.w700, color: Colors.white),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
payout.requestedAt,
|
||||
style: const TextStyle(fontSize: 11, color: Color(0xFF64748B)),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
'${payout.amountJod.toStringAsFixed(0)} د.أ',
|
||||
style: TextStyle(
|
||||
fontSize: 13.5,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: isDone ? TeacherTheme.emeraldPrimary : TeacherTheme.royalGold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
isDone ? 'تم التحويل بنجاح' : 'في طابور المقاصة ⚡',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: isDone ? TeacherTheme.emeraldLight : TeacherTheme.royalGold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _splitRow(String label, String amount, Color color) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
||||
+167
-112
@@ -4,6 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/theme/teacher_theme.dart';
|
||||
import '../../../logic/cubits/teacher_auth_cubit.dart';
|
||||
|
||||
import '../../../data/repositories/teacher_repository.dart';
|
||||
|
||||
/**
|
||||
* ==============================================================================
|
||||
* SAQEL TEACHER STUDIO - TAB 3: REPUTATION & CERTIFICATION SCORECARD
|
||||
@@ -14,132 +16,185 @@ import '../../../logic/cubits/teacher_auth_cubit.dart';
|
||||
* - رادار الجودة التربوية (نتاجات المنهاج، الفواصل السقراطية، السلامة اللغوية، والتركيز 20-25 دقيقة)
|
||||
* - توجيهات الذكاء الاصطناعي الأسبوعية للتحسين المستمر.
|
||||
*/
|
||||
class TeacherReputationScorecardTab extends StatelessWidget {
|
||||
class TeacherReputationScorecardTab extends StatefulWidget {
|
||||
const TeacherReputationScorecardTab({super.key});
|
||||
|
||||
@override
|
||||
State<TeacherReputationScorecardTab> createState() => _TeacherReputationScorecardTabState();
|
||||
}
|
||||
|
||||
class _TeacherReputationScorecardTabState extends State<TeacherReputationScorecardTab> {
|
||||
final TeacherRepository _repository = TeacherRepository();
|
||||
bool _isLoading = true;
|
||||
int _studentsEnrolled = 83;
|
||||
double _compositeMerit = 96.5;
|
||||
double _starRating = 4.92;
|
||||
double _successRate = 98.2;
|
||||
double _curriculumAlignment = 0.96;
|
||||
double _socraticInteraction = 0.89;
|
||||
double _audioClarity = 0.94;
|
||||
double _cognitiveFocus = 0.92;
|
||||
String _reputationTier = 'معلم نخبوي معتمد 💎';
|
||||
String _aiGuidance = 'توجيه الذكاء الاصطناعي الأسبوعي: نسبة الالتزام الوزاري ممتازة (96%). يُوصى بإضافة وقفة سقراطية استنتاجية في الدقيقة 14 من الدرس القادم لتعزيز تفاعل الطلبة.';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadReputation();
|
||||
}
|
||||
|
||||
Future<void> _loadReputation() async {
|
||||
try {
|
||||
final data = await _repository.getMyReputation();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_studentsEnrolled = (data['total_students_enrolled'] as num?)?.toInt() ?? 83;
|
||||
_compositeMerit = (data['composite_merit_score'] as num?)?.toDouble() ?? 96.5;
|
||||
_starRating = (data['star_equivalent'] as num?)?.toDouble() ?? 4.92;
|
||||
_successRate = (data['success_rate_percentage'] as num?)?.toDouble() ?? 98.2;
|
||||
_curriculumAlignment = ((data['curriculum_alignment_pct'] as num?)?.toDouble() ?? 96.0) / 100.0;
|
||||
_socraticInteraction = ((data['socratic_interaction_pct'] as num?)?.toDouble() ?? 89.0) / 100.0;
|
||||
_audioClarity = ((data['audio_clarity_pct'] as num?)?.toDouble() ?? 94.0) / 100.0;
|
||||
_cognitiveFocus = ((data['cognitive_focus_pct'] as num?)?.toDouble() ?? 92.0) / 100.0;
|
||||
_reputationTier = data['reputation_tier']?.toString() ?? 'معلم نخبوي معتمد 💎';
|
||||
_aiGuidance = data['ai_recommendation']?.toString() ?? _aiGuidance;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
} catch (_) {
|
||||
if (mounted) setState(() => _isLoading = false);
|
||||
}
|
||||
}
|
||||
|
||||
@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(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Top Merit Card
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF1E1B4B), Color(0xFF0F172A)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
return RefreshIndicator(
|
||||
onRefresh: _loadReputation,
|
||||
color: TeacherTheme.emeraldPrimary,
|
||||
backgroundColor: TeacherTheme.surfaceCard,
|
||||
child: SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Top Merit Card
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
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.5)),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: const Color(0xFF8B5CF6).withOpacity(0.5)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
radius: 32,
|
||||
backgroundColor: Color(0xFF8B5CF6),
|
||||
child: Icon(CupertinoIcons.rosette, size: 36, color: Colors.white),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
teacherName,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
radius: 32,
|
||||
backgroundColor: Color(0xFF8B5CF6),
|
||||
child: Icon(CupertinoIcons.rosette, size: 36, color: Colors.white),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: const Text(
|
||||
'🏅 معلم معتمد رسمياً من منصة صَقِل (فوق 90%)',
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: TeacherTheme.emeraldLight,
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
teacherName,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_ScoreStat(label: 'التقييم العام', value: '4.92 / 5.0'),
|
||||
_ScoreStat(label: 'الطلاب المخدومون', value: '1,240 طالب'),
|
||||
_ScoreStat(label: 'نسبة النجاح', value: '98.2%'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Pedagogical Metrics Breakdown
|
||||
Container(
|
||||
padding: const EdgeInsets.all(18),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'رادار الجودة التربوية المعتمد:',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.emeraldPrimary.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
'🏅 $_reputationTier (${_compositeMerit.toStringAsFixed(1)}%)',
|
||||
style: const TextStyle(
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: TeacherTheme.emeraldLight,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
_metricProgress('الالتزام بالمنهاج والنتاجات الوزارية', 0.96, TeacherTheme.emeraldPrimary),
|
||||
const SizedBox(height: 12),
|
||||
_metricProgress('التفاعل السقراطي وإثارة التفكير', 0.89, TeacherTheme.cyberCyan),
|
||||
const SizedBox(height: 12),
|
||||
_metricProgress('الوضوح الصوتي وسلامة اللغة', 0.94, TeacherTheme.royalGold),
|
||||
const SizedBox(height: 12),
|
||||
_metricProgress('إدارة الوقت والتركيز الإدراكي (20-25 دقيقة)', 0.92, const Color(0xFF8B5CF6)),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// AI Growth Insights Box
|
||||
Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF1E293B),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFF334155)),
|
||||
),
|
||||
child: const Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(CupertinoIcons.lightbulb_fill, color: TeacherTheme.royalGold, size: 20),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'توجيه الذكاء الاصطناعي الأسبوعي: نسبة الالتزام الوزاري ممتازة (96%). يُوصى بإضافة وقفة سقراطية استنتاجية في الدقيقة 14 من الدرس القادم لتعزيز تفاعل الطلبة.',
|
||||
style: TextStyle(fontSize: 12, color: Color(0xFFCBD5E1), height: 1.4),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_ScoreStat(label: 'التقييم العام', value: '${_starRating.toStringAsFixed(2)} / 5.0'),
|
||||
_ScoreStat(label: 'الطلاب المخدومون', value: '$_studentsEnrolled طالب'),
|
||||
_ScoreStat(label: 'نسبة النجاح', value: '${_successRate.toStringAsFixed(1)}%'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Pedagogical Metrics Breakdown
|
||||
Container(
|
||||
padding: const EdgeInsets.all(18),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'رادار الجودة التربوية المعتمد:',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
_metricProgress('الالتزام بالمنهاج والنتاجات الوزارية', _curriculumAlignment, TeacherTheme.emeraldPrimary),
|
||||
const SizedBox(height: 12),
|
||||
_metricProgress('التفاعل السقراطي وإثارة التفكير', _socraticInteraction, TeacherTheme.cyberCyan),
|
||||
const SizedBox(height: 12),
|
||||
_metricProgress('الوضوح الصوتي وسلامة اللغة', _audioClarity, TeacherTheme.royalGold),
|
||||
const SizedBox(height: 12),
|
||||
_metricProgress('إدارة الوقت والتركيز الإدراكي (20-25 دقيقة)', _cognitiveFocus, const Color(0xFF8B5CF6)),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// AI Growth Insights Box
|
||||
Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF1E293B),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
border: Border.all(color: const Color(0xFF334155)),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(CupertinoIcons.lightbulb_fill, color: TeacherTheme.royalGold, size: 20),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
_aiGuidance,
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFFCBD5E1), height: 1.4),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import '../../../core/theme/teacher_theme.dart';
|
||||
import '../../../data/models/teacher_models.dart';
|
||||
import '../../../logic/cubits/teacher_studio_cubit.dart';
|
||||
@@ -39,11 +41,29 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _pickVideo(BuildContext ctx) async {
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: const ['mp4', 'mov', 'webm'],
|
||||
withData: kIsWeb,
|
||||
);
|
||||
if (!mounted || result == null || result.files.isEmpty) return;
|
||||
|
||||
final file = result.files.single;
|
||||
ctx.read<TeacherStudioCubit>().selectVideoFile(
|
||||
file.name,
|
||||
file.size / (1024 * 1024),
|
||||
ctx.read<TeacherStudioCubit>().state.durationMinutes,
|
||||
path: file.path,
|
||||
bytes: file.bytes,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<TeacherStudioCubit, TeacherStudioState>(
|
||||
builder: (context, state) {
|
||||
final bool isDurationGood = state.durationMinutes >= 15.0 && state.durationMinutes <= 25.0;
|
||||
final bool isDurationGood = state.durationMinutes <= 25.0;
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@@ -81,7 +101,7 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
),
|
||||
SizedBox(height: 6),
|
||||
Text(
|
||||
'تخضع كل حصة رقمية لمعايير التركيز الإدراكي (20-25 دقيقة كحد أقصى) وفحص الذكاء الاصطناعي بنسبة قبول لا تقل عن 85% قبل نشرها وتسييلها.',
|
||||
'تخضع كل حصة رقمية لمعايير التركيز الإدراكي (حتى 25 دقيقة) وفحص الذكاء الاصطناعي بنسبة قبول لا تقل عن 85% قبل نشرها وتسييلها.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF94A3B8),
|
||||
@@ -128,12 +148,83 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Video Attachment Dropzone Card
|
||||
const Text(
|
||||
'ملف فيديو الحصة للشرح الرقمي (1080p):',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF161F30),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: state.selectedFileName != null ? TeacherTheme.emeraldPrimary : const Color(0xFF334155),
|
||||
width: state.selectedFileName != null ? 1.5 : 1.0,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: (state.selectedFileName != null ? TeacherTheme.emeraldPrimary : const Color(0xFF334155)).withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
CupertinoIcons.videocam_fill,
|
||||
color: state.selectedFileName != null ? TeacherTheme.emeraldLight : const Color(0xFF94A3B8),
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
state.selectedFileName ?? 'لم يتم اختيار ملف فيديو بعد',
|
||||
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
state.selectedFileName != null
|
||||
? 'الحجم: ${state.selectedFileSizeMb ?? 48.2} MB • المدة المستخرجة: ${state.durationMinutes.toStringAsFixed(1)} دقيقة'
|
||||
: 'الصيغ المدعومة: MP4, MOV, WebM (جودة 1080p)',
|
||||
style: const TextStyle(color: Color(0xFF94A3B8), fontSize: 11),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
ElevatedButton.icon(
|
||||
onPressed: () => _pickVideo(context),
|
||||
icon: const Icon(CupertinoIcons.folder_badge_plus, size: 15),
|
||||
label: Text(state.selectedFileName != null ? 'تغيير الملف' : 'اختيار ملف 📁'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: state.selectedFileName != null ? const Color(0xFF1E293B) : TeacherTheme.emeraldPrimary,
|
||||
foregroundColor: state.selectedFileName != null ? Colors.white : Colors.black,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
textStyle: const TextStyle(fontSize: 11.5, fontWeight: FontWeight.bold),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Duration Slider
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'مدة الشرح الرقمي:',
|
||||
'مدة الشرح الرقمي المستخرجة:',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -198,8 +289,8 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
isDurationGood
|
||||
? 'مثالي: الشرح ضمن المدى الإدراكي القياسي (20 إلى 25 دقيقة) لمعادلة تركيز الحصة الصفية.'
|
||||
: 'تحذير إدراكي: الشرح يتجاوز 25 دقيقة! ينخفض الاستيعاب بعد الدقيقة 18، يرجى اختصار المقطع أو تقسيمه.',
|
||||
? 'مدة الشرح مثالية ومناسبة للاستيعاب الإدراكي المركز للطلبة (ضمن المدى المعتمد حتى 25 دقيقة).'
|
||||
: 'تحذير إدراكي: الشرح يتجاوز 25 دقيقة! ينخفض استيعاب الطلبة تدريجياً، يرجى اختصار المقطع أو تقسيمه.',
|
||||
style: TextStyle(
|
||||
fontSize: 11.5,
|
||||
color: isDurationGood ? const Color(0xFF6EE7B7) : const Color(0xFFFCA5A5),
|
||||
@@ -246,7 +337,7 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Quality Audit Result Card
|
||||
if (state.auditResult != null) _buildAuditResultCard(context, state.auditResult!),
|
||||
if (state.auditResult != null) _buildAuditResultCard(context, state, state.auditResult!),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -254,7 +345,7 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAuditResultCard(BuildContext context, TeacherLessonAuditModel res) {
|
||||
Widget _buildAuditResultCard(BuildContext context, TeacherStudioState state, TeacherLessonAuditModel res) {
|
||||
final int score = res.qualityScore;
|
||||
final bool isApproved = score >= 85;
|
||||
|
||||
@@ -283,7 +374,7 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
isApproved ? 'حصة معتمدة للبث والتسييل 🏅' : 'تجميد الحصة للمراجعة ⚠️',
|
||||
isApproved ? 'جاهزة لرفع الملف والتحليل' : 'بيانات الحصة بحاجة للمراجعة',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w900,
|
||||
@@ -301,7 +392,7 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'درجة التقييم: $score%',
|
||||
'اكتمال فحص ما قبل الرفع: $score%',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w900,
|
||||
@@ -329,27 +420,72 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
|
||||
_rowMetric('نقاء الصوت ومخارج الحروف:', res.audioClarity),
|
||||
const SizedBox(height: 6),
|
||||
_rowMetric('الفواصل السقراطية التفاعلية:', '${res.socraticStopsCount} محطات تفكيرية إلزامية'),
|
||||
const SizedBox(height: 14),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
if (isApproved)
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('تم ترحيل الحصة لتقطيع البث المشفر ونشرها في سوق صَقِل! 🚀'),
|
||||
backgroundColor: TeacherTheme.emeraldPrimary,
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.cloud_upload_fill, size: 16),
|
||||
label: const Text('نشر الحصة في سوق التسييل التجاري 💰'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldDark,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: const Size(double.infinity, 42),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
if (isApproved) ...[
|
||||
if (state.isUploading)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
alignment: Alignment.center,
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(width: 18, height: 18, child: CircularProgressIndicator(color: TeacherTheme.emeraldPrimary, strokeWidth: 2)),
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
'جاري رفع الفيديو وبدء معالجة HLS والتحليل السقراطي... ⏳',
|
||||
style: TextStyle(color: TeacherTheme.emeraldLight, fontSize: 12.5, fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else if (state.isUploaded)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF064E3B).withOpacity(0.3),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: TeacherTheme.emeraldPrimary),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(CupertinoIcons.checkmark_seal_fill, color: TeacherTheme.emeraldLight, size: 22),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
state.uploadSuccessMessage ?? 'تم رفع ونشر الحصة بنجاح في المنهاج وسوق صَقِل! 🚀',
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.w900),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
const Text(
|
||||
'الحصة متاحة الآن لطلبة الصف العاشر وسوق التسييل التجاري 🎖️',
|
||||
style: TextStyle(color: TeacherTheme.emeraldLight, fontSize: 11),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
context.read<TeacherStudioCubit>().uploadAndPublishLesson();
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.cloud_upload_fill, size: 18),
|
||||
label: const Text('رفع ونشر الحصة في المنهاج وسوق التسييل 🚀', style: TextStyle(fontSize: 13.5, fontWeight: FontWeight.w900)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TeacherTheme.emeraldDark,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: const Size(double.infinity, 46),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
elevation: 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user