Update Saqel Platform: 2026-09-02 00:55:56

This commit is contained in:
Hamza-Ayed
2026-09-02 00:55:56 +03:00
parent 1c0cd88a98
commit f4ab43d49a
18 changed files with 409 additions and 214 deletions
@@ -10,6 +10,7 @@ import '../../../logic/cubits/auth_cubit.dart';
import '../../../logic/cubits/video_playback_cubit.dart';
import '../../widgets/luxury_widgets.dart';
import '../../widgets/socratic_dialog.dart';
import 'package:video_player/video_player.dart';
class SocraticVideoPlayerScreen extends StatefulWidget {
final CurriculumLessonItemModel lesson;
@@ -28,6 +29,8 @@ class SocraticVideoPlayerScreen extends StatefulWidget {
class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> with SingleTickerProviderStateMixin {
Timer? _playbackTicker;
late AnimationController _watermarkController;
VideoPlayerController? _videoController;
bool _isVideoInitialized = false;
@override
void initState() {
@@ -40,14 +43,14 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
duration: const Duration(seconds: 18),
)..repeat(reverse: true);
// Ticker simulating video playback time progression and Socratic checkpoint gatekeeping
// Read the real player clock and periodically persist progress.
_playbackTicker = Timer.periodic(const Duration(seconds: 1), (timer) {
final cubit = context.read<VideoPlaybackCubit>();
final state = cubit.state;
if (state is VideoPlaybackReady && state.isPlaying && state.activeCheckpoint == null) {
if (state.currentPositionSeconds < state.playbackData.durationSeconds) {
cubit.updatePosition(state.currentPositionSeconds + 1);
}
if (state is VideoPlaybackReady && _videoController?.value.isInitialized == true) {
final position = _videoController!.value.position.inSeconds;
if (state.activeCheckpoint == null) cubit.updatePosition(position);
cubit.saveProgress(positionSeconds: position, watchedSeconds: position);
}
});
}
@@ -56,6 +59,7 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
void dispose() {
_playbackTicker?.cancel();
_watermarkController.dispose();
_videoController?.dispose();
super.dispose();
}
@@ -111,6 +115,31 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
body: BlocConsumer<VideoPlaybackCubit, VideoPlaybackState>(
listener: (context, state) {
if (state is VideoPlaybackReady) {
// Initialize Video Player if not yet initialized
if (_videoController == null) {
_videoController = VideoPlayerController.networkUrl(Uri.parse(state.playbackData.videoUrl))
..initialize().then((_) {
if (mounted) {
setState(() {
_isVideoInitialized = true;
});
if (state.isPlaying && state.activeCheckpoint == null) {
_videoController!.play();
}
}
});
} else if (_isVideoInitialized) {
// Sync play/pause state
if (state.isPlaying && state.activeCheckpoint == null) {
_videoController!.play();
} else {
_videoController!.pause();
}
if (state.currentPositionSeconds != _videoController!.value.position.inSeconds) {
_videoController!.seekTo(Duration(seconds: state.currentPositionSeconds));
}
}
// Trigger Socratic Checkpoint Modal automatically when active
if (state.activeCheckpoint != null) {
showDialog(
@@ -187,20 +216,35 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
borderRadius: BorderRadius.circular(24),
child: Stack(
children: [
// Video Background Scene Simulation & Visualizer
Container(
decoration: const BoxDecoration(
gradient: RadialGradient(
center: Alignment(0.0, -0.3),
radius: 1.3,
colors: [
Color(0xFF0F2342),
Color(0xFF060B14),
],
),
),
child: Stack(
children: [
// Video Background Scene
Stack(
children: [
if (_videoController != null && _isVideoInitialized)
Positioned.fill(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: _videoController!.value.size.width,
height: _videoController!.value.size.height,
child: VideoPlayer(_videoController!),
),
),
)
else
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
gradient: RadialGradient(
center: Alignment(0.0, -0.3),
radius: 1.3,
colors: [
Color(0xFF0F2342),
Color(0xFF060B14),
],
),
),
),
),
// Grid Overlay Effect
Positioned.fill(
child: Opacity(
@@ -315,7 +359,6 @@ class _SocraticVideoPlayerScreenState extends State<SocraticVideoPlayerScreen> w
),
],
),
),
// Dynamic Forensic Anti-Piracy Watermark (Moves continuously)
AnimatedBuilder(