react-native-tpstreams 1.1.0-debug.8 → 1.1.0-debug.9
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.
|
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.swift_version = '5.0'
|
|
13
13
|
|
|
14
14
|
s.platforms = { :ios => min_ios_version_supported }
|
|
15
|
-
|
|
15
|
+
s.source = { :git => "https://github.com/testpress/react-native-tpstreams.git", :tag => "#{s.version}" }
|
|
16
16
|
|
|
17
17
|
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
|
|
18
18
|
s.private_header_files = "ios/**/*.h"
|
|
@@ -22,12 +22,6 @@ Pod::Spec.new do |s|
|
|
|
22
22
|
'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES'
|
|
23
23
|
}
|
|
24
24
|
s.dependency "TPStreamsSDK" , "1.2.13"
|
|
25
|
-
s.source = {
|
|
26
|
-
:git => "https://github.com/testpress/iOSPlayerSDK.git",
|
|
27
|
-
:branch => "fix_download_cleanup"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
25
|
|
|
32
26
|
# Ensure the module is not built as a framework to avoid bridging header conflicts
|
|
33
27
|
s.static_framework = true
|
|
@@ -24,7 +24,15 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
24
24
|
private var playbackSpeedObserver: NSKeyValueObservation?
|
|
25
25
|
private var timeControlStatusObserver: NSKeyValueObservation?
|
|
26
26
|
private var playerStateObserver: NSKeyValueObservation?
|
|
27
|
+
private lazy var loadingIndicator: UIActivityIndicatorView = {
|
|
28
|
+
let indicator = UIActivityIndicatorView(style: .large)
|
|
29
|
+
indicator.hidesWhenStopped = true
|
|
30
|
+
indicator.color = .white
|
|
31
|
+
indicator.translatesAutoresizingMaskIntoConstraints = false
|
|
32
|
+
return indicator
|
|
33
|
+
}()
|
|
27
34
|
private var setupScheduled = false
|
|
35
|
+
private var isPlayerReady = false
|
|
28
36
|
private var pendingOfflineCredentialsCompletion: ((String?, Double) -> Void)?
|
|
29
37
|
private var _offlineLicenseExpireTime: Double = TPStreamsRNPlayerView.maxOfflineLicenseDuration
|
|
30
38
|
|
|
@@ -57,11 +65,13 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
57
65
|
override init(frame: CGRect) {
|
|
58
66
|
super.init(frame: frame)
|
|
59
67
|
backgroundColor = .black
|
|
68
|
+
setupLoadingIndicator()
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
required init?(coder: NSCoder) {
|
|
63
72
|
super.init(coder: coder)
|
|
64
73
|
backgroundColor = .black
|
|
74
|
+
setupLoadingIndicator()
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
override func layoutSubviews() {
|
|
@@ -85,6 +95,7 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
85
95
|
|
|
86
96
|
private func setupPlayer() {
|
|
87
97
|
cleanupPlayer()
|
|
98
|
+
isPlayerReady = false
|
|
88
99
|
|
|
89
100
|
player = TPStreamsDownloadManager.shared.isAssetDownloaded(assetID: videoId as String)
|
|
90
101
|
? createOfflinePlayer()
|
|
@@ -95,6 +106,7 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
95
106
|
setupScheduled = false
|
|
96
107
|
return
|
|
97
108
|
}
|
|
109
|
+
showLoadingIndicator()
|
|
98
110
|
setupTokenDelegate()
|
|
99
111
|
configurePlayerView()
|
|
100
112
|
observePlayerChanges()
|
|
@@ -199,6 +211,7 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
199
211
|
playerVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
200
212
|
playerVC.view.isHidden = false
|
|
201
213
|
bringSubviewToFront(playerVC.view)
|
|
214
|
+
bringSubviewToFront(loadingIndicator)
|
|
202
215
|
playerVC.didMove(toParent: parentVC)
|
|
203
216
|
}
|
|
204
217
|
|
|
@@ -235,8 +248,17 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
235
248
|
|
|
236
249
|
timeControlStatusObserver = player.observe(\.timeControlStatus, options: [.new, .initial]) { [weak self] player, _ in
|
|
237
250
|
DispatchQueue.main.async {
|
|
238
|
-
let
|
|
239
|
-
|
|
251
|
+
guard let self = self else { return }
|
|
252
|
+
let timeStatus = player.timeControlStatus
|
|
253
|
+
let isPlaying = timeStatus == .playing
|
|
254
|
+
|
|
255
|
+
// Show loader while buffering; hide only after player is ready.
|
|
256
|
+
if timeStatus == .waitingToPlayAtSpecifiedRate {
|
|
257
|
+
self.showLoadingIndicator()
|
|
258
|
+
} else if self.isPlayerReady {
|
|
259
|
+
self.hideLoadingIndicator()
|
|
260
|
+
}
|
|
261
|
+
self.onIsPlayingChanged?(["isPlaying": isPlaying])
|
|
240
262
|
}
|
|
241
263
|
}
|
|
242
264
|
}
|
|
@@ -246,8 +268,25 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
246
268
|
|
|
247
269
|
playerStateObserver = player.observe(\.status, options: [.new, .initial]) { [weak self] player, _ in
|
|
248
270
|
DispatchQueue.main.async {
|
|
249
|
-
let
|
|
250
|
-
|
|
271
|
+
guard let self = self else { return }
|
|
272
|
+
let status = player.status
|
|
273
|
+
let state = self.mapPlayerStateToAndroid(status) ?? PlaybackState.idle.rawValue
|
|
274
|
+
self.onPlayerStateChanged?(["playbackState": state])
|
|
275
|
+
|
|
276
|
+
// Drive readiness and loader from AVPlayer.status.
|
|
277
|
+
switch status {
|
|
278
|
+
case .readyToPlay:
|
|
279
|
+
self.isPlayerReady = true
|
|
280
|
+
if player.timeControlStatus != .waitingToPlayAtSpecifiedRate {
|
|
281
|
+
self.hideLoadingIndicator()
|
|
282
|
+
}
|
|
283
|
+
case .failed:
|
|
284
|
+
self.isPlayerReady = false
|
|
285
|
+
self.hideLoadingIndicator()
|
|
286
|
+
default:
|
|
287
|
+
self.isPlayerReady = false
|
|
288
|
+
self.showLoadingIndicator()
|
|
289
|
+
}
|
|
251
290
|
}
|
|
252
291
|
}
|
|
253
292
|
|
|
@@ -287,6 +326,30 @@ class TPStreamsRNPlayerView: UIView {
|
|
|
287
326
|
TPStreamsDownloadModule.shared?.setAccessTokenDelegate(self)
|
|
288
327
|
}
|
|
289
328
|
|
|
329
|
+
private func setupLoadingIndicator() {
|
|
330
|
+
guard loadingIndicator.superview == nil else { return }
|
|
331
|
+
|
|
332
|
+
addSubview(loadingIndicator)
|
|
333
|
+
|
|
334
|
+
NSLayoutConstraint.activate([
|
|
335
|
+
loadingIndicator.centerXAnchor.constraint(equalTo: centerXAnchor),
|
|
336
|
+
loadingIndicator.centerYAnchor.constraint(equalTo: centerYAnchor)
|
|
337
|
+
])
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private func showLoadingIndicator() {
|
|
341
|
+
DispatchQueue.main.async {
|
|
342
|
+
self.loadingIndicator.startAnimating()
|
|
343
|
+
self.bringSubviewToFront(self.loadingIndicator)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private func hideLoadingIndicator() {
|
|
348
|
+
DispatchQueue.main.async {
|
|
349
|
+
self.loadingIndicator.stopAnimating()
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
290
353
|
private static func sanitizeLicenseDuration(_ value: Double) -> Double {
|
|
291
354
|
guard value > 0 else { return maxOfflineLicenseDuration }
|
|
292
355
|
return min(value, maxOfflineLicenseDuration)
|