@capgo/capacitor-video-player 8.1.9 → 8.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/android/build.gradle
CHANGED
|
@@ -58,7 +58,7 @@ dependencies {
|
|
|
58
58
|
implementation 'androidx.gridlayout:gridlayout:1.1.0'
|
|
59
59
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
|
60
60
|
implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1'
|
|
61
|
-
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.
|
|
61
|
+
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
|
|
62
62
|
implementation 'com.google.android.exoplayer:exoplayer-hls:2.19.1'
|
|
63
63
|
implementation 'com.google.android.exoplayer:exoplayer-dash:2.19.1'
|
|
64
64
|
implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.19.1'
|
|
@@ -38,7 +38,7 @@ import java.util.Map;
|
|
|
38
38
|
)
|
|
39
39
|
public class VideoPlayerPlugin extends Plugin {
|
|
40
40
|
|
|
41
|
-
private final String pluginVersion = "8.1.
|
|
41
|
+
private final String pluginVersion = "8.1.11";
|
|
42
42
|
|
|
43
43
|
// Permission alias constants
|
|
44
44
|
private static final String PERMISSION_DENIED_ERROR = "Unable to access media videos, user denied permission request";
|
|
@@ -24,6 +24,7 @@ final class VideoPlayerCastController: NSObject {
|
|
|
24
24
|
private weak var player: AVPlayer?
|
|
25
25
|
private weak var playerViewController: AVPlayerViewController?
|
|
26
26
|
private weak var castButton: GCKUICastButton?
|
|
27
|
+
private weak var castIndicatorLabel: UILabel?
|
|
27
28
|
private weak var observedRemoteMediaClient: GCKRemoteMediaClient?
|
|
28
29
|
private var mediaLoadRequest: GCKRequest?
|
|
29
30
|
private var pendingCastCommands: [PendingCastCommand] = []
|
|
@@ -36,6 +37,9 @@ final class VideoPlayerCastController: NSObject {
|
|
|
36
37
|
private var onPlay: (() -> Void)?
|
|
37
38
|
private var onPause: (() -> Void)?
|
|
38
39
|
private var onEnd: (() -> Void)?
|
|
40
|
+
private var controlsHideTimer: Timer?
|
|
41
|
+
private weak var tapGestureRecognizer: UITapGestureRecognizer?
|
|
42
|
+
private static let overlayAutoHideDuration: TimeInterval = 3.0
|
|
39
43
|
|
|
40
44
|
var isCasting: Bool {
|
|
41
45
|
return remoteMediaClient != nil && isLoadedOnCast
|
|
@@ -68,6 +72,8 @@ final class VideoPlayerCastController: NSObject {
|
|
|
68
72
|
|
|
69
73
|
GCKCastContext.sharedInstance().sessionManager.add(self)
|
|
70
74
|
self.addCastButton(to: playerViewController)
|
|
75
|
+
self.addCastIndicator(to: playerViewController)
|
|
76
|
+
self.beginObservingPlayerTaps(playerViewController)
|
|
71
77
|
self.loadMediaIfCastSessionAvailable()
|
|
72
78
|
}
|
|
73
79
|
|
|
@@ -98,8 +104,17 @@ final class VideoPlayerCastController: NSObject {
|
|
|
98
104
|
|
|
99
105
|
self.stopRemoteMediaObservation()
|
|
100
106
|
GCKCastContext.sharedInstance().sessionManager.remove(self)
|
|
107
|
+
self.controlsHideTimer?.invalidate()
|
|
108
|
+
self.controlsHideTimer = nil
|
|
109
|
+
if let tapRecognizer = self.tapGestureRecognizer,
|
|
110
|
+
let view = self.playerViewController?.view {
|
|
111
|
+
view.removeGestureRecognizer(tapRecognizer)
|
|
112
|
+
}
|
|
113
|
+
self.tapGestureRecognizer = nil
|
|
101
114
|
self.castButton?.removeFromSuperview()
|
|
102
115
|
self.castButton = nil
|
|
116
|
+
self.castIndicatorLabel?.removeFromSuperview()
|
|
117
|
+
self.castIndicatorLabel = nil
|
|
103
118
|
self.player = nil
|
|
104
119
|
self.playerViewController = nil
|
|
105
120
|
self.isLoadedOnCast = false
|
|
@@ -277,13 +292,93 @@ private extension VideoPlayerCastController {
|
|
|
277
292
|
NSLayoutConstraint.activate([
|
|
278
293
|
button.widthAnchor.constraint(equalToConstant: 44),
|
|
279
294
|
button.heightAnchor.constraint(equalToConstant: 44),
|
|
280
|
-
|
|
295
|
+
// Position below AVPlayerViewController's top row of controls (Done/X and route picker)
|
|
296
|
+
// using trailing to stay away from the leading-side dismiss button.
|
|
297
|
+
button.topAnchor.constraint(equalTo: overlayView.safeAreaLayoutGuide.topAnchor, constant: 60),
|
|
281
298
|
button.trailingAnchor.constraint(equalTo: overlayView.safeAreaLayoutGuide.trailingAnchor, constant: -16)
|
|
282
299
|
])
|
|
283
300
|
|
|
284
301
|
castButton = button
|
|
285
302
|
}
|
|
286
303
|
|
|
304
|
+
func addCastIndicator(to playerViewController: AVPlayerViewController) {
|
|
305
|
+
guard castIndicatorLabel == nil else {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
guard let overlayView = playerViewController.view else {
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
let label = UILabel(frame: .zero)
|
|
314
|
+
label.translatesAutoresizingMaskIntoConstraints = false
|
|
315
|
+
label.text = "Casting"
|
|
316
|
+
label.textColor = .white
|
|
317
|
+
label.font = UIFont.preferredFont(forTextStyle: .caption1)
|
|
318
|
+
label.backgroundColor = UIColor.black.withAlphaComponent(0.55)
|
|
319
|
+
label.layer.cornerRadius = 10
|
|
320
|
+
label.clipsToBounds = true
|
|
321
|
+
label.isHidden = true
|
|
322
|
+
|
|
323
|
+
overlayView.addSubview(label)
|
|
324
|
+
|
|
325
|
+
if let castButton = castButton {
|
|
326
|
+
NSLayoutConstraint.activate([
|
|
327
|
+
label.centerYAnchor.constraint(equalTo: castButton.centerYAnchor),
|
|
328
|
+
label.trailingAnchor.constraint(equalTo: castButton.leadingAnchor, constant: -8)
|
|
329
|
+
])
|
|
330
|
+
} else {
|
|
331
|
+
NSLayoutConstraint.activate([
|
|
332
|
+
label.topAnchor.constraint(equalTo: overlayView.safeAreaLayoutGuide.topAnchor, constant: 60),
|
|
333
|
+
label.trailingAnchor.constraint(equalTo: overlayView.safeAreaLayoutGuide.trailingAnchor, constant: -68)
|
|
334
|
+
])
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
castIndicatorLabel = label
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
func beginObservingPlayerTaps(_ playerViewController: AVPlayerViewController) {
|
|
341
|
+
guard let overlayView = playerViewController.view else { return }
|
|
342
|
+
// Remove any existing recognizer before adding a new one to prevent duplicates.
|
|
343
|
+
if let existing = tapGestureRecognizer {
|
|
344
|
+
overlayView.removeGestureRecognizer(existing)
|
|
345
|
+
}
|
|
346
|
+
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handlePlayerTap))
|
|
347
|
+
tapRecognizer.cancelsTouchesInView = false
|
|
348
|
+
overlayView.addGestureRecognizer(tapRecognizer)
|
|
349
|
+
self.tapGestureRecognizer = tapRecognizer
|
|
350
|
+
// Show the overlay immediately; it will auto-hide after the standard controls delay.
|
|
351
|
+
showOverlayControls()
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
@objc func handlePlayerTap() {
|
|
355
|
+
showOverlayControls()
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
func showOverlayControls() {
|
|
359
|
+
castButton?.isHidden = false
|
|
360
|
+
castIndicatorLabel?.isHidden = !isCasting
|
|
361
|
+
controlsHideTimer?.invalidate()
|
|
362
|
+
controlsHideTimer = Timer.scheduledTimer(withTimeInterval: Self.overlayAutoHideDuration, repeats: false) { [weak self] _ in
|
|
363
|
+
self?.hideOverlayControls()
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
func hideOverlayControls() {
|
|
368
|
+
controlsHideTimer = nil
|
|
369
|
+
let button = castButton
|
|
370
|
+
let label = castIndicatorLabel
|
|
371
|
+
UIView.animate(withDuration: 0.3, animations: {
|
|
372
|
+
button?.alpha = 0
|
|
373
|
+
label?.alpha = 0
|
|
374
|
+
}, completion: { _ in
|
|
375
|
+
button?.isHidden = true
|
|
376
|
+
label?.isHidden = true
|
|
377
|
+
button?.alpha = 1
|
|
378
|
+
label?.alpha = 1
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
287
382
|
func loadMediaIfCastSessionAvailable() {
|
|
288
383
|
guard let remoteMediaClient = remoteMediaClient,
|
|
289
384
|
let mediaInfo = makeMediaInformation() else {
|
|
@@ -511,6 +606,10 @@ private extension VideoPlayerCastController {
|
|
|
511
606
|
isLoadingOnCast = false
|
|
512
607
|
isLoadedOnCast = true
|
|
513
608
|
didNotifyRemoteEnd = false
|
|
609
|
+
DispatchQueue.main.async { [weak self] in
|
|
610
|
+
// Reveal the cast indicator and extend the controls visibility window.
|
|
611
|
+
self?.showOverlayControls()
|
|
612
|
+
}
|
|
514
613
|
flushPendingCastCommands()
|
|
515
614
|
}
|
|
516
615
|
|
|
@@ -8,7 +8,7 @@ import AVKit
|
|
|
8
8
|
*/
|
|
9
9
|
@objc(VideoPlayerPlugin)
|
|
10
10
|
public class VideoPlayerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
11
|
-
private let pluginVersion: String = "8.1.
|
|
11
|
+
private let pluginVersion: String = "8.1.11"
|
|
12
12
|
public let identifier = "VideoPlayerPlugin"
|
|
13
13
|
public let jsName = "VideoPlayer"
|
|
14
14
|
public let pluginMethods: [CAPPluginMethod] = [
|