Skip to content

Commit 14fae9c

Browse files
implement webview for youtube video
1 parent 3fad5b2 commit 14fae9c

5 files changed

Lines changed: 496 additions & 27 deletions

File tree

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ buildscript {
1414
}
1515

1616
plugins {
17-
id 'com.android.application' version '8.5.2' apply false
18-
id 'com.android.library' version '8.5.2' apply false
17+
id 'com.android.application' version '8.11.2' apply false
18+
id 'com.android.library' version '8.11.2' apply false
1919
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
2020
id 'com.google.gms.google-services' version '4.4.2' apply false
2121
id "com.google.firebase.crashlytics" version "3.0.2" apply false

course/src/main/java/org/openedx/course/presentation/unit/video/YoutubeVideoFullScreenFragment.kt

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.openedx.course.presentation.unit.video
22

33
import android.os.Bundle
44
import android.view.View
5+
import android.webkit.WebView
56
import android.widget.FrameLayout
67
import androidx.core.os.bundleOf
78
import androidx.core.view.WindowInsetsCompat
@@ -12,7 +13,6 @@ import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
1213
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
1314
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.options.IFramePlayerOptions
1415
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.YouTubePlayerTracker
15-
import com.pierfrancescosoffritti.androidyoutubeplayer.core.ui.DefaultPlayerUiController
1616
import org.koin.android.ext.android.inject
1717
import org.koin.androidx.viewmodel.ext.android.viewModel
1818
import 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

Comments
 (0)