@technotoil/image-video-editor 0.1.1 → 0.1.3
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/README.md +17 -3
- package/android/src/main/java/com/technotoil/image_videoeditor/FrameGrabberModule.kt +2 -6
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaEditorModule.kt +103 -37
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaLibraryModule.kt +51 -35
- package/android/src/main/java/com/technotoil/image_videoeditor/RNVideoPreviewManager.kt +98 -117
- package/ios/RNMediaEditor.m +38 -7
- package/ios/RNMediaLibrary.m +19 -15
- package/ios/RNVideoPreviewManager.m +2 -0
- package/lib/commonjs/components/Icon.js +31 -0
- package/lib/commonjs/components/Icon.js.map +1 -0
- package/lib/commonjs/components/VideoEditor.js +97 -32
- package/lib/commonjs/components/VideoEditor.js.map +1 -1
- package/lib/commonjs/icons.js +35 -0
- package/lib/commonjs/icons.js.map +1 -0
- package/lib/commonjs/screens/CropScreen.js +5 -3
- package/lib/commonjs/screens/CropScreen.js.map +1 -1
- package/lib/commonjs/screens/EditorScreen.js +269 -84
- package/lib/commonjs/screens/EditorScreen.js.map +1 -1
- package/lib/commonjs/screens/PickScreen.js +221 -129
- package/lib/commonjs/screens/PickScreen.js.map +1 -1
- package/lib/module/components/Icon.js +25 -0
- package/lib/module/components/Icon.js.map +1 -0
- package/lib/module/components/VideoEditor.js +98 -33
- package/lib/module/components/VideoEditor.js.map +1 -1
- package/lib/module/icons.js +31 -0
- package/lib/module/icons.js.map +1 -0
- package/lib/module/screens/CropScreen.js +5 -3
- package/lib/module/screens/CropScreen.js.map +1 -1
- package/lib/module/screens/EditorScreen.js +230 -45
- package/lib/module/screens/EditorScreen.js.map +1 -1
- package/lib/module/screens/PickScreen.js +216 -124
- package/lib/module/screens/PickScreen.js.map +1 -1
- package/lib/typescript/src/components/Icon.d.ts +11 -0
- package/lib/typescript/src/components/VideoEditor.d.ts +10 -2
- package/lib/typescript/src/icons.d.ts +28 -0
- package/lib/typescript/src/screens/CropScreen.d.ts +2 -1
- package/lib/typescript/src/screens/EditorScreen.d.ts +2 -1
- package/lib/typescript/src/screens/PickScreen.d.ts +4 -1
- package/lib/typescript/src/types.d.ts +1 -0
- package/package.json +4 -4
- package/src/components/Icon.tsx +19 -0
- package/src/components/VideoEditor.tsx +67 -11
- package/src/icons.ts +28 -0
- package/src/screens/CropScreen.tsx +8 -3
- package/src/screens/EditorScreen.tsx +228 -62
- package/src/screens/PickScreen.tsx +198 -120
- package/src/types.ts +1 -0
|
@@ -11,7 +11,7 @@ var _FrameGrabber = require("../native/FrameGrabber");
|
|
|
11
11
|
var _MediaLibrary = require("../native/MediaLibrary");
|
|
12
12
|
var _VideoPreview = require("../native/VideoPreview");
|
|
13
13
|
var _reactNativeVideo = _interopRequireDefault(require("react-native-video"));
|
|
14
|
-
var
|
|
14
|
+
var _Icon = require("../components/Icon");
|
|
15
15
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
16
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
17
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
@@ -174,12 +174,16 @@ function EditorScreen({
|
|
|
174
174
|
onBack,
|
|
175
175
|
onSaved,
|
|
176
176
|
onOpenCrop,
|
|
177
|
-
musicList
|
|
177
|
+
musicList,
|
|
178
|
+
maxVideoDurationMs
|
|
178
179
|
}) {
|
|
179
180
|
const [activeIndex, setActiveIndex] = (0, _react.useState)(initialIndex);
|
|
180
181
|
const currentItem = items[activeIndex] || items[0];
|
|
181
182
|
const item = currentItem; // Aliasing to 'item' for ease of compatibility
|
|
182
183
|
|
|
184
|
+
(0, _react.useEffect)(() => {
|
|
185
|
+
setActiveIndex(initialIndex);
|
|
186
|
+
}, [initialIndex]);
|
|
183
187
|
const [activeFilter, setActiveFilter] = (0, _react.useState)('none');
|
|
184
188
|
const [imageOptions, setImageOptions] = (0, _react.useState)({
|
|
185
189
|
rotateDegrees: 0,
|
|
@@ -190,13 +194,21 @@ function EditorScreen({
|
|
|
190
194
|
saturation: 1,
|
|
191
195
|
grayscale: false
|
|
192
196
|
});
|
|
197
|
+
const [panel, setPanel] = (0, _react.useState)(item.type === 'video' ? 'trim' : 'filter');
|
|
193
198
|
const [trimStart, setTrimStart] = (0, _react.useState)(0);
|
|
194
|
-
const [trimEnd, setTrimEnd] = (0, _react.useState)(
|
|
199
|
+
const [trimEnd, setTrimEnd] = (0, _react.useState)(() => {
|
|
200
|
+
const end = item.durationMs || 10000;
|
|
201
|
+
return maxVideoDurationMs ? Math.min(end, maxVideoDurationMs) : end;
|
|
202
|
+
});
|
|
195
203
|
(0, _react.useEffect)(() => {
|
|
196
204
|
setTrimStart(0);
|
|
197
|
-
|
|
205
|
+
const end = item.durationMs || maxVideoDurationMs || 10000;
|
|
206
|
+
setTrimEnd(maxVideoDurationMs ? Math.min(end, maxVideoDurationMs) : end);
|
|
198
207
|
setThumbnails([]);
|
|
199
|
-
|
|
208
|
+
if (item.type === 'video' && maxVideoDurationMs && end > maxVideoDurationMs) {
|
|
209
|
+
setPanel('trim');
|
|
210
|
+
}
|
|
211
|
+
}, [item.id, item.durationMs, maxVideoDurationMs]);
|
|
200
212
|
const [editsHistory, setEditsHistory] = (0, _react.useState)({});
|
|
201
213
|
const editsHistoryRef = (0, _react.useRef)({});
|
|
202
214
|
const [dimensionsMap, setDimensionsMap] = (0, _react.useState)({});
|
|
@@ -253,7 +265,7 @@ function EditorScreen({
|
|
|
253
265
|
setCropOffset(saved.cropOffset);
|
|
254
266
|
setZoomScale(saved.zoomScale);
|
|
255
267
|
setStraightenAngle(saved.straightenAngle);
|
|
256
|
-
setIsMuted(saved.isMuted);
|
|
268
|
+
setIsMuted(selectedMusic ? true : saved.isMuted);
|
|
257
269
|
} else {
|
|
258
270
|
setActiveFilter('none');
|
|
259
271
|
setImageOptions({
|
|
@@ -266,7 +278,8 @@ function EditorScreen({
|
|
|
266
278
|
grayscale: false
|
|
267
279
|
});
|
|
268
280
|
setTrimStart(0);
|
|
269
|
-
|
|
281
|
+
const end = targetItem.durationMs || 10000;
|
|
282
|
+
setTrimEnd(maxVideoDurationMs ? Math.min(end, maxVideoDurationMs) : end);
|
|
270
283
|
setOverlays([]);
|
|
271
284
|
setCropRatio(null);
|
|
272
285
|
setCropOffset({
|
|
@@ -275,7 +288,14 @@ function EditorScreen({
|
|
|
275
288
|
});
|
|
276
289
|
setZoomScale(1);
|
|
277
290
|
setStraightenAngle(0);
|
|
278
|
-
setIsMuted(false);
|
|
291
|
+
setIsMuted(selectedMusic ? true : false);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Force trim panel if video is too long
|
|
295
|
+
if (targetItem.type === 'video' && maxVideoDurationMs && targetItem.durationMs && targetItem.durationMs > maxVideoDurationMs) {
|
|
296
|
+
setPanel('trim');
|
|
297
|
+
} else if (!saved) {
|
|
298
|
+
setPanel(targetItem.type === 'video' ? 'trim' : 'filter');
|
|
279
299
|
}
|
|
280
300
|
};
|
|
281
301
|
const handleScrollEnd = e => {
|
|
@@ -334,13 +354,13 @@ function EditorScreen({
|
|
|
334
354
|
y: (o.y + 8) * renderScale,
|
|
335
355
|
color: o.color,
|
|
336
356
|
fontSize: o.fontSize * renderScale
|
|
337
|
-
}))
|
|
357
|
+
})),
|
|
358
|
+
frameUri: edits.imageOptions.frame && FRAME_IMAGES[edits.imageOptions.frame] ? _reactNative.Image.resolveAssetSource(FRAME_IMAGES[edits.imageOptions.frame]).uri : undefined
|
|
338
359
|
};
|
|
339
360
|
};
|
|
340
361
|
const [saving, setSaving] = (0, _react.useState)(false);
|
|
341
362
|
const [videoPaused, setVideoPaused] = (0, _react.useState)(false);
|
|
342
|
-
const
|
|
343
|
-
const resolvedMusicList = musicList || DUMMY_MUSIC_LIST;
|
|
363
|
+
const resolvedMusicList = musicList || [];
|
|
344
364
|
const [selectedMusic, setSelectedMusic] = (0, _react.useState)(null);
|
|
345
365
|
const [musicPaused, setMusicPaused] = (0, _react.useState)(false);
|
|
346
366
|
const [showMusicModal, setShowMusicModal] = (0, _react.useState)(false);
|
|
@@ -1119,13 +1139,18 @@ function EditorScreen({
|
|
|
1119
1139
|
y: (o.y + 8) * renderScale,
|
|
1120
1140
|
color: o.color,
|
|
1121
1141
|
fontSize: o.fontSize * renderScale
|
|
1122
|
-
}))
|
|
1142
|
+
})),
|
|
1143
|
+
frameUri: imageOptions.frame && FRAME_IMAGES[imageOptions.frame] ? _reactNative.Image.resolveAssetSource(FRAME_IMAGES[imageOptions.frame]).uri : undefined
|
|
1123
1144
|
};
|
|
1124
1145
|
}, [imageOptions, cropOffset, maxPan, dimensions, cropRatio, straightenAngle, overlays]);
|
|
1125
1146
|
|
|
1126
1147
|
// For visual trim
|
|
1127
1148
|
|
|
1128
1149
|
const duration = item.durationMs ?? 10_000;
|
|
1150
|
+
const durationRef = (0, _react.useRef)(duration);
|
|
1151
|
+
(0, _react.useEffect)(() => {
|
|
1152
|
+
durationRef.current = duration;
|
|
1153
|
+
}, [duration]);
|
|
1129
1154
|
const formatTime = ms => {
|
|
1130
1155
|
const totalSec = Math.floor(ms / 1000);
|
|
1131
1156
|
const mins = Math.floor(totalSec / 60);
|
|
@@ -1187,6 +1212,39 @@ function EditorScreen({
|
|
|
1187
1212
|
generateThumbs();
|
|
1188
1213
|
}
|
|
1189
1214
|
}, [item.type, item.uri, duration, thumbnails.length]);
|
|
1215
|
+
const leftOverlayRef = (0, _react.useRef)(null);
|
|
1216
|
+
const rightOverlayRef = (0, _react.useRef)(null);
|
|
1217
|
+
const selectionRangeRef = (0, _react.useRef)(null);
|
|
1218
|
+
const leftHandleRef = (0, _react.useRef)(null);
|
|
1219
|
+
const rightHandleRef = (0, _react.useRef)(null);
|
|
1220
|
+
const updateNativeRefs = (newStartX, newEndX) => {
|
|
1221
|
+
leftOverlayRef.current?.setNativeProps({
|
|
1222
|
+
style: {
|
|
1223
|
+
width: newStartX
|
|
1224
|
+
}
|
|
1225
|
+
});
|
|
1226
|
+
rightOverlayRef.current?.setNativeProps({
|
|
1227
|
+
style: {
|
|
1228
|
+
left: newEndX
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
selectionRangeRef.current?.setNativeProps({
|
|
1232
|
+
style: {
|
|
1233
|
+
left: newStartX,
|
|
1234
|
+
width: newEndX - newStartX
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
leftHandleRef.current?.setNativeProps({
|
|
1238
|
+
style: {
|
|
1239
|
+
left: newStartX - 16
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
rightHandleRef.current?.setNativeProps({
|
|
1243
|
+
style: {
|
|
1244
|
+
left: newEndX - 16
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
};
|
|
1190
1248
|
const startPanOffset = (0, _react.useRef)(0);
|
|
1191
1249
|
const startPan = (0, _react.useRef)(_reactNative.PanResponder.create({
|
|
1192
1250
|
onStartShouldSetPanResponder: () => true,
|
|
@@ -1200,20 +1258,76 @@ function EditorScreen({
|
|
|
1200
1258
|
setScrollEnabled(false);
|
|
1201
1259
|
},
|
|
1202
1260
|
onPanResponderMove: (_, gesture) => {
|
|
1203
|
-
|
|
1261
|
+
let newX = Math.max(0, Math.min(endX.current - 32, startPanOffset.current + gesture.dx));
|
|
1262
|
+
let newTime = newX / TIMELINE_WIDTH * durationRef.current;
|
|
1263
|
+
const currentTrimEnd = endX.current / TIMELINE_WIDTH * durationRef.current;
|
|
1264
|
+
if (maxVideoDurationMs && currentTrimEnd - newTime > maxVideoDurationMs) {
|
|
1265
|
+
newTime = currentTrimEnd - maxVideoDurationMs;
|
|
1266
|
+
newX = newTime / durationRef.current * TIMELINE_WIDTH;
|
|
1267
|
+
}
|
|
1204
1268
|
startX.current = newX;
|
|
1205
|
-
|
|
1206
|
-
setTrimStart(newTime);
|
|
1269
|
+
updateNativeRefs(newX, endX.current);
|
|
1207
1270
|
throttledSeek(newTime);
|
|
1208
1271
|
},
|
|
1209
1272
|
onPanResponderRelease: () => {
|
|
1210
1273
|
isDraggingHandle.current = false;
|
|
1211
1274
|
setScrollEnabled(true);
|
|
1275
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1276
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1212
1277
|
setSeekToMs(-1);
|
|
1213
1278
|
},
|
|
1214
1279
|
onPanResponderTerminate: () => {
|
|
1215
1280
|
isDraggingHandle.current = false;
|
|
1216
1281
|
setScrollEnabled(true);
|
|
1282
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1283
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1284
|
+
setSeekToMs(-1);
|
|
1285
|
+
}
|
|
1286
|
+
})).current;
|
|
1287
|
+
const middlePanOffsetStart = (0, _react.useRef)(0);
|
|
1288
|
+
const middlePanOffsetEnd = (0, _react.useRef)(0);
|
|
1289
|
+
const middlePan = (0, _react.useRef)(_reactNative.PanResponder.create({
|
|
1290
|
+
onStartShouldSetPanResponder: () => true,
|
|
1291
|
+
onStartShouldSetPanResponderCapture: () => true,
|
|
1292
|
+
onMoveShouldSetPanResponder: () => true,
|
|
1293
|
+
onMoveShouldSetPanResponderCapture: () => true,
|
|
1294
|
+
onPanResponderGrant: () => {
|
|
1295
|
+
pushToHistory();
|
|
1296
|
+
middlePanOffsetStart.current = startX.current;
|
|
1297
|
+
middlePanOffsetEnd.current = endX.current;
|
|
1298
|
+
isDraggingHandle.current = true;
|
|
1299
|
+
setScrollEnabled(false);
|
|
1300
|
+
},
|
|
1301
|
+
onPanResponderMove: (_, gesture) => {
|
|
1302
|
+
const windowWidth = middlePanOffsetEnd.current - middlePanOffsetStart.current;
|
|
1303
|
+
let newStartX = middlePanOffsetStart.current + gesture.dx;
|
|
1304
|
+
let newEndX = middlePanOffsetEnd.current + gesture.dx;
|
|
1305
|
+
if (newStartX < 0) {
|
|
1306
|
+
newStartX = 0;
|
|
1307
|
+
newEndX = windowWidth;
|
|
1308
|
+
}
|
|
1309
|
+
if (newEndX > TIMELINE_WIDTH) {
|
|
1310
|
+
newEndX = TIMELINE_WIDTH;
|
|
1311
|
+
newStartX = TIMELINE_WIDTH - windowWidth;
|
|
1312
|
+
}
|
|
1313
|
+
startX.current = newStartX;
|
|
1314
|
+
endX.current = newEndX;
|
|
1315
|
+
const newStartTime = newStartX / TIMELINE_WIDTH * durationRef.current;
|
|
1316
|
+
updateNativeRefs(newStartX, newEndX);
|
|
1317
|
+
throttledSeek(newStartTime);
|
|
1318
|
+
},
|
|
1319
|
+
onPanResponderRelease: () => {
|
|
1320
|
+
isDraggingHandle.current = false;
|
|
1321
|
+
setScrollEnabled(true);
|
|
1322
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1323
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1324
|
+
setSeekToMs(-1);
|
|
1325
|
+
},
|
|
1326
|
+
onPanResponderTerminate: () => {
|
|
1327
|
+
isDraggingHandle.current = false;
|
|
1328
|
+
setScrollEnabled(true);
|
|
1329
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1330
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1217
1331
|
setSeekToMs(-1);
|
|
1218
1332
|
}
|
|
1219
1333
|
})).current;
|
|
@@ -1230,20 +1344,29 @@ function EditorScreen({
|
|
|
1230
1344
|
setScrollEnabled(false);
|
|
1231
1345
|
},
|
|
1232
1346
|
onPanResponderMove: (_, gesture) => {
|
|
1233
|
-
|
|
1347
|
+
let newX = Math.min(TIMELINE_WIDTH, Math.max(startX.current + 32, endPanOffset.current + gesture.dx));
|
|
1348
|
+
let newTime = newX / TIMELINE_WIDTH * durationRef.current;
|
|
1349
|
+
const currentTrimStart = startX.current / TIMELINE_WIDTH * durationRef.current;
|
|
1350
|
+
if (maxVideoDurationMs && newTime - currentTrimStart > maxVideoDurationMs) {
|
|
1351
|
+
newTime = currentTrimStart + maxVideoDurationMs;
|
|
1352
|
+
newX = newTime / durationRef.current * TIMELINE_WIDTH;
|
|
1353
|
+
}
|
|
1234
1354
|
endX.current = newX;
|
|
1235
|
-
|
|
1236
|
-
setTrimEnd(newTime);
|
|
1355
|
+
updateNativeRefs(startX.current, newX);
|
|
1237
1356
|
throttledSeek(newTime);
|
|
1238
1357
|
},
|
|
1239
1358
|
onPanResponderRelease: () => {
|
|
1240
1359
|
isDraggingHandle.current = false;
|
|
1241
1360
|
setScrollEnabled(true);
|
|
1361
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1362
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1242
1363
|
setSeekToMs(-1);
|
|
1243
1364
|
},
|
|
1244
1365
|
onPanResponderTerminate: () => {
|
|
1245
1366
|
isDraggingHandle.current = false;
|
|
1246
1367
|
setScrollEnabled(true);
|
|
1368
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1369
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1247
1370
|
setSeekToMs(-1);
|
|
1248
1371
|
}
|
|
1249
1372
|
})).current;
|
|
@@ -2018,11 +2141,16 @@ function EditorScreen({
|
|
|
2018
2141
|
});
|
|
2019
2142
|
}
|
|
2020
2143
|
} else {
|
|
2144
|
+
const safeEndMs = Math.min(trimEnd, item.durationMs || 10000);
|
|
2145
|
+
const safeStartMs = Math.min(trimStart, Math.max(0, safeEndMs - 100));
|
|
2146
|
+
const isFullTrim = trimStart === 0 && trimEnd >= (item.durationMs || 10000);
|
|
2021
2147
|
exportUri = await (0, _MediaEditor.trimVideo)(item.uri, {
|
|
2022
|
-
startMs:
|
|
2023
|
-
endMs:
|
|
2148
|
+
startMs: safeStartMs,
|
|
2149
|
+
endMs: safeEndMs,
|
|
2024
2150
|
mute: isMuted,
|
|
2025
|
-
|
|
2151
|
+
...(selectedMusic?.url ? {
|
|
2152
|
+
musicUri: selectedMusic.url
|
|
2153
|
+
} : {}),
|
|
2026
2154
|
...activeOptions
|
|
2027
2155
|
});
|
|
2028
2156
|
}
|
|
@@ -2039,6 +2167,7 @@ function EditorScreen({
|
|
|
2039
2167
|
setSaving(true);
|
|
2040
2168
|
saveEditsForIndex(activeIndex);
|
|
2041
2169
|
const updatedItems = [...items];
|
|
2170
|
+
let cumulativeMusicOffsetMs = 0;
|
|
2042
2171
|
for (let i = 0; i < items.length; i++) {
|
|
2043
2172
|
const targetItem = items[i];
|
|
2044
2173
|
let edits = editsHistoryRef.current[targetItem.id];
|
|
@@ -2064,6 +2193,7 @@ function EditorScreen({
|
|
|
2064
2193
|
outUri = await (0, _MediaEditor.trimVideo)(outUri, {
|
|
2065
2194
|
isImage: true,
|
|
2066
2195
|
musicUri: selectedMusic.url,
|
|
2196
|
+
musicOffsetMs: cumulativeMusicOffsetMs,
|
|
2067
2197
|
rotateDegrees: 0,
|
|
2068
2198
|
flipX: false,
|
|
2069
2199
|
flipY: false,
|
|
@@ -2078,12 +2208,20 @@ function EditorScreen({
|
|
|
2078
2208
|
uri: outUri,
|
|
2079
2209
|
thumbnailUri: outUri
|
|
2080
2210
|
};
|
|
2211
|
+
cumulativeMusicOffsetMs += 10000; // Images are 10s by default
|
|
2081
2212
|
} else {
|
|
2213
|
+
const originalDuration = targetItem.durationMs || maxVideoDurationMs || 10000;
|
|
2214
|
+
const safeEndMs = Math.min(edits.trimEnd, originalDuration);
|
|
2215
|
+
const safeStartMs = Math.min(edits.trimStart, Math.max(0, safeEndMs - 100));
|
|
2216
|
+
const isFullTrim = edits.trimStart === 0 && edits.trimEnd >= originalDuration;
|
|
2082
2217
|
const outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
|
|
2083
|
-
startMs:
|
|
2084
|
-
endMs:
|
|
2218
|
+
startMs: safeStartMs,
|
|
2219
|
+
endMs: safeEndMs,
|
|
2085
2220
|
mute: edits.isMuted,
|
|
2086
|
-
|
|
2221
|
+
...(selectedMusic?.url ? {
|
|
2222
|
+
musicUri: selectedMusic.url,
|
|
2223
|
+
musicOffsetMs: cumulativeMusicOffsetMs
|
|
2224
|
+
} : {}),
|
|
2087
2225
|
...opts
|
|
2088
2226
|
});
|
|
2089
2227
|
let newThumb = undefined;
|
|
@@ -2101,6 +2239,7 @@ function EditorScreen({
|
|
|
2101
2239
|
thumbnailUri: newThumb ? newThumb : targetItem.thumbnailUri,
|
|
2102
2240
|
durationMs: newDuration
|
|
2103
2241
|
};
|
|
2242
|
+
cumulativeMusicOffsetMs += newDuration;
|
|
2104
2243
|
}
|
|
2105
2244
|
} else {
|
|
2106
2245
|
if (selectedMusic) {
|
|
@@ -2109,6 +2248,7 @@ function EditorScreen({
|
|
|
2109
2248
|
outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
|
|
2110
2249
|
isImage: true,
|
|
2111
2250
|
musicUri: selectedMusic.url,
|
|
2251
|
+
musicOffsetMs: cumulativeMusicOffsetMs,
|
|
2112
2252
|
rotateDegrees: 0,
|
|
2113
2253
|
flipX: false,
|
|
2114
2254
|
flipY: false,
|
|
@@ -2117,12 +2257,17 @@ function EditorScreen({
|
|
|
2117
2257
|
saturation: 1,
|
|
2118
2258
|
grayscale: false
|
|
2119
2259
|
});
|
|
2260
|
+
cumulativeMusicOffsetMs += 10000;
|
|
2120
2261
|
} else {
|
|
2262
|
+
const safeEndMs = targetItem.durationMs || 10000;
|
|
2121
2263
|
outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
|
|
2122
2264
|
startMs: 0,
|
|
2123
|
-
endMs:
|
|
2265
|
+
endMs: safeEndMs,
|
|
2124
2266
|
mute: isMuted,
|
|
2125
|
-
|
|
2267
|
+
...(selectedMusic?.url ? {
|
|
2268
|
+
musicUri: selectedMusic.url,
|
|
2269
|
+
musicOffsetMs: cumulativeMusicOffsetMs
|
|
2270
|
+
} : {}),
|
|
2126
2271
|
rotateDegrees: 0,
|
|
2127
2272
|
flipX: false,
|
|
2128
2273
|
flipY: false,
|
|
@@ -2131,6 +2276,7 @@ function EditorScreen({
|
|
|
2131
2276
|
saturation: 1,
|
|
2132
2277
|
grayscale: false
|
|
2133
2278
|
});
|
|
2279
|
+
cumulativeMusicOffsetMs += safeEndMs;
|
|
2134
2280
|
}
|
|
2135
2281
|
updatedItems[i] = {
|
|
2136
2282
|
...targetItem,
|
|
@@ -2258,7 +2404,7 @@ function EditorScreen({
|
|
|
2258
2404
|
style: styles.previewOverlay,
|
|
2259
2405
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2260
2406
|
style: styles.playPauseCircle,
|
|
2261
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2407
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2262
2408
|
name: "play",
|
|
2263
2409
|
size: 22,
|
|
2264
2410
|
color: "#fff"
|
|
@@ -2382,7 +2528,7 @@ function EditorScreen({
|
|
|
2382
2528
|
}), isActive && cardItem.type === 'image' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
2383
2529
|
style: styles.cropIconBtn,
|
|
2384
2530
|
onPress: () => onOpenCrop(cardItem),
|
|
2385
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2531
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2386
2532
|
name: "crop-outline",
|
|
2387
2533
|
size: 20,
|
|
2388
2534
|
color: "#fff"
|
|
@@ -2417,7 +2563,7 @@ function EditorScreen({
|
|
|
2417
2563
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
2418
2564
|
onPress: () => setIsEditingVideo(false),
|
|
2419
2565
|
style: styles.editModeBackBtn,
|
|
2420
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2566
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2421
2567
|
name: "chevron-down",
|
|
2422
2568
|
size: 22,
|
|
2423
2569
|
color: "#fff"
|
|
@@ -2429,7 +2575,7 @@ function EditorScreen({
|
|
|
2429
2575
|
children: saving ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
|
|
2430
2576
|
size: "small",
|
|
2431
2577
|
color: "#fff"
|
|
2432
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2578
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2433
2579
|
name: "arrow-forward",
|
|
2434
2580
|
size: 20,
|
|
2435
2581
|
color: "#fff"
|
|
@@ -2556,7 +2702,7 @@ function EditorScreen({
|
|
|
2556
2702
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
2557
2703
|
onPress: () => setVideoPaused(!videoPaused),
|
|
2558
2704
|
style: styles.editPlayPauseBtn,
|
|
2559
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2705
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2560
2706
|
name: videoPaused ? 'play' : 'pause',
|
|
2561
2707
|
size: 20,
|
|
2562
2708
|
color: "#fff"
|
|
@@ -2572,7 +2718,7 @@ function EditorScreen({
|
|
|
2572
2718
|
}],
|
|
2573
2719
|
onPress: handleUndo,
|
|
2574
2720
|
disabled: undoStack.length === 0,
|
|
2575
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2721
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2576
2722
|
name: "arrow-undo",
|
|
2577
2723
|
size: 18,
|
|
2578
2724
|
color: "#fff"
|
|
@@ -2583,7 +2729,7 @@ function EditorScreen({
|
|
|
2583
2729
|
}],
|
|
2584
2730
|
onPress: handleRedo,
|
|
2585
2731
|
disabled: redoStack.length === 0,
|
|
2586
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
2732
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2587
2733
|
name: "arrow-redo",
|
|
2588
2734
|
size: 18,
|
|
2589
2735
|
color: "#fff"
|
|
@@ -2672,7 +2818,15 @@ function EditorScreen({
|
|
|
2672
2818
|
},
|
|
2673
2819
|
style: styles.filmstripImage
|
|
2674
2820
|
}, idx)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2675
|
-
style: styles.timelineOverlay
|
|
2821
|
+
style: [styles.timelineOverlay, {
|
|
2822
|
+
left: 0,
|
|
2823
|
+
width: trimStart / duration * TIMELINE_WIDTH
|
|
2824
|
+
}]
|
|
2825
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2826
|
+
style: [styles.timelineOverlay, {
|
|
2827
|
+
left: trimEnd / duration * TIMELINE_WIDTH,
|
|
2828
|
+
right: 0
|
|
2829
|
+
}]
|
|
2676
2830
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2677
2831
|
style: [styles.selectionRange, {
|
|
2678
2832
|
left: trimStart / duration * TIMELINE_WIDTH,
|
|
@@ -2683,20 +2837,18 @@ function EditorScreen({
|
|
|
2683
2837
|
style: [styles.customHandle, styles.customHandleLeft, {
|
|
2684
2838
|
left: trimStart / duration * TIMELINE_WIDTH - 16
|
|
2685
2839
|
}],
|
|
2686
|
-
...startPan.panHandlers,
|
|
2687
2840
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2688
2841
|
style: styles.handleBarLine
|
|
2689
2842
|
})
|
|
2690
2843
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2691
2844
|
style: [styles.customHandle, styles.customHandleRight, {
|
|
2692
|
-
left: trimEnd / duration * TIMELINE_WIDTH
|
|
2845
|
+
left: trimEnd / duration * TIMELINE_WIDTH - 16
|
|
2693
2846
|
}],
|
|
2694
|
-
...endPan.panHandlers,
|
|
2695
2847
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2696
2848
|
style: styles.handleBarLine
|
|
2697
2849
|
})
|
|
2698
2850
|
})]
|
|
2699
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
2851
|
+
}), resolvedMusicList.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
2700
2852
|
style: styles.subTrackRow,
|
|
2701
2853
|
onPress: () => setShowMusicModal(true),
|
|
2702
2854
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -2893,7 +3045,7 @@ function EditorScreen({
|
|
|
2893
3045
|
justifyContent: 'center',
|
|
2894
3046
|
alignItems: 'center'
|
|
2895
3047
|
},
|
|
2896
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3048
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2897
3049
|
name: "close",
|
|
2898
3050
|
size: 20,
|
|
2899
3051
|
color: "#fff"
|
|
@@ -2968,7 +3120,7 @@ function EditorScreen({
|
|
|
2968
3120
|
onPress: addTextOverlay,
|
|
2969
3121
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2970
3122
|
style: styles.toolIconContainer,
|
|
2971
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3123
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2972
3124
|
name: "text",
|
|
2973
3125
|
size: 22,
|
|
2974
3126
|
color: "#fff"
|
|
@@ -2977,12 +3129,12 @@ function EditorScreen({
|
|
|
2977
3129
|
style: styles.toolLabel,
|
|
2978
3130
|
children: "Text"
|
|
2979
3131
|
})]
|
|
2980
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
3132
|
+
}), resolvedMusicList.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
2981
3133
|
style: [styles.toolButton, showMusicModal && styles.toolButtonActive],
|
|
2982
3134
|
onPress: () => setShowMusicModal(true),
|
|
2983
3135
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2984
3136
|
style: styles.toolIconContainer,
|
|
2985
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3137
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
2986
3138
|
name: "musical-notes",
|
|
2987
3139
|
size: 22,
|
|
2988
3140
|
color: "#fff"
|
|
@@ -2996,7 +3148,7 @@ function EditorScreen({
|
|
|
2996
3148
|
onPress: () => setPanel(panel === 'transform' ? 'trim' : 'transform'),
|
|
2997
3149
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
2998
3150
|
style: styles.toolIconContainer,
|
|
2999
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3151
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3000
3152
|
name: "crop",
|
|
3001
3153
|
size: 22,
|
|
3002
3154
|
color: "#fff"
|
|
@@ -3010,7 +3162,7 @@ function EditorScreen({
|
|
|
3010
3162
|
onPress: () => setPanel(panel === 'filter' ? 'trim' : 'filter'),
|
|
3011
3163
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3012
3164
|
style: styles.toolIconContainer,
|
|
3013
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3165
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3014
3166
|
name: "color-palette",
|
|
3015
3167
|
size: 22,
|
|
3016
3168
|
color: "#fff"
|
|
@@ -3024,7 +3176,7 @@ function EditorScreen({
|
|
|
3024
3176
|
onPress: () => setPanel(panel === 'frame' ? 'trim' : 'frame'),
|
|
3025
3177
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3026
3178
|
style: styles.toolIconContainer,
|
|
3027
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3179
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3028
3180
|
name: "images",
|
|
3029
3181
|
size: 22,
|
|
3030
3182
|
color: "#fff"
|
|
@@ -3038,7 +3190,7 @@ function EditorScreen({
|
|
|
3038
3190
|
onPress: () => setPanel(panel === 'edit' ? 'trim' : 'edit'),
|
|
3039
3191
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3040
3192
|
style: styles.toolIconContainer,
|
|
3041
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3193
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3042
3194
|
name: "settings-outline",
|
|
3043
3195
|
size: 22,
|
|
3044
3196
|
color: "#fff"
|
|
@@ -3061,7 +3213,7 @@ function EditorScreen({
|
|
|
3061
3213
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3062
3214
|
onPress: onBack,
|
|
3063
3215
|
style: styles.fullscreenCloseBtn,
|
|
3064
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3216
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3065
3217
|
name: "close",
|
|
3066
3218
|
size: 24,
|
|
3067
3219
|
color: "#fff"
|
|
@@ -3069,7 +3221,7 @@ function EditorScreen({
|
|
|
3069
3221
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3070
3222
|
onPress: () => setIsMuted(!isMuted),
|
|
3071
3223
|
style: styles.fullscreenSoundBtn,
|
|
3072
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3224
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3073
3225
|
name: isMuted ? 'volume-mute' : 'volume-high',
|
|
3074
3226
|
size: 22,
|
|
3075
3227
|
color: "#fff"
|
|
@@ -3139,12 +3291,12 @@ function EditorScreen({
|
|
|
3139
3291
|
contentContainerStyle: [styles.toolButtonsRow, {
|
|
3140
3292
|
flexGrow: 1
|
|
3141
3293
|
}],
|
|
3142
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
3294
|
+
children: [resolvedMusicList.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
3143
3295
|
style: [styles.toolButton, showMusicModal && styles.toolButtonActive],
|
|
3144
3296
|
onPress: () => setShowMusicModal(true),
|
|
3145
3297
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3146
3298
|
style: styles.toolIconContainer,
|
|
3147
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3299
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3148
3300
|
name: "musical-notes",
|
|
3149
3301
|
size: 22,
|
|
3150
3302
|
color: "#fff"
|
|
@@ -3158,7 +3310,7 @@ function EditorScreen({
|
|
|
3158
3310
|
onPress: addTextOverlay,
|
|
3159
3311
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3160
3312
|
style: styles.toolIconContainer,
|
|
3161
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3313
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3162
3314
|
name: "text",
|
|
3163
3315
|
size: 22,
|
|
3164
3316
|
color: "#fff"
|
|
@@ -3175,7 +3327,7 @@ function EditorScreen({
|
|
|
3175
3327
|
},
|
|
3176
3328
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3177
3329
|
style: styles.toolIconContainer,
|
|
3178
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3330
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3179
3331
|
name: "crop",
|
|
3180
3332
|
size: 22,
|
|
3181
3333
|
color: "#fff"
|
|
@@ -3189,7 +3341,7 @@ function EditorScreen({
|
|
|
3189
3341
|
onPress: () => setIsEditingVideo(true),
|
|
3190
3342
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3191
3343
|
style: styles.toolIconContainer,
|
|
3192
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3344
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3193
3345
|
name: "cut",
|
|
3194
3346
|
size: 22,
|
|
3195
3347
|
color: "#fff"
|
|
@@ -3206,7 +3358,7 @@ function EditorScreen({
|
|
|
3206
3358
|
},
|
|
3207
3359
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3208
3360
|
style: styles.toolIconContainer,
|
|
3209
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3361
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3210
3362
|
name: "images",
|
|
3211
3363
|
size: 22,
|
|
3212
3364
|
color: "#fff"
|
|
@@ -3223,7 +3375,7 @@ function EditorScreen({
|
|
|
3223
3375
|
},
|
|
3224
3376
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3225
3377
|
style: styles.toolIconContainer,
|
|
3226
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3378
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3227
3379
|
name: "color-palette",
|
|
3228
3380
|
size: 22,
|
|
3229
3381
|
color: "#fff"
|
|
@@ -3240,7 +3392,7 @@ function EditorScreen({
|
|
|
3240
3392
|
},
|
|
3241
3393
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3242
3394
|
style: styles.toolIconContainer,
|
|
3243
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3395
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3244
3396
|
name: "settings-outline",
|
|
3245
3397
|
size: 22,
|
|
3246
3398
|
color: "#fff"
|
|
@@ -3279,7 +3431,7 @@ function EditorScreen({
|
|
|
3279
3431
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3280
3432
|
onPress: onBack,
|
|
3281
3433
|
style: styles.backButton,
|
|
3282
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3434
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3283
3435
|
name: "close",
|
|
3284
3436
|
size: 22,
|
|
3285
3437
|
color: "#fff"
|
|
@@ -3289,7 +3441,7 @@ function EditorScreen({
|
|
|
3289
3441
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3290
3442
|
onPress: () => setIsMuted(!isMuted),
|
|
3291
3443
|
style: styles.soundButton,
|
|
3292
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3444
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3293
3445
|
name: isMuted ? 'volume-mute' : 'volume-high',
|
|
3294
3446
|
size: 22,
|
|
3295
3447
|
color: "#fff"
|
|
@@ -3308,6 +3460,12 @@ function EditorScreen({
|
|
|
3308
3460
|
data: items,
|
|
3309
3461
|
extraData: [overlays, editingTextId, editsHistory, activeFilter, imageOptions, trimStart, trimEnd, isMuted, activeIndex],
|
|
3310
3462
|
keyExtractor: it => it.id,
|
|
3463
|
+
initialScrollIndex: activeIndex,
|
|
3464
|
+
getItemLayout: (_, index) => ({
|
|
3465
|
+
length: SCREEN_WIDTH,
|
|
3466
|
+
offset: SCREEN_WIDTH * index,
|
|
3467
|
+
index
|
|
3468
|
+
}),
|
|
3311
3469
|
horizontal: true,
|
|
3312
3470
|
pagingEnabled: false,
|
|
3313
3471
|
showsHorizontalScrollIndicator: false,
|
|
@@ -3418,7 +3576,7 @@ function EditorScreen({
|
|
|
3418
3576
|
fontWeight: '700'
|
|
3419
3577
|
},
|
|
3420
3578
|
children: (() => {
|
|
3421
|
-
const selMs =
|
|
3579
|
+
const selMs = (endX.current - startX.current) / TIMELINE_WIDTH * duration;
|
|
3422
3580
|
const totalSec = Math.floor(selMs / 1000);
|
|
3423
3581
|
return totalSec >= 60 ? `${Math.floor(totalSec / 60)}:${(totalSec % 60).toString().padStart(2, '0')} selected` : `${(selMs / 1000).toFixed(1)}s selected`;
|
|
3424
3582
|
})()
|
|
@@ -3429,30 +3587,54 @@ function EditorScreen({
|
|
|
3429
3587
|
}],
|
|
3430
3588
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
3431
3589
|
style: styles.filmstrip,
|
|
3432
|
-
children: [thumbnails.
|
|
3590
|
+
children: [thumbnails.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3591
|
+
style: {
|
|
3592
|
+
flex: 1,
|
|
3593
|
+
justifyContent: 'center',
|
|
3594
|
+
alignItems: 'center'
|
|
3595
|
+
},
|
|
3596
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
|
|
3597
|
+
color: "#ffffff",
|
|
3598
|
+
size: "small"
|
|
3599
|
+
})
|
|
3600
|
+
}) : thumbnails.map((uri, idx) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
|
|
3433
3601
|
source: {
|
|
3434
3602
|
uri
|
|
3435
3603
|
},
|
|
3436
3604
|
style: styles.filmstripImage
|
|
3437
3605
|
}, idx)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3438
|
-
|
|
3606
|
+
ref: leftOverlayRef,
|
|
3607
|
+
style: [styles.timelineOverlay, {
|
|
3608
|
+
left: 0,
|
|
3609
|
+
width: startX.current
|
|
3610
|
+
}]
|
|
3439
3611
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3612
|
+
ref: rightOverlayRef,
|
|
3613
|
+
style: [styles.timelineOverlay, {
|
|
3614
|
+
left: endX.current,
|
|
3615
|
+
right: 0
|
|
3443
3616
|
}]
|
|
3617
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3618
|
+
ref: selectionRangeRef,
|
|
3619
|
+
style: [styles.selectionRange, {
|
|
3620
|
+
left: startX.current,
|
|
3621
|
+
width: endX.current - startX.current
|
|
3622
|
+
}],
|
|
3623
|
+
...middlePan.panHandlers
|
|
3444
3624
|
})]
|
|
3445
3625
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3626
|
+
ref: leftHandleRef,
|
|
3446
3627
|
style: [styles.customHandle, styles.customHandleLeft, {
|
|
3447
|
-
left:
|
|
3628
|
+
left: startX.current - 16
|
|
3448
3629
|
}],
|
|
3449
3630
|
...startPan.panHandlers,
|
|
3450
3631
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3451
3632
|
style: styles.handleBarLine
|
|
3452
3633
|
})
|
|
3453
3634
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3635
|
+
ref: rightHandleRef,
|
|
3454
3636
|
style: [styles.customHandle, styles.customHandleRight, {
|
|
3455
|
-
left:
|
|
3637
|
+
left: endX.current - 16
|
|
3456
3638
|
}],
|
|
3457
3639
|
...endPan.panHandlers,
|
|
3458
3640
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
@@ -3479,7 +3661,7 @@ function EditorScreen({
|
|
|
3479
3661
|
justifyContent: 'center',
|
|
3480
3662
|
alignItems: 'center'
|
|
3481
3663
|
}],
|
|
3482
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3664
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3483
3665
|
name: "close",
|
|
3484
3666
|
size: 24,
|
|
3485
3667
|
color: "#fff"
|
|
@@ -3581,7 +3763,7 @@ function EditorScreen({
|
|
|
3581
3763
|
fontSize: 20
|
|
3582
3764
|
},
|
|
3583
3765
|
children: s.emoji
|
|
3584
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3766
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3585
3767
|
name: "close-circle",
|
|
3586
3768
|
size: 14,
|
|
3587
3769
|
color: "#ff6b6b",
|
|
@@ -3689,7 +3871,7 @@ function EditorScreen({
|
|
|
3689
3871
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3690
3872
|
onPress: () => removeCaption(c.id),
|
|
3691
3873
|
style: styles.captionRemoveBtn,
|
|
3692
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3874
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3693
3875
|
name: "close",
|
|
3694
3876
|
size: 14,
|
|
3695
3877
|
color: "#ff6b6b"
|
|
@@ -3730,12 +3912,12 @@ function EditorScreen({
|
|
|
3730
3912
|
contentContainerStyle: [styles.toolButtonsRow, {
|
|
3731
3913
|
flexGrow: 1
|
|
3732
3914
|
}],
|
|
3733
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
3915
|
+
children: [resolvedMusicList.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
3734
3916
|
style: [styles.toolButton, showMusicModal && styles.toolButtonActive],
|
|
3735
3917
|
onPress: () => setShowMusicModal(true),
|
|
3736
3918
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3737
3919
|
style: styles.toolIconContainer,
|
|
3738
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3920
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3739
3921
|
name: "musical-notes",
|
|
3740
3922
|
size: 22,
|
|
3741
3923
|
color: "#fff"
|
|
@@ -3749,7 +3931,7 @@ function EditorScreen({
|
|
|
3749
3931
|
onPress: () => setPanel('text'),
|
|
3750
3932
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3751
3933
|
style: styles.toolIconContainer,
|
|
3752
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3934
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3753
3935
|
name: "text",
|
|
3754
3936
|
size: 22,
|
|
3755
3937
|
color: "#fff"
|
|
@@ -3763,7 +3945,7 @@ function EditorScreen({
|
|
|
3763
3945
|
onPress: handleOpenTransform,
|
|
3764
3946
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3765
3947
|
style: styles.toolIconContainer,
|
|
3766
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3948
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3767
3949
|
name: "crop",
|
|
3768
3950
|
size: 22,
|
|
3769
3951
|
color: "#fff"
|
|
@@ -3777,7 +3959,7 @@ function EditorScreen({
|
|
|
3777
3959
|
onPress: () => setPanel('trim'),
|
|
3778
3960
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3779
3961
|
style: styles.toolIconContainer,
|
|
3780
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3962
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3781
3963
|
name: "cut",
|
|
3782
3964
|
size: 22,
|
|
3783
3965
|
color: "#fff"
|
|
@@ -3791,7 +3973,7 @@ function EditorScreen({
|
|
|
3791
3973
|
onPress: () => setPanel('frame'),
|
|
3792
3974
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3793
3975
|
style: styles.toolIconContainer,
|
|
3794
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3976
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3795
3977
|
name: "images",
|
|
3796
3978
|
size: 22,
|
|
3797
3979
|
color: "#fff"
|
|
@@ -3805,7 +3987,7 @@ function EditorScreen({
|
|
|
3805
3987
|
onPress: () => setPanel('filter'),
|
|
3806
3988
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3807
3989
|
style: styles.toolIconContainer,
|
|
3808
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
3990
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3809
3991
|
name: "color-palette",
|
|
3810
3992
|
size: 22,
|
|
3811
3993
|
color: "#fff"
|
|
@@ -3819,7 +4001,7 @@ function EditorScreen({
|
|
|
3819
4001
|
onPress: () => setPanel('edit'),
|
|
3820
4002
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
3821
4003
|
style: styles.toolIconContainer,
|
|
3822
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
4004
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3823
4005
|
name: "settings-outline",
|
|
3824
4006
|
size: 22,
|
|
3825
4007
|
color: "#fff"
|
|
@@ -3846,7 +4028,7 @@ function EditorScreen({
|
|
|
3846
4028
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
3847
4029
|
style: styles.nextBlueText,
|
|
3848
4030
|
children: "Next"
|
|
3849
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
4031
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3850
4032
|
name: "arrow-forward",
|
|
3851
4033
|
size: 16,
|
|
3852
4034
|
color: "#fff",
|
|
@@ -3881,7 +4063,7 @@ function EditorScreen({
|
|
|
3881
4063
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3882
4064
|
onPress: () => setShowMusicModal(false),
|
|
3883
4065
|
style: styles.musicModalCloseBtn,
|
|
3884
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
4066
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3885
4067
|
name: "close",
|
|
3886
4068
|
size: 24,
|
|
3887
4069
|
color: "#fff"
|
|
@@ -3902,7 +4084,7 @@ function EditorScreen({
|
|
|
3902
4084
|
}), musicSearchQuery.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
3903
4085
|
onPress: () => setMusicSearchQuery(''),
|
|
3904
4086
|
style: styles.musicSearchClearBtn,
|
|
3905
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
4087
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
3906
4088
|
name: "close-circle",
|
|
3907
4089
|
size: 18,
|
|
3908
4090
|
color: "#8e8e93"
|
|
@@ -4038,6 +4220,7 @@ function EditorScreen({
|
|
|
4038
4220
|
onPress: () => {
|
|
4039
4221
|
setSelectedMusic(null);
|
|
4040
4222
|
setMusicPaused(true);
|
|
4223
|
+
setIsMuted(false);
|
|
4041
4224
|
},
|
|
4042
4225
|
style: styles.musicFooterRemoveBtn,
|
|
4043
4226
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -4156,7 +4339,7 @@ function EditorScreen({
|
|
|
4156
4339
|
scale: 1.15
|
|
4157
4340
|
}]
|
|
4158
4341
|
} : {}],
|
|
4159
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
4342
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.Icon, {
|
|
4160
4343
|
name: isOverTrash ? "trash" : "trash-outline",
|
|
4161
4344
|
size: 20,
|
|
4162
4345
|
color: "#fff"
|
|
@@ -4805,7 +4988,9 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
4805
4988
|
height: 60
|
|
4806
4989
|
},
|
|
4807
4990
|
timelineOverlay: {
|
|
4808
|
-
|
|
4991
|
+
position: 'absolute',
|
|
4992
|
+
top: 0,
|
|
4993
|
+
bottom: 0,
|
|
4809
4994
|
backgroundColor: 'rgba(0,0,0,0.6)'
|
|
4810
4995
|
},
|
|
4811
4996
|
selectionRange: {
|
|
@@ -4815,7 +5000,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
4815
5000
|
backgroundColor: 'transparent',
|
|
4816
5001
|
borderTopWidth: 2,
|
|
4817
5002
|
borderBottomWidth: 2,
|
|
4818
|
-
borderColor: '#
|
|
5003
|
+
borderColor: '#FFD60A'
|
|
4819
5004
|
},
|
|
4820
5005
|
handle: {
|
|
4821
5006
|
position: 'absolute',
|
|
@@ -4841,7 +5026,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
4841
5026
|
top: 0,
|
|
4842
5027
|
width: 16,
|
|
4843
5028
|
height: 60,
|
|
4844
|
-
backgroundColor: '#
|
|
5029
|
+
backgroundColor: '#FFD60A',
|
|
4845
5030
|
justifyContent: 'center',
|
|
4846
5031
|
alignItems: 'center',
|
|
4847
5032
|
zIndex: 20
|