react-native-video-trim 6.2.3 → 7.0.0

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.
@@ -0,0 +1,15 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="18.818dp"
3
+ android:height="18.232dp"
4
+ android:viewportWidth="18.818"
5
+ android:viewportHeight="18.232">
6
+ <path
7
+ android:fillColor="#FF000000"
8
+ android:pathData="M0,0h18.818v18.232h-18.818z"
9
+ android:strokeAlpha="0"
10
+ android:fillAlpha="0"/>
11
+ <path
12
+ android:pathData="M0,6.572C0,6.807 0.098,7.031 0.293,7.217L6.035,12.852C6.201,13.027 6.455,13.125 6.66,13.125C7.188,13.125 7.529,12.773 7.529,12.266C7.529,12.012 7.441,11.826 7.295,11.67L4.473,8.926L1.719,6.572L4.473,4.209L7.295,1.465C7.441,1.309 7.529,1.123 7.529,0.869C7.529,0.361 7.188,0.01 6.66,0.01C6.455,0.01 6.201,0.107 6.035,0.283L0.293,5.918C0.098,6.104 0,6.328 0,6.572ZM8.486,17.363C8.486,17.842 8.838,18.232 9.375,18.232L11.631,18.232C15.996,18.232 18.457,15.742 18.457,12.002C18.457,8.271 15.928,5.693 11.475,5.693L4.912,5.693L1.68,5.84C1.279,5.859 0.957,6.162 0.957,6.572C0.957,6.973 1.279,7.275 1.68,7.295L4.912,7.441L11.621,7.441C14.951,7.441 16.709,9.277 16.709,11.904C16.709,14.541 14.951,16.494 11.621,16.494L9.375,16.494C8.838,16.494 8.486,16.885 8.486,17.363Z"
13
+ android:fillColor="#ffffff"
14
+ android:fillAlpha="0.85"/>
15
+ </vector>
@@ -0,0 +1,15 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="18.818dp"
3
+ android:height="18.232dp"
4
+ android:viewportWidth="18.818"
5
+ android:viewportHeight="18.232">
6
+ <path
7
+ android:fillColor="#FF000000"
8
+ android:pathData="M0,0h18.818v18.232h-18.818z"
9
+ android:strokeAlpha="0"
10
+ android:fillAlpha="0"/>
11
+ <path
12
+ android:pathData="M18.457,6.572C18.457,6.328 18.359,6.104 18.164,5.918L12.422,0.283C12.256,0.107 12.002,0.01 11.787,0.01C11.269,0.01 10.928,0.361 10.928,0.869C10.928,1.123 11.006,1.309 11.162,1.465L13.975,4.209L16.738,6.572L13.975,8.926L11.162,11.67C11.006,11.826 10.928,12.012 10.928,12.266C10.928,12.773 11.269,13.125 11.787,13.125C12.002,13.125 12.256,13.027 12.422,12.852L18.164,7.217C18.359,7.031 18.457,6.807 18.457,6.572ZM9.971,17.363C9.971,16.885 9.619,16.494 9.082,16.494L6.836,16.494C3.506,16.494 1.738,14.541 1.738,11.904C1.738,9.277 3.506,7.441 6.836,7.441L13.535,7.441L16.768,7.295C17.178,7.275 17.5,6.973 17.5,6.572C17.5,6.162 17.178,5.859 16.768,5.84L13.535,5.693L6.982,5.693C2.52,5.693 0,8.271 0,12.002C0,15.742 2.451,18.232 6.826,18.232L9.082,18.232C9.619,18.232 9.971,17.842 9.971,17.363Z"
13
+ android:fillColor="#ffffff"
14
+ android:fillAlpha="0.85"/>
15
+ </vector>
@@ -0,0 +1,15 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="21.777dp"
3
+ android:height="21.982dp"
4
+ android:viewportWidth="21.777"
5
+ android:viewportHeight="21.982">
6
+ <path
7
+ android:fillColor="#FF000000"
8
+ android:pathData="M0,0h21.777v21.982h-21.777z"
9
+ android:strokeAlpha="0"
10
+ android:fillAlpha="0"/>
11
+ <path
12
+ android:pathData="M21.416,16.553C21.416,16.094 21.113,15.811 20.635,15.811L6.553,15.811C6.338,15.811 6.27,15.742 6.27,15.527L6.27,1.445C6.27,0.957 5.957,0.625 5.479,0.625C5.01,0.625 4.697,0.957 4.697,1.445L4.697,16.514C4.697,16.982 5,17.285 5.469,17.285L20.635,17.285C21.113,17.285 21.416,17.002 21.416,16.553ZM0,6.055C0,6.523 0.303,6.797 0.771,6.797L14.863,6.797C15.078,6.797 15.146,6.875 15.146,7.08L15.146,21.162C15.146,21.65 15.459,21.982 15.928,21.982C16.406,21.982 16.719,21.65 16.719,21.162L16.719,6.104C16.719,5.635 16.416,5.322 15.947,5.322L0.771,5.322C0.303,5.322 0,5.605 0,6.055Z"
13
+ android:fillColor="#ffffff"
14
+ android:fillAlpha="0.85"/>
15
+ </vector>
@@ -0,0 +1,19 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24.082dp"
3
+ android:height="24.727dp"
4
+ android:viewportWidth="24.082"
5
+ android:viewportHeight="24.727">
6
+ <path
7
+ android:fillColor="#FF000000"
8
+ android:pathData="M0,0h24.082v24.727h-24.082z"
9
+ android:strokeAlpha="0"
10
+ android:fillAlpha="0"/>
11
+ <path
12
+ android:pathData="M7.021,21.353L16.699,21.353C18.369,21.353 19.209,20.562 19.209,18.853L19.209,9.194C19.209,7.485 18.369,6.685 16.699,6.685L7.021,6.685C5.352,6.685 4.512,7.485 4.512,9.194L4.512,18.853C4.512,20.562 5.352,21.353 7.021,21.353ZM7.051,19.78C6.387,19.78 6.084,19.507 6.084,18.823L6.084,9.214C6.084,8.53 6.387,8.257 7.051,8.257L16.67,8.257C17.344,8.257 17.637,8.53 17.637,9.214L17.637,18.823C17.637,19.507 17.344,19.78 16.67,19.78Z"
13
+ android:fillColor="#ffffff"
14
+ android:fillAlpha="0.85"/>
15
+ <path
16
+ android:pathData="M19.209,4.312L19.209,0.698C19.209,-0.024 18.662,-0.19 18.115,0.22L15.654,2.027C15.244,2.329 15.234,2.681 15.654,2.984L18.115,4.78C18.662,5.181 19.209,5.015 19.209,4.312ZM18.184,1.929C17.871,1.929 17.617,2.183 17.617,2.486C17.617,2.798 17.871,3.062 18.184,3.062L19.404,3.062C21.523,3.062 22.861,4.527 22.861,6.607L22.861,8.071C22.861,8.403 23.135,8.677 23.467,8.677C23.799,8.677 24.082,8.403 24.082,8.071L24.082,6.607C24.082,3.814 22.217,1.929 19.414,1.929Z"
17
+ android:fillColor="#ffffff"
18
+ android:fillAlpha="0.85"/>
19
+ </vector>
@@ -3,39 +3,130 @@
3
3
  android:layout_width="match_parent"
4
4
  android:layout_height="match_parent"
5
5
  android:orientation="vertical">
6
+
6
7
  <FrameLayout
7
8
  android:id="@+id/headerView"
8
9
  android:layout_width="match_parent"
9
10
  android:layout_height="wrap_content"
10
- android:minHeight="50dp"
11
11
  android:background="@android:color/black"
12
- android:visibility="gone"
13
- >
14
- <TextView
15
- android:id="@+id/headerText"
16
- android:layout_width="wrap_content"
17
- android:layout_height="match_parent"
12
+ android:visibility="gone">
13
+
14
+ <HorizontalScrollView
15
+ android:layout_width="match_parent"
16
+ android:layout_height="wrap_content"
18
17
  android:layout_gravity="center"
19
- android:clickable="true"
20
- android:focusable="true"
21
- android:text="Header text"
22
- android:textColor="@android:color/white"
23
- android:textSize="16dp" />
18
+ android:scrollbars="none"
19
+ android:fillViewport="true"
20
+ android:paddingTop="6dp"
21
+ android:paddingBottom="2dp">
22
+
23
+ <TextView
24
+ android:id="@+id/headerText"
25
+ android:layout_width="wrap_content"
26
+ android:layout_height="wrap_content"
27
+ android:gravity="center"
28
+ android:singleLine="true"
29
+ android:text=""
30
+ android:textColor="@android:color/white"
31
+ android:textSize="16dp"
32
+ android:paddingHorizontal="16dp" />
33
+ </HorizontalScrollView>
24
34
  </FrameLayout>
25
35
 
26
- <RelativeLayout
36
+ <LinearLayout
37
+ android:id="@+id/transformRow"
38
+ android:layout_width="match_parent"
39
+ android:layout_height="wrap_content"
40
+ android:layout_below="@+id/headerView"
41
+ android:orientation="horizontal"
42
+ android:paddingHorizontal="16dp"
43
+ android:paddingVertical="4dp"
44
+ android:background="@android:color/black"
45
+ android:gravity="center_vertical"
46
+ android:visibility="gone">
47
+
48
+ <LinearLayout
49
+ android:layout_width="wrap_content"
50
+ android:layout_height="wrap_content"
51
+ android:orientation="horizontal"
52
+ android:gravity="center_vertical">
53
+
54
+ <ImageView
55
+ android:id="@+id/flipBtn"
56
+ android:layout_width="22dp"
57
+ android:layout_height="22dp"
58
+ android:src="@drawable/arrow_trianglehead_left_and_right_righttriangle_left_righttriangle_right"
59
+ android:tint="@android:color/white"
60
+ android:scaleType="fitCenter"
61
+ android:layout_marginEnd="12dp"
62
+ android:contentDescription="Flip" />
63
+
64
+ <ImageView
65
+ android:id="@+id/rotateBtn"
66
+ android:layout_width="22dp"
67
+ android:layout_height="22dp"
68
+ android:src="@drawable/rotate_left"
69
+ android:tint="@android:color/white"
70
+ android:scaleType="fitCenter"
71
+ android:layout_marginEnd="12dp"
72
+ android:contentDescription="Rotate" />
73
+
74
+ <ImageView
75
+ android:id="@+id/cropBtn"
76
+ android:layout_width="22dp"
77
+ android:layout_height="22dp"
78
+ android:src="@drawable/crop"
79
+ android:tint="#80FFFFFF"
80
+ android:scaleType="fitCenter"
81
+ android:contentDescription="Crop" />
82
+ </LinearLayout>
83
+
84
+ <View
85
+ android:layout_width="0dp"
86
+ android:layout_height="0dp"
87
+ android:layout_weight="1" />
88
+
89
+ <LinearLayout
90
+ android:layout_width="wrap_content"
91
+ android:layout_height="wrap_content"
92
+ android:orientation="horizontal"
93
+ android:gravity="center_vertical">
94
+
95
+ <ImageView
96
+ android:id="@+id/undoBtn"
97
+ android:layout_width="22dp"
98
+ android:layout_height="22dp"
99
+ android:src="@drawable/arrow_uturn_backward"
100
+ android:tint="#80FFFFFF"
101
+ android:scaleType="fitCenter"
102
+ android:layout_marginEnd="12dp"
103
+ android:contentDescription="Undo" />
104
+
105
+ <ImageView
106
+ android:id="@+id/redoBtn"
107
+ android:layout_width="22dp"
108
+ android:layout_height="22dp"
109
+ android:src="@drawable/arrow_uturn_forward"
110
+ android:tint="#80FFFFFF"
111
+ android:scaleType="fitCenter"
112
+ android:contentDescription="Redo" />
113
+ </LinearLayout>
114
+ </LinearLayout>
115
+
116
+ <FrameLayout
117
+ android:id="@+id/videoContainer"
27
118
  android:layout_width="match_parent"
28
119
  android:layout_height="match_parent"
29
120
  android:layout_above="@+id/layout"
30
- android:layout_below="@+id/headerView"
121
+ android:layout_below="@+id/transformRow"
31
122
  android:background="@android:color/black"
32
- android:gravity="center">
123
+ android:clipChildren="true">
33
124
 
34
- <VideoView
125
+ <TextureView
35
126
  android:id="@+id/video_loader"
36
127
  android:layout_width="match_parent"
37
128
  android:layout_height="match_parent"
38
- />
129
+ android:layout_gravity="center" />
39
130
 
40
131
  <FrameLayout
41
132
  android:id="@+id/audioBannerView"
@@ -53,11 +144,9 @@
53
144
  android:layout_height="match_parent"
54
145
  android:layout_gravity="center"
55
146
  android:contentDescription="Airpods Max"
56
- android:src="@drawable/airpodsmax"
57
- />
147
+ android:src="@drawable/airpodsmax" />
58
148
  </FrameLayout>
59
-
60
- </RelativeLayout>
149
+ </FrameLayout>
61
150
 
62
151
  <RelativeLayout
63
152
  android:id="@+id/layout"
@@ -66,7 +155,6 @@
66
155
  android:layout_alignParentBottom="true"
67
156
  android:background="@android:color/black">
68
157
 
69
-
70
158
  <RelativeLayout
71
159
  android:id="@+id/trimmerView"
72
160
  android:layout_width="match_parent"
@@ -79,8 +167,7 @@
79
167
  android:layout_height="match_parent"
80
168
  android:layout_marginHorizontal="20dp"
81
169
  android:orientation="horizontal"
82
- android:padding="4dp"
83
- />
170
+ android:padding="4dp" />
84
171
 
85
172
  <RelativeLayout
86
173
  android:id="@+id/trimmerContainerWrapper"
@@ -161,9 +248,7 @@
161
248
  android:contentDescription="TrailingHandle"
162
249
  android:src="@drawable/chevron_compact_right" />
163
250
  </FrameLayout>
164
-
165
251
  </RelativeLayout>
166
-
167
252
  </RelativeLayout>
168
253
 
169
254
  <FrameLayout
@@ -213,7 +298,6 @@
213
298
  android:text="00:00.00"
214
299
  android:textColor="@android:color/white"
215
300
  android:textSize="16sp" />
216
-
217
301
  </FrameLayout>
218
302
 
219
303
  <FrameLayout
@@ -244,8 +328,7 @@
244
328
  android:padding="12dp"
245
329
  android:src="@drawable/play_fill"
246
330
  android:tint="@color/white"
247
- android:visibility="gone"
248
- />
331
+ android:visibility="gone" />
249
332
 
250
333
  <ImageView
251
334
  android:id="@+id/failToLoadBtn"
@@ -255,8 +338,7 @@
255
338
  android:padding="12dp"
256
339
  android:src="@drawable/exclamationmark_triangle_fill"
257
340
  android:tint="@color/trim_color"
258
- android:visibility="gone"
259
- />
341
+ android:visibility="gone" />
260
342
 
261
343
  <ProgressBar
262
344
  android:id="@+id/loadingIndicator"
@@ -265,8 +347,7 @@
265
347
  android:layout_height="wrap_content"
266
348
  android:layout_gravity="center"
267
349
  android:padding="10dp"
268
- android:indeterminateTint="@color/white"
269
- />
350
+ android:indeterminateTint="@color/white" />
270
351
 
271
352
  <TextView
272
353
  android:id="@+id/saveBtn"
@@ -278,10 +359,7 @@
278
359
  android:text="@string/save"
279
360
  android:textColor="#2196F3"
280
361
  android:textSize="16dp"
281
- android:visibility="gone"
282
- />
283
-
362
+ android:visibility="gone" />
284
363
  </FrameLayout>
285
-
286
364
  </RelativeLayout>
287
365
  </RelativeLayout>
@@ -0,0 +1,285 @@
1
+ import UIKit
2
+
3
+ @available(iOS 13.0, *)
4
+ class CropOverlayView: UIView {
5
+
6
+ var cropRect: CGRect = .zero {
7
+ didSet {
8
+ setNeedsDisplay()
9
+ updateDimmingMask()
10
+ }
11
+ }
12
+
13
+ var allowedRect: CGRect = .zero {
14
+ didSet {
15
+ if cropRect.isEmpty {
16
+ cropRect = allowedRect
17
+ } else {
18
+ let clamped = cropRect.intersection(allowedRect)
19
+ if clamped.isEmpty || clamped.width < minCropSize || clamped.height < minCropSize {
20
+ cropRect = allowedRect
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ var onCropChanged: (() -> Void)?
27
+ var onCropBegan: (() -> Void)?
28
+ var onCropEnded: (() -> Void)?
29
+
30
+ private let minCropSize: CGFloat = 60
31
+ private let borderWidth: CGFloat = 1.0
32
+ private let cornerLength: CGFloat = 20
33
+ private let cornerWidth: CGFloat = 4.0
34
+ private let gridLineWidth: CGFloat = CGFloat(1.0 / UIScreen.main.scale)
35
+ private let edgeHitZone: CGFloat = 30
36
+
37
+ private var activeEdge: DragEdge?
38
+ private var dragStart: CGPoint = .zero
39
+ private var dragStartRect: CGRect = .zero
40
+
41
+ private let dimmingLayer = CAShapeLayer()
42
+
43
+ private enum DragEdge {
44
+ case top, bottom, left, right
45
+ case topLeft, topRight, bottomLeft, bottomRight
46
+ case move
47
+ }
48
+
49
+ override init(frame: CGRect) {
50
+ super.init(frame: frame)
51
+ commonInit()
52
+ }
53
+
54
+ required init?(coder: NSCoder) {
55
+ super.init(coder: coder)
56
+ commonInit()
57
+ }
58
+
59
+ private func commonInit() {
60
+ backgroundColor = .clear
61
+ isUserInteractionEnabled = true
62
+ clipsToBounds = true
63
+ isOpaque = false
64
+
65
+ dimmingLayer.fillRule = .evenOdd
66
+ dimmingLayer.fillColor = UIColor.black.withAlphaComponent(0.55).cgColor
67
+ layer.addSublayer(dimmingLayer)
68
+
69
+ let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
70
+ addGestureRecognizer(pan)
71
+
72
+ let pinch = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
73
+ addGestureRecognizer(pinch)
74
+ }
75
+
76
+ override func layoutSubviews() {
77
+ super.layoutSubviews()
78
+ updateDimmingMask()
79
+ }
80
+
81
+ private func updateDimmingMask() {
82
+ let full = UIBezierPath(rect: bounds)
83
+ if !cropRect.isEmpty {
84
+ full.append(UIBezierPath(rect: cropRect))
85
+ }
86
+ dimmingLayer.path = full.cgPath
87
+ dimmingLayer.frame = bounds
88
+ }
89
+
90
+ // MARK: - Drawing
91
+
92
+ override func draw(_ rect: CGRect) {
93
+ guard !cropRect.isEmpty, let ctx = UIGraphicsGetCurrentContext() else { return }
94
+ let cr = cropRect
95
+
96
+ ctx.setStrokeColor(UIColor.white.withAlphaComponent(0.6).cgColor)
97
+ ctx.setLineWidth(borderWidth)
98
+ ctx.stroke(cr)
99
+
100
+ ctx.setLineWidth(gridLineWidth)
101
+ ctx.setStrokeColor(UIColor.white.cgColor)
102
+ for i in 1...2 {
103
+ let x = cr.minX + cr.width * CGFloat(i) / 3
104
+ ctx.move(to: CGPoint(x: x, y: cr.minY))
105
+ ctx.addLine(to: CGPoint(x: x, y: cr.maxY))
106
+ }
107
+ for i in 1...2 {
108
+ let y = cr.minY + cr.height * CGFloat(i) / 3
109
+ ctx.move(to: CGPoint(x: cr.minX, y: y))
110
+ ctx.addLine(to: CGPoint(x: cr.maxX, y: y))
111
+ }
112
+ ctx.strokePath()
113
+
114
+ ctx.setStrokeColor(UIColor.white.cgColor)
115
+ ctx.setLineWidth(cornerWidth)
116
+ ctx.setLineCap(.round)
117
+
118
+ let cl = cornerLength
119
+ let corners: [(CGPoint, CGPoint, CGPoint)] = [
120
+ (CGPoint(x: cr.minX, y: cr.minY + cl),
121
+ CGPoint(x: cr.minX, y: cr.minY),
122
+ CGPoint(x: cr.minX + cl, y: cr.minY)),
123
+ (CGPoint(x: cr.maxX - cl, y: cr.minY),
124
+ CGPoint(x: cr.maxX, y: cr.minY),
125
+ CGPoint(x: cr.maxX, y: cr.minY + cl)),
126
+ (CGPoint(x: cr.minX, y: cr.maxY - cl),
127
+ CGPoint(x: cr.minX, y: cr.maxY),
128
+ CGPoint(x: cr.minX + cl, y: cr.maxY)),
129
+ (CGPoint(x: cr.maxX - cl, y: cr.maxY),
130
+ CGPoint(x: cr.maxX, y: cr.maxY),
131
+ CGPoint(x: cr.maxX, y: cr.maxY - cl)),
132
+ ]
133
+ for (start, corner, end) in corners {
134
+ ctx.move(to: start)
135
+ ctx.addLine(to: corner)
136
+ ctx.addLine(to: end)
137
+ }
138
+ ctx.strokePath()
139
+ }
140
+
141
+ // MARK: - Hit Testing
142
+
143
+ override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
144
+ if detectEdge(at: point) != nil { return self }
145
+ return nil
146
+ }
147
+
148
+ private func detectEdge(at pt: CGPoint) -> DragEdge? {
149
+ let r = cropRect
150
+ let z = edgeHitZone
151
+
152
+ let nearT = abs(pt.y - r.minY) < z
153
+ let nearB = abs(pt.y - r.maxY) < z
154
+ let nearL = abs(pt.x - r.minX) < z
155
+ let nearR = abs(pt.x - r.maxX) < z
156
+ let inH = pt.x > r.minX - z && pt.x < r.maxX + z
157
+ let inV = pt.y > r.minY - z && pt.y < r.maxY + z
158
+
159
+ if nearT && nearL { return .topLeft }
160
+ if nearT && nearR { return .topRight }
161
+ if nearB && nearL { return .bottomLeft }
162
+ if nearB && nearR { return .bottomRight }
163
+ if nearT && inH { return .top }
164
+ if nearB && inH { return .bottom }
165
+ if nearL && inV { return .left }
166
+ if nearR && inV { return .right }
167
+ if r.contains(pt) { return .move }
168
+ return nil
169
+ }
170
+
171
+ // MARK: - Gestures
172
+
173
+ @objc private func handlePan(_ g: UIPanGestureRecognizer) {
174
+ let pt = g.location(in: self)
175
+ switch g.state {
176
+ case .began:
177
+ activeEdge = detectEdge(at: pt)
178
+ dragStart = pt
179
+ dragStartRect = cropRect
180
+ onCropBegan?()
181
+ case .changed:
182
+ guard let edge = activeEdge else { return }
183
+ let dx = pt.x - dragStart.x
184
+ let dy = pt.y - dragStart.y
185
+ cropRect = computeNewRect(edge: edge, dx: dx, dy: dy)
186
+ onCropChanged?()
187
+ case .ended, .cancelled:
188
+ activeEdge = nil
189
+ onCropEnded?()
190
+ default:
191
+ break
192
+ }
193
+ }
194
+
195
+ @objc private func handlePinch(_ g: UIPinchGestureRecognizer) {
196
+ switch g.state {
197
+ case .began:
198
+ dragStartRect = cropRect
199
+ onCropBegan?()
200
+ case .changed:
201
+ let scale = g.scale
202
+ let cx = dragStartRect.midX
203
+ let cy = dragStartRect.midY
204
+ var newW = max(dragStartRect.width * scale, minCropSize)
205
+ var newH = max(dragStartRect.height * scale, minCropSize)
206
+ newW = min(newW, allowedRect.width)
207
+ newH = min(newH, allowedRect.height)
208
+ var r = CGRect(x: cx - newW / 2, y: cy - newH / 2, width: newW, height: newH)
209
+ r = clamp(r, isMove: true)
210
+ cropRect = r
211
+ onCropChanged?()
212
+ case .ended, .cancelled:
213
+ onCropEnded?()
214
+ default:
215
+ break
216
+ }
217
+ }
218
+
219
+ // MARK: - Rect Computation
220
+
221
+ private func computeNewRect(edge: DragEdge, dx: CGFloat, dy: CGFloat) -> CGRect {
222
+ var r = dragStartRect
223
+
224
+ switch edge {
225
+ case .topLeft:
226
+ r.origin.x += dx; r.size.width -= dx
227
+ r.origin.y += dy; r.size.height -= dy
228
+ case .topRight:
229
+ r.size.width += dx
230
+ r.origin.y += dy; r.size.height -= dy
231
+ case .bottomLeft:
232
+ r.origin.x += dx; r.size.width -= dx
233
+ r.size.height += dy
234
+ case .bottomRight:
235
+ r.size.width += dx; r.size.height += dy
236
+ case .top:
237
+ r.origin.y += dy; r.size.height -= dy
238
+ case .bottom:
239
+ r.size.height += dy
240
+ case .left:
241
+ r.origin.x += dx; r.size.width -= dx
242
+ case .right:
243
+ r.size.width += dx
244
+ case .move:
245
+ r.origin.x += dx; r.origin.y += dy
246
+ return clamp(r, isMove: true)
247
+ }
248
+
249
+ if r.width < minCropSize {
250
+ let anchorsRight = (edge == .left || edge == .topLeft || edge == .bottomLeft)
251
+ if anchorsRight { r.origin.x = dragStartRect.maxX - minCropSize }
252
+ r.size.width = minCropSize
253
+ }
254
+ if r.height < minCropSize {
255
+ let anchorsBottom = (edge == .top || edge == .topLeft || edge == .topRight)
256
+ if anchorsBottom { r.origin.y = dragStartRect.maxY - minCropSize }
257
+ r.size.height = minCropSize
258
+ }
259
+
260
+ return clamp(r, isMove: false)
261
+ }
262
+
263
+ private func clamp(_ rect: CGRect, isMove: Bool) -> CGRect {
264
+ var r = rect
265
+ let a = allowedRect
266
+ guard !a.isEmpty else { return r }
267
+
268
+ if isMove {
269
+ r.size.width = min(r.width, a.width)
270
+ r.size.height = min(r.height, a.height)
271
+ r.origin.x = max(a.minX, min(r.origin.x, a.maxX - r.width))
272
+ r.origin.y = max(a.minY, min(r.origin.y, a.maxY - r.height))
273
+ } else {
274
+ r.origin.x = max(r.origin.x, a.minX)
275
+ r.origin.y = max(r.origin.y, a.minY)
276
+ if r.maxX > a.maxX { r.size.width = a.maxX - r.origin.x }
277
+ if r.maxY > a.maxY { r.size.height = a.maxY - r.origin.y }
278
+ }
279
+ return r
280
+ }
281
+
282
+ func resetCrop() {
283
+ cropRect = allowedRect
284
+ }
285
+ }
package/ios/VideoTrim.mm CHANGED
@@ -70,10 +70,9 @@ RCT_EXPORT_MODULE()
70
70
  dict[@"outputExt"] = options.outputExt();
71
71
  dict[@"removeAfterSavedToPhoto"] = @(options.removeAfterSavedToPhoto());
72
72
  dict[@"removeAfterFailedToSavePhoto"] = @(options.removeAfterFailedToSavePhoto());
73
- dict[@"enableRotation"] = @(options.enableRotation());
74
- dict[@"rotationAngle"] = @(options.rotationAngle());
75
73
  dict[@"startTime"] = @(options.startTime());
76
74
  dict[@"endTime"] = @(options.endTime());
75
+ dict[@"enablePreciseTrimming"] = @(options.enablePreciseTrimming());
77
76
 
78
77
  [self->videoTrim trim:url url:dict config:^(NSDictionary<NSString *,id> * _Nonnull result) {
79
78
  BOOL success = [result[@"success"] boolValue];
@@ -109,8 +108,6 @@ RCT_EXPORT_MODULE()
109
108
  dict[@"removeAfterFailedToSaveDocuments"] = @(config.removeAfterFailedToSaveDocuments());
110
109
  dict[@"removeAfterShared"] = @(config.removeAfterShared());
111
110
  dict[@"removeAfterFailedToShare"] = @(config.removeAfterFailedToShare());
112
- dict[@"enableRotation"] = @(config.enableRotation());
113
- dict[@"rotationAngle"] = @(config.rotationAngle());
114
111
  dict[@"enableHapticFeedback"] = @(config.enableHapticFeedback());
115
112
  dict[@"maxDuration"] = @(config.maxDuration());
116
113
  dict[@"minDuration"] = @(config.minDuration());
@@ -145,6 +142,7 @@ RCT_EXPORT_MODULE()
145
142
  dict[@"alertOnFailTitle"] = config.alertOnFailTitle();
146
143
  dict[@"alertOnFailMessage"] = config.alertOnFailMessage();
147
144
  dict[@"alertOnFailCloseText"] = config.alertOnFailCloseText();
145
+ dict[@"enablePreciseTrimming"] = @(config.enablePreciseTrimming());
148
146
 
149
147
  // Handle optional color values
150
148
  auto trimmerColorOpt = config.trimmerColor();