@@ -2,6 +2,7 @@ package org.openedx.course.presentation.unit.video
22
33import android.os.Bundle
44import android.view.View
5+ import android.webkit.WebView
56import android.widget.FrameLayout
67import androidx.core.os.bundleOf
78import androidx.core.view.WindowInsetsCompat
@@ -12,7 +13,6 @@ import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
1213import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
1314import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.options.IFramePlayerOptions
1415import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.YouTubePlayerTracker
15- import com.pierfrancescosoffritti.androidyoutubeplayer.core.ui.DefaultPlayerUiController
1616import org.koin.android.ext.android.inject
1717import org.koin.androidx.viewmodel.ext.android.viewModel
1818import org.koin.core.parameter.parametersOf
@@ -39,8 +39,8 @@ class YoutubeVideoFullScreenFragment : Fragment(R.layout.fragment_youtube_video_
3939
4040 override fun onCreate (savedInstanceState : Bundle ? ) {
4141 super .onCreate(savedInstanceState)
42- viewModel.videoUrl = requireArguments().getString( ARG_BLOCK_VIDEO_URL , " " )
43- blockId = requireArguments().getString( ARG_BLOCK_ID , " " )
42+ // Enable WebView debugging for YouTube player
43+ WebView .setWebContentsDebuggingEnabled( true )
4444 if (viewModel.currentVideoTime == 0L ) {
4545 viewModel.currentVideoTime = requireArguments().getLong(ARG_VIDEO_TIME , 0 )
4646 }
@@ -67,8 +67,10 @@ class YoutubeVideoFullScreenFragment : Fragment(R.layout.fragment_youtube_video_
6767
6868 lifecycle.addObserver(binding.youtubePlayerView)
6969 val options = IFramePlayerOptions .Builder ()
70- .controls(0 )
71- .rel(0 )
70+ .controls(0 ) // Hide default controls (using custom UI)
71+ .rel(0 ) // Don't show related videos
72+ .ivLoadPolicy(3 ) // Critical: Disable video annotations
73+ .ccLoadPolicy(1 ) // Show closed captions
7274 .build()
7375
7476 binding.youtubePlayerView.initialize(
@@ -80,12 +82,20 @@ class YoutubeVideoFullScreenFragment : Fragment(R.layout.fragment_youtube_video_
8082 state : PlayerConstants .PlayerState ,
8183 ) {
8284 super .onStateChange(youTubePlayer, state)
85+ android.util.Log .d(" YoutubePlayerFS" , " Player state: $state " )
86+
8387 if (state == PlayerConstants .PlayerState .ENDED ) {
8488 viewModel.markBlockCompleted(blockId, CourseAnalyticsKey .YOUTUBE .key)
8589 }
8690 viewModel.isPlaying = when (state) {
87- PlayerConstants .PlayerState .PLAYING -> true
88- PlayerConstants .PlayerState .PAUSED -> false
91+ PlayerConstants .PlayerState .PLAYING -> {
92+ android.util.Log .d(" YoutubePlayerFS" , " ✅ Fullscreen video PLAYING" )
93+ true
94+ }
95+ PlayerConstants .PlayerState .PAUSED -> {
96+ android.util.Log .d(" YoutubePlayerFS" , " ⏸️ Fullscreen video PAUSED" )
97+ false
98+ }
8999 else -> return
90100 }
91101 }
@@ -108,21 +118,23 @@ class YoutubeVideoFullScreenFragment : Fragment(R.layout.fragment_youtube_video_
108118 override fun onReady (youTubePlayer : YouTubePlayer ) {
109119 super .onReady(youTubePlayer)
110120 binding.youtubePlayerView.isVisible = true
111- val defPlayerUiController =
112- DefaultPlayerUiController (binding.youtubePlayerView, youTubePlayer)
113- defPlayerUiController.setFullScreenButtonClickListener {
114- parentFragmentManager.popBackStack()
115- }
116121
117- binding.youtubePlayerView.setCustomPlayerUi(defPlayerUiController.rootView)
122+ android.util.Log .d(" YoutubePlayerFS" , " === Fullscreen onReady ===" )
123+ android.util.Log .d(" YoutubePlayerFS" , " Video URL: ${viewModel.videoUrl} " )
118124
119- val videoId = viewModel.videoUrl.split(" watch?v=" )[1 ]
120- if (viewModel.isPlaying == true ) {
121- youTubePlayer.loadVideo(videoId, viewModel.currentVideoTime.toFloat() / 1000 )
125+ val videoId = extractYouTubeVideoId(viewModel.videoUrl)
126+ android.util.Log .d(" YoutubePlayerFS" , " Extracted video ID: '$videoId '" )
127+
128+ if (videoId != null ) {
129+ val startTime = viewModel.currentVideoTime.toFloat() / 1000
130+ // Always use cueVideo - avoids autoplay policy issues
131+ android.util.Log .d(" YoutubePlayerFS" , " Action: cueVideo, Start time: $startTime sec" )
132+
133+ youTubePlayer.cueVideo(videoId, startTime)
134+ youTubePlayer.addListener(youtubeTrackerListener)
122135 } else {
123- youTubePlayer.cueVideo(videoId, viewModel.currentVideoTime.toFloat() / 1000 )
136+ android.util. Log .e( " YoutubePlayerFS " , " ❌ FAILED to extract video ID from: ${viewModel.videoUrl} " )
124137 }
125- youTubePlayer.addListener(youtubeTrackerListener)
126138 }
127139 },
128140 options
@@ -134,6 +146,48 @@ class YoutubeVideoFullScreenFragment : Fragment(R.layout.fragment_youtube_video_
134146 super .onDestroyView()
135147 }
136148
149+ private fun extractYouTubeVideoId (url : String ): String? {
150+ return try {
151+ when {
152+ // Standard watch URL: https://www.youtube.com/watch?v=VIDEO_ID
153+ url.contains(" watch?v=" ) -> {
154+ val parts = url.split(" watch?v=" )
155+ if (parts.size > 1 ) {
156+ parts[1 ].split(" &" ).firstOrNull()
157+ } else null
158+ }
159+ // Short URL: https://youtu.be/VIDEO_ID
160+ url.contains(" youtu.be/" ) -> {
161+ val parts = url.split(" youtu.be/" )
162+ if (parts.size > 1 ) {
163+ parts[1 ].split(" ?" ).firstOrNull()?.split(" &" )?.firstOrNull()
164+ } else null
165+ }
166+ // Embed URL: https://www.youtube.com/embed/VIDEO_ID
167+ url.contains(" /embed/" ) -> {
168+ val parts = url.split(" /embed/" )
169+ if (parts.size > 1 ) {
170+ parts[1 ].split(" ?" ).firstOrNull()?.split(" &" )?.firstOrNull()
171+ } else null
172+ }
173+ // v parameter: https://youtube.com/v/VIDEO_ID
174+ url.contains(" /v/" ) -> {
175+ val parts = url.split(" /v/" )
176+ if (parts.size > 1 ) {
177+ parts[1 ].split(" ?" ).firstOrNull()?.split(" &" )?.firstOrNull()
178+ } else null
179+ }
180+ else -> {
181+ android.util.Log .w(" YoutubePlayer" , " Unknown YouTube URL format: $url " )
182+ null
183+ }
184+ }
185+ } catch (e: Exception ) {
186+ android.util.Log .e(" YoutubePlayer" , " Error extracting video ID from: $url " , e)
187+ null
188+ }
189+ }
190+
137191 companion object {
138192 private const val ARG_BLOCK_VIDEO_URL = " blockVideoUrl"
139193 private const val ARG_VIDEO_TIME = " videoTime"
0 commit comments