react-native-video-trim 1.0.21 → 1.0.23

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.
@@ -1,41 +1,23 @@
1
- //
2
- // VideoTrimmerViewController.swift
3
- // react-native-video-trim
4
- //
5
- // Created by Duc Trung Mai on 17/1/24.
6
- //
7
-
8
1
  import UIKit
9
2
  import AVKit
10
3
 
11
4
  extension CMTime {
12
5
  var displayString: String {
13
6
  let offset = TimeInterval(seconds)
14
- let numberOfNanosecondsFloat = (offset - TimeInterval(Int(offset))) * 1000.0
7
+ let numberOfNanosecondsFloat = (offset - TimeInterval(Int(offset))) * 100.0
15
8
  let nanoseconds = Int(numberOfNanosecondsFloat)
9
+
10
+ let formatter = CMTime.dateFormatter
11
+ return String(format: "%@.%02d", formatter.string(from: offset) ?? "00:00", nanoseconds)
12
+ }
13
+
14
+ private static var dateFormatter: DateComponentsFormatter = {
16
15
  let formatter = DateComponentsFormatter()
17
16
  formatter.unitsStyle = .positional
18
17
  formatter.zeroFormattingBehavior = .pad
19
18
  formatter.allowedUnits = [.minute, .second]
20
- return String(format: "%@.%03d", formatter.string(from: offset) ?? "00:00", nanoseconds)
21
- }
22
- }
23
-
24
- extension AVAsset {
25
- var fullRange: CMTimeRange {
26
- return CMTimeRange(start: .zero, duration: duration)
27
- }
28
- func trimmedComposition(_ range: CMTimeRange) -> AVAsset {
29
- guard CMTimeRangeEqual(fullRange, range) == false else {return self}
30
-
31
- let composition = AVMutableComposition()
32
- try? composition.insertTimeRange(range, of: self, at: .zero)
33
-
34
- if let videoTrack = tracks(withMediaType: .video).first {
35
- composition.tracks.forEach {$0.preferredTransform = videoTrack.preferredTransform}
36
- }
37
- return composition
38
- }
19
+ return formatter
20
+ }()
39
21
  }
40
22
 
41
23
  @available(iOS 13.0, *)
@@ -48,69 +30,60 @@ class VideoTrimmerViewController: UIViewController {
48
30
  var cancelBtnClicked: (() -> Void)?
49
31
  var saveBtnClicked: ((CMTimeRange) -> Void)?
50
32
 
51
- let playerController = AVPlayerViewController()
52
- var trimmer: VideoTrimmer!
53
- var timingStackView: UIStackView!
54
- var leadingTrimLabel: UILabel!
55
- var currentTimeLabel: UILabel!
56
- var trailingTrimLabel: UILabel!
57
-
33
+ private let playerController = AVPlayerViewController()
34
+ private var trimmer: VideoTrimmer!
35
+ private var timingStackView: UIStackView!
36
+ private var leadingTrimLabel: UILabel!
37
+ private var currentTimeLabel: UILabel!
38
+ private var trailingTrimLabel: UILabel!
58
39
  private var btnStackView: UIStackView!
59
40
  private var cancelBtn: UIButton!
60
41
  private var playBtn: UIButton!
61
42
  private var saveBtn: UIButton!
62
43
  private let playIcon = UIImage(systemName: "play.fill")
63
44
  private let pauseIcon = UIImage(systemName: "pause.fill")
64
-
65
- private var wasPlaying = false
66
- private var player: AVPlayer! {playerController.player}
45
+ private var player: AVPlayer! { playerController.player }
67
46
  private var timeObserverToken: Any?
68
47
 
48
+ var isSeekInProgress: Bool = false // Marker
49
+ private var chaseTime = CMTime.zero
50
+ private var preferredFrameRate: Float = 23.98
69
51
 
70
52
  // MARK: - Input
71
- @objc private func didBeginTrimming(_ sender: VideoTrimmer) {
72
- updateLabels()
73
-
74
- wasPlaying = (player.timeControlStatus != .paused)
75
- player.pause()
76
-
77
- updatePlayerAsset()
53
+ @objc private func didBeginTrimmingFromStart(_ sender: VideoTrimmer) {
54
+ handleBeforeProgressChange()
78
55
  }
79
56
 
80
- @objc private func didEndTrimming(_ sender: VideoTrimmer) {
81
- updateLabels()
82
-
83
- if wasPlaying == true {
84
- player.play()
85
- }
86
-
87
- updatePlayerAsset()
57
+ @objc private func leadingGrabberChanged(_ sender: VideoTrimmer) {
58
+ handleProgressChanged(time: trimmer.selectedRange.start)
88
59
  }
89
60
 
90
- @objc private func selectedRangeDidChanged(_ sender: VideoTrimmer) {
91
- updateLabels()
61
+ @objc private func didEndTrimmingFromStart(_ sender: VideoTrimmer) {
62
+ handleTrimmingEnd(true)
63
+ }
64
+
65
+ @objc private func didBeginTrimmingFromEnd(_ sender: VideoTrimmer) {
66
+ handleBeforeProgressChange()
67
+ }
68
+
69
+ @objc private func trailingGrabberChanged(_ sender: VideoTrimmer) {
70
+ handleProgressChanged(time: trimmer.selectedRange.end)
71
+ }
72
+
73
+ @objc private func didEndTrimmingFromEnd(_ sender: VideoTrimmer) {
74
+ handleTrimmingEnd(false)
92
75
  }
93
76
 
94
77
  @objc private func didBeginScrubbing(_ sender: VideoTrimmer) {
95
- updateLabels()
96
-
97
- wasPlaying = (player.timeControlStatus != .paused)
98
- player.pause()
78
+ handleBeforeProgressChange()
99
79
  }
100
80
 
101
81
  @objc private func didEndScrubbing(_ sender: VideoTrimmer) {
102
82
  updateLabels()
103
-
104
- if wasPlaying == true {
105
- player.play()
106
- }
107
83
  }
108
84
 
109
85
  @objc private func progressDidChanged(_ sender: VideoTrimmer) {
110
- updateLabels()
111
-
112
- let time = CMTimeSubtract(trimmer.progress, trimmer.selectedRange.start)
113
- player.seek(to: time, toleranceBefore: .zero, toleranceAfter: .zero)
86
+ handleProgressChanged(time: trimmer.progress)
114
87
  }
115
88
 
116
89
  // MARK: - Private
@@ -120,38 +93,84 @@ class VideoTrimmerViewController: UIViewController {
120
93
  trailingTrimLabel.text = trimmer.selectedRange.end.displayString
121
94
  }
122
95
 
123
- private func updatePlayerAsset() {
124
- let outputRange = trimmer.trimmingState == .none ? trimmer.selectedRange : asset.fullRange
125
- let trimmedAsset = asset.trimmedComposition(outputRange)
126
- if trimmedAsset != player.currentItem?.asset {
127
- player.replaceCurrentItem(with: AVPlayerItem(asset: trimmedAsset))
128
- }
96
+ private func handleBeforeProgressChange() {
97
+ updateLabels()
98
+ player.pause()
99
+ setPlayBtnIcon()
100
+ }
101
+
102
+ private func handleProgressChanged(time: CMTime) {
103
+ updateLabels()
104
+ seek(to: time)
105
+ }
106
+
107
+ private func handleTrimmingEnd(_ start: Bool) {
108
+ self.trimmer.progress = start ? trimmer.selectedRange.start : trimmer.selectedRange.end
109
+ updateLabels()
110
+ player.seek(to: trimmer.progress, toleranceBefore: .zero, toleranceAfter: .zero)
129
111
  }
130
112
 
131
113
  // MARK: - UIViewController
132
114
  override func viewDidLoad() {
133
115
  super.viewDidLoad()
134
116
 
135
- view.backgroundColor = .black
117
+ setupView()
118
+ setupButtons()
119
+ setupTimeLabels()
120
+ setupVideoTrimmer()
121
+ setupPlayerController()
122
+ setupTimeObserver()
136
123
 
137
- // bottom action buttons
138
- cancelBtn = UIButton(type: .system)
139
- cancelBtn.setTitle(cancelBtnText, for: .normal)
140
- cancelBtn.titleLabel?.font = .systemFont(ofSize: 18)
141
- cancelBtn.setTitleColor(.white, for: .normal)
142
- cancelBtn.addTarget(self, action: #selector(onCancelBtnClicked), for: .touchUpInside)
124
+ updateLabels()
125
+ }
126
+
127
+ override func viewWillDisappear(_ animated: Bool) {
128
+ super.viewWillDisappear(animated)
143
129
 
130
+ player.pause()
131
+ if let token = timeObserverToken {
132
+ player.removeTimeObserver(token)
133
+ timeObserverToken = nil
134
+ }
135
+ // Remove observer
136
+ NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
144
137
 
145
- playBtn = UIButton(type: .system)
146
- playBtn.setImage(playIcon, for: .normal)
147
- playBtn.tintColor = .systemBlue
148
- playBtn.addTarget(self, action: #selector(togglePlay(sender:)), for: .touchUpInside)
138
+ playerController.player = nil
139
+ playerController.dismiss(animated: false, completion: nil)
140
+ }
141
+
142
+ @objc private func togglePlay(sender: UIButton) {
143
+ if player.timeControlStatus == .playing {
144
+ player.pause()
145
+ } else {
146
+ if CMTimeCompare(trimmer.progress, trimmer.selectedRange.end) != -1 {
147
+ trimmer.progress = trimmer.selectedRange.start
148
+ player.seek(to: trimmer.progress, toleranceBefore: .zero, toleranceAfter: .zero)
149
+ }
150
+
151
+ player.play()
152
+ }
149
153
 
150
- saveBtn = UIButton(type: .system)
151
- saveBtn.setTitle(saveButtonText, for: .normal)
152
- saveBtn.titleLabel?.font = .systemFont(ofSize: 18)
153
- saveBtn.setTitleColor(.systemBlue, for: .normal)
154
- saveBtn.addTarget(self, action: #selector(onSaveBtnClicked), for: .touchUpInside)
154
+ setPlayBtnIcon()
155
+ }
156
+
157
+ @objc private func onSaveBtnClicked() {
158
+ saveBtnClicked?(trimmer.selectedRange)
159
+ }
160
+
161
+ @objc private func onCancelBtnClicked() {
162
+ cancelBtnClicked?()
163
+ }
164
+
165
+ // MARK: - Setup Methods
166
+ private func setupView() {
167
+ view.backgroundColor = .black
168
+ }
169
+
170
+ private func setupButtons() {
171
+ cancelBtn = UIButton.createButton(title: cancelBtnText, font: .systemFont(ofSize: 18), titleColor: .white, target: self, action: #selector(onCancelBtnClicked))
172
+ playBtn = UIButton.createButton(image: playIcon, tintColor: .systemBlue, target: self, action: #selector(togglePlay(sender:)))
173
+ saveBtn = UIButton.createButton(title: saveButtonText, font: .systemFont(ofSize: 18), titleColor: .systemBlue, target: self, action: #selector(onSaveBtnClicked))
155
174
 
156
175
  btnStackView = UIStackView(arrangedSubviews: [cancelBtn, playBtn, saveBtn])
157
176
  btnStackView.axis = .horizontal
@@ -163,24 +182,14 @@ class VideoTrimmerViewController: UIViewController {
163
182
  NSLayoutConstraint.activate([
164
183
  btnStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
165
184
  btnStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
166
- btnStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16),
185
+ btnStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16)
167
186
  ])
168
-
169
- // time labels
170
- leadingTrimLabel = UILabel()
171
- leadingTrimLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
172
- leadingTrimLabel.textAlignment = .left
173
- leadingTrimLabel.textColor = .white
174
-
175
- currentTimeLabel = UILabel()
176
- currentTimeLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
177
- currentTimeLabel.textAlignment = .center
178
- currentTimeLabel.textColor = .white
179
-
180
- trailingTrimLabel = UILabel()
181
- trailingTrimLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
182
- trailingTrimLabel.textAlignment = .right
183
- trailingTrimLabel.textColor = .white
187
+ }
188
+
189
+ private func setupTimeLabels() {
190
+ leadingTrimLabel = UILabel.createLabel(textAlignment: .left, textColor: .white)
191
+ currentTimeLabel = UILabel.createLabel(textAlignment: .center, textColor: .white)
192
+ trailingTrimLabel = UILabel.createLabel(textAlignment: .right, textColor: .white)
184
193
 
185
194
  timingStackView = UIStackView(arrangedSubviews: [leadingTrimLabel, currentTimeLabel, trailingTrimLabel])
186
195
  timingStackView.axis = .horizontal
@@ -192,50 +201,57 @@ class VideoTrimmerViewController: UIViewController {
192
201
  NSLayoutConstraint.activate([
193
202
  timingStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
194
203
  timingStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
195
- timingStackView.bottomAnchor.constraint(equalTo: btnStackView.topAnchor, constant: -8),
204
+ timingStackView.bottomAnchor.constraint(equalTo: btnStackView.topAnchor, constant: -8)
196
205
  ])
197
-
198
- // THIS IS WHERE WE SETUP THE VIDEOTRIMMER:
206
+ }
207
+
208
+ private func setupVideoTrimmer() {
199
209
  trimmer = VideoTrimmer()
200
- trimmer.asset = asset // this should happen before trimmer.selectedRange below otherwise its didSet will override
210
+ trimmer.asset = asset
201
211
  trimmer.minimumDuration = CMTime(seconds: 1, preferredTimescale: 600)
202
212
 
203
- if maximumDuration != nil {
204
- trimmer.maximumDuration = CMTime(seconds: max(1, Double(maximumDuration!)), preferredTimescale: 600) // minimum 1 second
205
-
206
- // guard check to make sure max duration can only <= asset.duration
207
- if CMTimeCompare(trimmer.maximumDuration, asset.duration) == 1 {
213
+ if let maxDuration = maximumDuration {
214
+ trimmer.maximumDuration = CMTime(seconds: max(1, Double(maxDuration)), preferredTimescale: 600)
215
+ if trimmer.maximumDuration > asset.duration {
208
216
  trimmer.maximumDuration = asset.duration
209
217
  }
210
-
211
218
  trimmer.selectedRange = CMTimeRange(start: .zero, end: trimmer.maximumDuration)
212
219
  }
213
-
214
- if minimumDuration != nil {
215
- trimmer.minimumDuration = CMTime(seconds: max(1, Double(minimumDuration!)), preferredTimescale: 600) // minimum 1 second
220
+
221
+ if let minDuration = minimumDuration {
222
+ trimmer.minimumDuration = CMTime(seconds: max(1, Double(minDuration)), preferredTimescale: 600)
216
223
  }
217
224
 
218
- trimmer.addTarget(self, action: #selector(didBeginTrimming(_:)), for: VideoTrimmer.didBeginTrimming)
219
- trimmer.addTarget(self, action: #selector(didEndTrimming(_:)), for: VideoTrimmer.didEndTrimming)
220
- trimmer.addTarget(self, action: #selector(selectedRangeDidChanged(_:)), for: VideoTrimmer.selectedRangeChanged)
221
225
  trimmer.addTarget(self, action: #selector(didBeginScrubbing(_:)), for: VideoTrimmer.didBeginScrubbing)
222
226
  trimmer.addTarget(self, action: #selector(didEndScrubbing(_:)), for: VideoTrimmer.didEndScrubbing)
223
227
  trimmer.addTarget(self, action: #selector(progressDidChanged(_:)), for: VideoTrimmer.progressChanged)
228
+
229
+ trimmer.addTarget(self, action: #selector(didBeginTrimmingFromStart(_:)), for: VideoTrimmer.didBeginTrimmingFromStart)
230
+ trimmer.addTarget(self, action: #selector(leadingGrabberChanged(_:)), for: VideoTrimmer.leadingGrabberChanged)
231
+ trimmer.addTarget(self, action: #selector(didEndTrimmingFromStart(_:)), for: VideoTrimmer.didEndTrimmingFromStart)
232
+
233
+ trimmer.addTarget(self, action: #selector(didBeginTrimmingFromEnd(_:)), for: VideoTrimmer.didBeginTrimmingFromEnd)
234
+ trimmer.addTarget(self, action: #selector(trailingGrabberChanged(_:)), for: VideoTrimmer.trailingGrabberChanged)
235
+ trimmer.addTarget(self, action: #selector(didEndTrimmingFromEnd(_:)), for: VideoTrimmer.didEndTrimmingFromEnd)
224
236
  view.addSubview(trimmer)
225
237
  trimmer.translatesAutoresizingMaskIntoConstraints = false
226
238
  NSLayoutConstraint.activate([
227
239
  trimmer.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
228
240
  trimmer.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
229
241
  trimmer.bottomAnchor.constraint(equalTo: timingStackView.topAnchor, constant: -16),
230
- trimmer.heightAnchor.constraint(equalToConstant: 50),
242
+ trimmer.heightAnchor.constraint(equalToConstant: 50)
231
243
  ])
232
-
233
- playerController.showsPlaybackControls = false // hide control buttons
244
+ }
245
+
246
+ private func setupPlayerController() {
247
+ playerController.showsPlaybackControls = false
234
248
  if #available(iOS 16.0, *) {
235
- playerController.allowsVideoFrameAnalysis = false // hide live text
249
+ playerController.allowsVideoFrameAnalysis = false
236
250
  }
237
251
  playerController.player = AVPlayer()
238
- try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: []) // this is to play audio even when device is in silent mode
252
+ player.replaceCurrentItem(with: AVPlayerItem(asset: asset))
253
+
254
+ try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
239
255
  addChild(playerController)
240
256
  view.addSubview(playerController.view)
241
257
  playerController.view.translatesAutoresizingMaskIntoConstraints = false
@@ -246,55 +262,108 @@ class VideoTrimmerViewController: UIViewController {
246
262
  playerController.view.bottomAnchor.constraint(equalTo: trimmer.topAnchor, constant: -16)
247
263
  ])
248
264
 
249
- updatePlayerAsset()
250
-
265
+ // Add observer for the end of playback
266
+ NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
267
+ }
268
+
269
+ @objc private func playerDidFinishPlaying(note: NSNotification) {
270
+ // Directly set the play icon
271
+ // the reason in at this time player.timeControlStatus == .playing still returns true
272
+ playBtn.setImage(self.playIcon, for: .normal)
273
+ }
274
+
275
+ private func setupTimeObserver() {
251
276
  timeObserverToken = player.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 30), queue: .main) { [weak self] time in
252
- guard let self = self else {return}
253
-
254
- currentTimeLabel.text = player.currentTime().displayString
277
+ guard let self = self else { return }
255
278
 
256
- // when we're not trimming, the players starting point is actual later than the trimmer,
257
- // (because the vidoe has been trimmed), so we need to account for that.
258
- // When we're trimming, we always show the full video
259
- let finalTime = self.trimmer.trimmingState == .none ? CMTimeAdd(time, self.trimmer.selectedRange.start) : time
260
- self.trimmer.progress = finalTime
279
+ if self.player.timeControlStatus != .playing {
280
+ return
281
+ }
261
282
 
262
- if self.player.timeControlStatus == .playing {
263
- self.playBtn.setImage(self.pauseIcon, for: .normal)
264
- } else {
265
- self.playBtn.setImage(self.playIcon, for: .normal)
283
+ self.trimmer.progress = time
284
+
285
+ // pause if reach end of selected range
286
+ if CMTimeCompare(self.trimmer.progress, trimmer.selectedRange.end) == 1 {
287
+ player.pause()
288
+ self.trimmer.progress = trimmer.selectedRange.end
289
+ player.seek(to: trimmer.selectedRange.end, toleranceBefore: .zero, toleranceAfter: .zero)
266
290
  }
291
+
292
+ currentTimeLabel.text = trimmer.progress.displayString
293
+
294
+ self.setPlayBtnIcon()
267
295
  }
268
-
269
- updateLabels()
270
296
  }
271
297
 
272
- override func viewWillDisappear(_ animated: Bool) {
273
- super.viewWillDisappear(animated)
274
-
275
- player.pause()
276
- if timeObserverToken != nil {
277
- player.removeTimeObserver(timeObserverToken as Any)
278
- timeObserverToken = nil
279
- }
280
- playerController.player = nil
281
- playerController.dismiss(animated: false, completion: nil)
298
+ private func setPlayBtnIcon() {
299
+ self.playBtn.setImage(self.player.timeControlStatus == .playing ? self.pauseIcon : self.playIcon, for: .normal)
282
300
  }
283
301
 
284
- @objc private func togglePlay(sender: UIButton) {
285
- if player.timeControlStatus == .playing {
286
- player.pause()
287
- } else {
288
- player.play()
302
+ // ====Smoother seek
303
+ public func seek(to time: CMTime) {
304
+ seekSmoothlyToTime(newChaseTime: time)
305
+ }
306
+
307
+ private func seekSmoothlyToTime(newChaseTime: CMTime) {
308
+ if CMTimeCompare(newChaseTime, chaseTime) != 0 {
309
+ chaseTime = newChaseTime
310
+
311
+ if !isSeekInProgress {
312
+ trySeekToChaseTime()
313
+ }
289
314
  }
290
-
291
315
  }
292
316
 
293
- @objc func onSaveBtnClicked() {
294
- saveBtnClicked?(trimmer.selectedRange)
317
+ private func trySeekToChaseTime() {
318
+ guard player?.status == .readyToPlay else { return }
319
+ actuallySeekToTime()
295
320
  }
296
321
 
297
- @objc func onCancelBtnClicked() {
298
- cancelBtnClicked?()
322
+ private func actuallySeekToTime() {
323
+ isSeekInProgress = true
324
+ let seekTimeInProgress = chaseTime
325
+
326
+ player?.seek(to: seekTimeInProgress, toleranceBefore: .zero, toleranceAfter: .zero) { [weak self] _ in
327
+ guard let `self` = self else { return }
328
+
329
+ if CMTimeCompare(seekTimeInProgress, self.chaseTime) == 0 {
330
+ self.isSeekInProgress = false
331
+ } else {
332
+ self.trySeekToChaseTime()
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ private extension UIButton {
339
+ static func createButton(title: String? = nil, image: UIImage? = nil, font: UIFont? = nil, titleColor: UIColor? = nil, tintColor: UIColor? = nil, target: Any?, action: Selector) -> UIButton {
340
+ let button = UIButton(type: .system)
341
+ if let title = title {
342
+ button.setTitle(title, for: .normal)
343
+ }
344
+ if let image = image {
345
+ button.setImage(image, for: .normal)
346
+ }
347
+ if let font = font {
348
+ button.titleLabel?.font = font
349
+ }
350
+ if let titleColor = titleColor {
351
+ button.setTitleColor(titleColor, for: .normal)
352
+ }
353
+ if let tintColor = tintColor {
354
+ button.tintColor = tintColor
355
+ }
356
+ button.addTarget(target, action: action, for: .touchUpInside)
357
+ return button
358
+ }
359
+ }
360
+
361
+ private extension UILabel {
362
+ static func createLabel(textAlignment: NSTextAlignment, textColor: UIColor) -> UILabel {
363
+ let label = UILabel()
364
+ label.font = UIFont.preferredFont(forTextStyle: .caption1)
365
+ label.textAlignment = textAlignment
366
+ label.textColor = textColor
367
+ return label
299
368
  }
300
369
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-video-trim",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Video trimmer for your React Native app",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",