Skip to content

Commit

Permalink
chore: show subtitles for videos in full-screen mode (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
shafqat-muneer authored Nov 22, 2024
1 parent 9409d67 commit dc2eab5
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 7 deletions.
10 changes: 9 additions & 1 deletion Course/Course/Presentation/Video/EncodedVideoPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public struct EncodedVideoPlayer: View {
@State private var isLoading: Bool = true
@State private var isAnimating: Bool = false
@State private var isOrientationChanged: Bool = false
@State private var subtitleText: String = ""

@State var showAlert = false
@State var alertMessage: String? {
Expand All @@ -54,7 +55,10 @@ public struct EncodedVideoPlayer: View {
VStack(spacing: 10) {
HStack {
VStack {
PlayerViewController(playerController: viewModel.controller)
PlayerViewController(
playerController: viewModel.controller,
subtitleText: $subtitleText
)
.aspectRatio(16 / 9, contentMode: .fit)
.frame(minWidth: playerWidth(for: reader.size))
.cornerRadius(12)
Expand Down Expand Up @@ -115,6 +119,10 @@ public struct EncodedVideoPlayer: View {
viewModel.controller.player?.allowsExternalPlayback = true
viewModel.controller.setNeedsStatusBarAppearanceUpdate()
}
.onReceive(viewModel.$currentTime) { currentTime in
let subtitle = viewModel.findSubtitle(at: Date(milliseconds: currentTime))
subtitleText = subtitle?.text ?? ""
}
}

private func playerWidth(for size: CGSize) -> CGFloat {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Core
import Combine

public class EncodedVideoPlayerViewModel: VideoPlayerViewModel {
var controller: AVPlayerViewController {
(playerHolder.playerController as? AVPlayerViewController) ?? AVPlayerViewController()
var controller: CustomAVPlayerViewController {
(playerHolder.playerController as? CustomAVPlayerViewController) ?? CustomAVPlayerViewController()
}
}
68 changes: 65 additions & 3 deletions Course/Course/Presentation/Video/PlayerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import SwiftUI
import _AVKit_SwiftUI

struct PlayerViewController: UIViewControllerRepresentable {
var playerController: AVPlayerViewController
var playerController: CustomAVPlayerViewController
@Binding var subtitleText: String

func makeUIViewController(context: Context) -> AVPlayerViewController {
func makeUIViewController(context: Context) -> CustomAVPlayerViewController {
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
} catch {
Expand All @@ -23,5 +24,66 @@ struct PlayerViewController: UIViewControllerRepresentable {
return playerController
}

func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {}
func updateUIViewController(_ playerController: CustomAVPlayerViewController, context: Context) {
playerController.subtitleText = subtitleText
}
}

class CustomAVPlayerViewController: AVPlayerViewController {
private let subtitleLabel = UILabel()

var subtitleText: String = "" {
didSet {
subtitleLabel.text = subtitleText
}
}

var hideSubtitle: Bool = false {
didSet {
subtitleLabel.isHidden = hideSubtitle
}
}

override func viewDidLoad() {
super.viewDidLoad()

// Configure the subtitle label
subtitleLabel.textColor = .white
subtitleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
subtitleLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
subtitleLabel.textAlignment = .center
subtitleLabel.numberOfLines = 0
subtitleLabel.layer.cornerRadius = 8
subtitleLabel.layer.masksToBounds = true
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.isHidden = true

self.delegate = self

// Add subtitle label to the content overlay view of AVPlayerViewController
contentOverlayView?.addSubview(subtitleLabel)

// Set constraints for the subtitle label
NSLayoutConstraint.activate([
subtitleLabel.centerXAnchor.constraint(equalTo: contentOverlayView!.centerXAnchor),
subtitleLabel.bottomAnchor.constraint(equalTo: contentOverlayView!.bottomAnchor, constant: -20),
subtitleLabel.widthAnchor.constraint(lessThanOrEqualTo: contentOverlayView!.widthAnchor, multiplier: 0.9)
])
}
}

extension CustomAVPlayerViewController: AVPlayerViewControllerDelegate {
func playerViewController(
_ playerViewController: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator coordinator: any UIViewControllerTransitionCoordinator
) {
hideSubtitle = false
}

func playerViewController(
_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: any UIViewControllerTransitionCoordinator
) {
hideSubtitle = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public class PlayerViewControllerHolder: PlayerViewControllerHolderProtocol {
let pipManager: PipManagerProtocol

public lazy var playerController: PlayerControllerProtocol? = {
let playerController = AVPlayerViewController()
let playerController = CustomAVPlayerViewController()
playerController.modalPresentationStyle = .fullScreen
playerController.allowsPictureInPicturePlayback = true
playerController.canStartPictureInPictureAutomaticallyFromInline = true
Expand Down
4 changes: 4 additions & 0 deletions Course/Course/Presentation/Video/VideoPlayerViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,8 @@ public class VideoPlayerViewModel: ObservableObject {
duration: playerHolder.duration
)
}

func findSubtitle(at currentTime: Date) -> Subtitle? {
return subtitles.first { $0.fromTo.contains(currentTime) }
}
}

0 comments on commit dc2eab5

Please sign in to comment.