Fix UI overflows in SubjectHub/Grid and guarantee Socratic checkpoints response

This commit is contained in:
Hamza-Ayed
2026-08-31 17:55:22 +03:00
parent 43d6b88106
commit 7ab10209dc
4 changed files with 188 additions and 52 deletions
@@ -302,20 +302,30 @@ class _SubjectHubScreenState extends State<SubjectHubScreen> with SingleTickerPr
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(CupertinoIcons.question_circle, color: AppColors.textSecondaryDark, size: 14),
const SizedBox(width: 4),
Text('${exam.questionsCount} سؤال اختياري', style: const TextStyle(color: AppColors.textSecondaryDark, fontSize: 12)),
const SizedBox(width: 14),
const Icon(CupertinoIcons.time, color: AppColors.textSecondaryDark, size: 14),
const SizedBox(width: 4),
Text('${exam.durationMinutes} دقيقة', style: const TextStyle(color: AppColors.textSecondaryDark, fontSize: 12)),
const Spacer(),
LuxuryButton(
text: 'بدء الاختبار 🚀',
Row(
children: [
const Icon(CupertinoIcons.question_circle, color: AppColors.textSecondaryDark, size: 14),
const SizedBox(width: 4),
Text('${exam.questionsCount} أسئلة', style: const TextStyle(color: AppColors.textSecondaryDark, fontSize: 12)),
const SizedBox(width: 12),
const Icon(CupertinoIcons.time, color: AppColors.textSecondaryDark, size: 14),
const SizedBox(width: 4),
Text('${exam.durationMinutes} د', style: const TextStyle(color: AppColors.textSecondaryDark, fontSize: 12)),
],
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.appleBlue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
onPressed: () {
SaqelToast.showInfo(context, 'جاري توليد أسئلة الاختبار التكيفي من بنك الوزارة', title: 'بدء الامتحان 📝');
},
child: const Text('بدء الاختبار 🚀', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w700)),
),
],
),
@@ -275,10 +275,13 @@ class _SubjectsGridScreenState extends State<SubjectsGridScreen> {
LayoutBuilder(
builder: (context, constraints) {
int crossAxisCount = 4;
double aspectRatio = 1.15;
if (constraints.maxWidth < 600) {
crossAxisCount = 2;
aspectRatio = 0.95;
} else if (constraints.maxWidth < 900) {
crossAxisCount = 3;
aspectRatio = 1.05;
}
return GridView.builder(
@@ -288,7 +291,7 @@ class _SubjectsGridScreenState extends State<SubjectsGridScreen> {
crossAxisCount: crossAxisCount,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 1.15,
childAspectRatio: aspectRatio,
),
itemCount: state.filteredSubjects.length,
itemBuilder: (context, idx) {
@@ -187,58 +187,133 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
borderRadius: BorderRadius.circular(24),
child: Stack(
children: [
// Video Background Scene Simulation
// Video Background Scene Simulation & Visualizer
Container(
decoration: const BoxDecoration(
gradient: RadialGradient(
center: Alignment(0.0, -0.2),
radius: 1.2,
center: Alignment(0.0, -0.3),
radius: 1.3,
colors: [
Color(0xFF0F1E36),
Color(0xFF050B14),
Color(0xFF0F2342),
Color(0xFF060B14),
],
),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: AppColors.saqelCyan.withAlpha(25),
shape: BoxShape.circle,
border: Border.all(color: AppColors.saqelCyan.withAlpha(100), width: 2),
child: Stack(
children: [
// Grid Overlay Effect
Positioned.fill(
child: Opacity(
opacity: 0.08,
child: CustomPaint(
painter: _GridPatternPainter(),
),
child: IconButton(
icon: Icon(
state.isPlaying ? CupertinoIcons.pause_fill : CupertinoIcons.play_fill,
color: AppColors.saqelCyan,
size: 36,
),
),
// Center Lesson Title & Visuals
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Dynamic Play/Pause Button
InkWell(
onTap: () => context.read<VideoPlaybackCubit>().togglePlayPause(),
borderRadius: BorderRadius.circular(40),
child: Container(
width: 72,
height: 72,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: state.isPlaying
? [AppColors.saqelCyan.withAlpha(40), AppColors.appleBlue.withAlpha(30)]
: [AppColors.appleBlue, AppColors.saqelCyan],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
shape: BoxShape.circle,
border: Border.all(
color: state.isPlaying ? AppColors.saqelCyan.withAlpha(120) : Colors.white,
width: 2,
),
boxShadow: [
BoxShadow(
color: AppColors.saqelCyan.withAlpha(state.isPlaying ? 40 : 80),
blurRadius: 24,
),
],
),
child: Icon(
state.isPlaying ? CupertinoIcons.pause_fill : CupertinoIcons.play_fill,
color: state.isPlaying ? AppColors.saqelCyan : Colors.black,
size: 32,
),
),
),
onPressed: () => context.read<VideoPlaybackCubit>().togglePlayPause(),
const SizedBox(height: 18),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
widget.lesson.title,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w800,
letterSpacing: -0.2,
),
),
),
const SizedBox(height: 6),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: state.isPlaying ? AppColors.emeraldGreen : AppColors.guardianAmber,
shape: BoxShape.circle,
),
),
const SizedBox(width: 8),
Text(
state.isPlaying ? 'جاري البث والشرح التفاعلي ⚡' : 'الشرح متوقف مؤقتاً',
style: const TextStyle(
color: AppColors.textSecondaryDark,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
),
],
),
),
// Top Version Badge
Positioned(
top: 14,
right: 14,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.black.withAlpha(140),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: AppColors.saqelCyan.withAlpha(60)),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(CupertinoIcons.sparkles, color: AppColors.saqelCyan, size: 12),
SizedBox(width: 6),
Text(
'الشرح السقراطي المعزز 🤖',
style: TextStyle(color: AppColors.saqelCyan, fontSize: 11, fontWeight: FontWeight.w700),
),
],
),
),
const SizedBox(height: 16),
Text(
widget.lesson.title,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 6),
const Text(
'بث مشفر فائق الجودة HLS 1080p — منصة صَقِل',
style: TextStyle(
color: AppColors.textSecondaryDark,
fontSize: 12,
),
),
],
),
),
],
),
),
@@ -461,3 +536,23 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
);
}
}
class _GridPatternPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.white
..strokeWidth = 1.0;
const step = 28.0;
for (double x = 0; x < size.width; x += step) {
canvas.drawLine(Offset(x, 0), Offset(x, size.height), paint);
}
for (double y = 0; y < size.height; y += step) {
canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}