@technotoil/image-video-editor 0.1.0 → 0.1.2
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 +75 -35
- 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/assets/frames/film_vintage.png +0 -0
- package/lib/commonjs/assets/frames/floral_gold.png +0 -0
- package/lib/commonjs/assets/frames/minimal_double.png +0 -0
- package/lib/commonjs/assets/frames/polaroid_white.png +0 -0
- package/lib/commonjs/assets/frames/watercolor_floral.png +0 -0
- package/lib/commonjs/components/VideoEditor.js +235 -0
- package/lib/commonjs/components/VideoEditor.js.map +1 -0
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/native/CameraView.js +109 -0
- package/lib/commonjs/native/CameraView.js.map +1 -0
- package/lib/commonjs/native/FrameGrabber.js +17 -0
- package/lib/commonjs/native/FrameGrabber.js.map +1 -0
- package/lib/commonjs/native/MediaEditor.js +24 -0
- package/lib/commonjs/native/MediaEditor.js.map +1 -0
- package/lib/commonjs/native/MediaLibrary.js +45 -0
- package/lib/commonjs/native/MediaLibrary.js.map +1 -0
- package/lib/commonjs/native/MediaPicker.js +17 -0
- package/lib/commonjs/native/MediaPicker.js.map +1 -0
- package/lib/commonjs/native/MediaPlayer.js +17 -0
- package/lib/commonjs/native/MediaPlayer.js.map +1 -0
- package/lib/commonjs/native/VideoPreview.js +17 -0
- package/lib/commonjs/native/VideoPreview.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/screens/CropScreen.js +1233 -0
- package/lib/commonjs/screens/CropScreen.js.map +1 -0
- package/lib/commonjs/screens/EditorScreen.js +6043 -0
- package/lib/commonjs/screens/EditorScreen.js.map +1 -0
- package/lib/commonjs/screens/ExportScreen.js +294 -0
- package/lib/commonjs/screens/ExportScreen.js.map +1 -0
- package/lib/commonjs/screens/GalleryScreen.js +510 -0
- package/lib/commonjs/screens/GalleryScreen.js.map +1 -0
- package/lib/commonjs/screens/PickScreen.js +1353 -0
- package/lib/commonjs/screens/PickScreen.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/components/VideoEditor.js +104 -31
- package/lib/module/components/VideoEditor.js.map +1 -1
- package/lib/module/screens/CropScreen.js +26 -9
- package/lib/module/screens/CropScreen.js.map +1 -1
- package/lib/module/screens/EditorScreen.js +371 -86
- package/lib/module/screens/EditorScreen.js.map +1 -1
- package/lib/module/screens/PickScreen.js +245 -93
- package/lib/module/screens/PickScreen.js.map +1 -1
- package/lib/typescript/src/components/VideoEditor.d.ts +18 -2
- package/lib/typescript/src/screens/CropScreen.d.ts +3 -1
- package/lib/typescript/src/screens/EditorScreen.d.ts +2 -1
- package/lib/typescript/src/screens/PickScreen.d.ts +6 -1
- package/lib/typescript/src/types.d.ts +1 -0
- package/package.json +17 -8
- package/src/components/VideoEditor.tsx +82 -11
- package/src/screens/CropScreen.tsx +54 -33
- package/src/screens/EditorScreen.tsx +366 -106
- package/src/screens/PickScreen.tsx +231 -76
- package/src/types.ts +1 -0
|
@@ -10,6 +10,7 @@ import Video from 'react-native-video';
|
|
|
10
10
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
|
11
11
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
12
12
|
const SCREEN_WIDTH = Dimensions.get('window').width;
|
|
13
|
+
const SCREEN_HEIGHT = Dimensions.get('window').height;
|
|
13
14
|
const TIMELINE_WIDTH = SCREEN_WIDTH - 40;
|
|
14
15
|
const HANDLE_SIZE = 24;
|
|
15
16
|
const CARD_WIDTH = SCREEN_WIDTH * 0.76;
|
|
@@ -167,12 +168,16 @@ export function EditorScreen({
|
|
|
167
168
|
onBack,
|
|
168
169
|
onSaved,
|
|
169
170
|
onOpenCrop,
|
|
170
|
-
musicList
|
|
171
|
+
musicList,
|
|
172
|
+
maxVideoDurationMs
|
|
171
173
|
}) {
|
|
172
174
|
const [activeIndex, setActiveIndex] = useState(initialIndex);
|
|
173
175
|
const currentItem = items[activeIndex] || items[0];
|
|
174
176
|
const item = currentItem; // Aliasing to 'item' for ease of compatibility
|
|
175
177
|
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
setActiveIndex(initialIndex);
|
|
180
|
+
}, [initialIndex]);
|
|
176
181
|
const [activeFilter, setActiveFilter] = useState('none');
|
|
177
182
|
const [imageOptions, setImageOptions] = useState({
|
|
178
183
|
rotateDegrees: 0,
|
|
@@ -183,13 +188,21 @@ export function EditorScreen({
|
|
|
183
188
|
saturation: 1,
|
|
184
189
|
grayscale: false
|
|
185
190
|
});
|
|
191
|
+
const [panel, setPanel] = useState(item.type === 'video' ? 'trim' : 'filter');
|
|
186
192
|
const [trimStart, setTrimStart] = useState(0);
|
|
187
|
-
const [trimEnd, setTrimEnd] = useState(
|
|
193
|
+
const [trimEnd, setTrimEnd] = useState(() => {
|
|
194
|
+
const end = item.durationMs || 10000;
|
|
195
|
+
return maxVideoDurationMs ? Math.min(end, maxVideoDurationMs) : end;
|
|
196
|
+
});
|
|
188
197
|
useEffect(() => {
|
|
189
198
|
setTrimStart(0);
|
|
190
|
-
|
|
199
|
+
const end = item.durationMs || maxVideoDurationMs || 10000;
|
|
200
|
+
setTrimEnd(maxVideoDurationMs ? Math.min(end, maxVideoDurationMs) : end);
|
|
191
201
|
setThumbnails([]);
|
|
192
|
-
|
|
202
|
+
if (item.type === 'video' && maxVideoDurationMs && end > maxVideoDurationMs) {
|
|
203
|
+
setPanel('trim');
|
|
204
|
+
}
|
|
205
|
+
}, [item.id, item.durationMs, maxVideoDurationMs]);
|
|
193
206
|
const [editsHistory, setEditsHistory] = useState({});
|
|
194
207
|
const editsHistoryRef = useRef({});
|
|
195
208
|
const [dimensionsMap, setDimensionsMap] = useState({});
|
|
@@ -246,7 +259,7 @@ export function EditorScreen({
|
|
|
246
259
|
setCropOffset(saved.cropOffset);
|
|
247
260
|
setZoomScale(saved.zoomScale);
|
|
248
261
|
setStraightenAngle(saved.straightenAngle);
|
|
249
|
-
setIsMuted(saved.isMuted);
|
|
262
|
+
setIsMuted(selectedMusic ? true : saved.isMuted);
|
|
250
263
|
} else {
|
|
251
264
|
setActiveFilter('none');
|
|
252
265
|
setImageOptions({
|
|
@@ -259,7 +272,8 @@ export function EditorScreen({
|
|
|
259
272
|
grayscale: false
|
|
260
273
|
});
|
|
261
274
|
setTrimStart(0);
|
|
262
|
-
|
|
275
|
+
const end = targetItem.durationMs || 10000;
|
|
276
|
+
setTrimEnd(maxVideoDurationMs ? Math.min(end, maxVideoDurationMs) : end);
|
|
263
277
|
setOverlays([]);
|
|
264
278
|
setCropRatio(null);
|
|
265
279
|
setCropOffset({
|
|
@@ -268,7 +282,14 @@ export function EditorScreen({
|
|
|
268
282
|
});
|
|
269
283
|
setZoomScale(1);
|
|
270
284
|
setStraightenAngle(0);
|
|
271
|
-
setIsMuted(false);
|
|
285
|
+
setIsMuted(selectedMusic ? true : false);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Force trim panel if video is too long
|
|
289
|
+
if (targetItem.type === 'video' && maxVideoDurationMs && targetItem.durationMs && targetItem.durationMs > maxVideoDurationMs) {
|
|
290
|
+
setPanel('trim');
|
|
291
|
+
} else if (!saved) {
|
|
292
|
+
setPanel(targetItem.type === 'video' ? 'trim' : 'filter');
|
|
272
293
|
}
|
|
273
294
|
};
|
|
274
295
|
const handleScrollEnd = e => {
|
|
@@ -327,13 +348,13 @@ export function EditorScreen({
|
|
|
327
348
|
y: (o.y + 8) * renderScale,
|
|
328
349
|
color: o.color,
|
|
329
350
|
fontSize: o.fontSize * renderScale
|
|
330
|
-
}))
|
|
351
|
+
})),
|
|
352
|
+
frameUri: edits.imageOptions.frame && FRAME_IMAGES[edits.imageOptions.frame] ? Image.resolveAssetSource(FRAME_IMAGES[edits.imageOptions.frame]).uri : undefined
|
|
331
353
|
};
|
|
332
354
|
};
|
|
333
355
|
const [saving, setSaving] = useState(false);
|
|
334
356
|
const [videoPaused, setVideoPaused] = useState(false);
|
|
335
|
-
const
|
|
336
|
-
const resolvedMusicList = musicList || DUMMY_MUSIC_LIST;
|
|
357
|
+
const resolvedMusicList = musicList || [];
|
|
337
358
|
const [selectedMusic, setSelectedMusic] = useState(null);
|
|
338
359
|
const [musicPaused, setMusicPaused] = useState(false);
|
|
339
360
|
const [showMusicModal, setShowMusicModal] = useState(false);
|
|
@@ -428,6 +449,8 @@ export function EditorScreen({
|
|
|
428
449
|
const [newText, setNewText] = useState('');
|
|
429
450
|
const isNewOverlay = React.useRef(false); // track if overlay was just created (not yet saved)
|
|
430
451
|
const originalOverlayBackup = React.useRef(null);
|
|
452
|
+
const [activeDraggingId, setActiveDraggingId] = useState(null);
|
|
453
|
+
const [isOverTrash, setIsOverTrash] = useState(false);
|
|
431
454
|
|
|
432
455
|
// ── Stickers ────────────────────────────────────────────────────────────────
|
|
433
456
|
const STICKER_LIST = ['😂', '❤️', '🔥', '✨', '💯', '👑', '🎉', '🌈', '🎶', '💫', '🙌', '😍', '🤩', '😎', '🥳', '🌸', '🦋', '⚡', '🌙', '💎', '🍕', '🎸', '🎬', '📸', '🎯', '🌺', '🦄', '🐉', '🎭', '🪩'];
|
|
@@ -894,10 +917,17 @@ export function EditorScreen({
|
|
|
894
917
|
const createTextPan = id => {
|
|
895
918
|
let startX = 0;
|
|
896
919
|
let startY = 0;
|
|
920
|
+
let pressStartTime = 0;
|
|
921
|
+
let hasMoved = false;
|
|
922
|
+
let longPressTimeout = null;
|
|
897
923
|
return PanResponder.create({
|
|
898
924
|
onStartShouldSetPanResponder: () => true,
|
|
899
925
|
onMoveShouldSetPanResponder: () => true,
|
|
900
926
|
onPanResponderGrant: () => {
|
|
927
|
+
pressStartTime = Date.now();
|
|
928
|
+
hasMoved = false;
|
|
929
|
+
setActiveDraggingId(id);
|
|
930
|
+
setIsOverTrash(false);
|
|
901
931
|
setOverlays(prev => {
|
|
902
932
|
const item = prev.find(o => o.id === id);
|
|
903
933
|
if (item) {
|
|
@@ -906,13 +936,78 @@ export function EditorScreen({
|
|
|
906
936
|
}
|
|
907
937
|
return prev;
|
|
908
938
|
});
|
|
939
|
+
|
|
940
|
+
// Setup long press timer (600ms)
|
|
941
|
+
if (longPressTimeout) clearTimeout(longPressTimeout);
|
|
942
|
+
longPressTimeout = setTimeout(() => {
|
|
943
|
+
if (!hasMoved) {
|
|
944
|
+
removeTextOverlay(id);
|
|
945
|
+
}
|
|
946
|
+
}, 600);
|
|
909
947
|
},
|
|
910
948
|
onPanResponderMove: (_, gesture) => {
|
|
949
|
+
if (Math.abs(gesture.dx) > 4 || Math.abs(gesture.dy) > 4) {
|
|
950
|
+
hasMoved = true;
|
|
951
|
+
if (longPressTimeout) {
|
|
952
|
+
clearTimeout(longPressTimeout);
|
|
953
|
+
longPressTimeout = null;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
const newX = startX + gesture.dx;
|
|
957
|
+
const newY = startY + gesture.dy;
|
|
958
|
+
|
|
959
|
+
// Trash zone: bottom 140px of screen, center horizontal
|
|
960
|
+
const isNearTrash = gesture.moveY > SCREEN_HEIGHT - 140 && Math.abs(gesture.moveX - SCREEN_WIDTH / 2) < 90;
|
|
961
|
+
setIsOverTrash(isNearTrash);
|
|
911
962
|
setOverlays(prev => prev.map(o => o.id === id ? {
|
|
912
963
|
...o,
|
|
913
|
-
x:
|
|
914
|
-
y:
|
|
964
|
+
x: newX,
|
|
965
|
+
y: newY
|
|
915
966
|
} : o));
|
|
967
|
+
},
|
|
968
|
+
onPanResponderRelease: (_, gesture) => {
|
|
969
|
+
if (longPressTimeout) {
|
|
970
|
+
clearTimeout(longPressTimeout);
|
|
971
|
+
longPressTimeout = null;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Check if released over trash zone using final touch screen coordinates
|
|
975
|
+
const releasedOverTrash = gesture.moveY > SCREEN_HEIGHT - 140 && Math.abs(gesture.moveX - SCREEN_WIDTH / 2) < 90;
|
|
976
|
+
|
|
977
|
+
// Reset dragging states
|
|
978
|
+
setActiveDraggingId(null);
|
|
979
|
+
setIsOverTrash(false);
|
|
980
|
+
if (releasedOverTrash) {
|
|
981
|
+
setTimeout(() => {
|
|
982
|
+
removeTextOverlay(id);
|
|
983
|
+
}, 50);
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
const pressDuration = Date.now() - pressStartTime;
|
|
987
|
+
if (!hasMoved && pressDuration < 250) {
|
|
988
|
+
pushToHistory();
|
|
989
|
+
setOverlays(prev => {
|
|
990
|
+
const found = prev.find(o => o.id === id);
|
|
991
|
+
if (found) {
|
|
992
|
+
originalOverlayBackup.current = {
|
|
993
|
+
...found
|
|
994
|
+
};
|
|
995
|
+
isNewOverlay.current = false;
|
|
996
|
+
setEditingTextId(id);
|
|
997
|
+
setNewText(found.text);
|
|
998
|
+
setPanel('text');
|
|
999
|
+
}
|
|
1000
|
+
return prev;
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
onPanResponderTerminate: () => {
|
|
1005
|
+
if (longPressTimeout) {
|
|
1006
|
+
clearTimeout(longPressTimeout);
|
|
1007
|
+
longPressTimeout = null;
|
|
1008
|
+
}
|
|
1009
|
+
setActiveDraggingId(null);
|
|
1010
|
+
setIsOverTrash(false);
|
|
916
1011
|
}
|
|
917
1012
|
});
|
|
918
1013
|
};
|
|
@@ -1038,13 +1133,18 @@ export function EditorScreen({
|
|
|
1038
1133
|
y: (o.y + 8) * renderScale,
|
|
1039
1134
|
color: o.color,
|
|
1040
1135
|
fontSize: o.fontSize * renderScale
|
|
1041
|
-
}))
|
|
1136
|
+
})),
|
|
1137
|
+
frameUri: imageOptions.frame && FRAME_IMAGES[imageOptions.frame] ? Image.resolveAssetSource(FRAME_IMAGES[imageOptions.frame]).uri : undefined
|
|
1042
1138
|
};
|
|
1043
1139
|
}, [imageOptions, cropOffset, maxPan, dimensions, cropRatio, straightenAngle, overlays]);
|
|
1044
1140
|
|
|
1045
1141
|
// For visual trim
|
|
1046
1142
|
|
|
1047
1143
|
const duration = item.durationMs ?? 10_000;
|
|
1144
|
+
const durationRef = useRef(duration);
|
|
1145
|
+
useEffect(() => {
|
|
1146
|
+
durationRef.current = duration;
|
|
1147
|
+
}, [duration]);
|
|
1048
1148
|
const formatTime = ms => {
|
|
1049
1149
|
const totalSec = Math.floor(ms / 1000);
|
|
1050
1150
|
const mins = Math.floor(totalSec / 60);
|
|
@@ -1106,6 +1206,39 @@ export function EditorScreen({
|
|
|
1106
1206
|
generateThumbs();
|
|
1107
1207
|
}
|
|
1108
1208
|
}, [item.type, item.uri, duration, thumbnails.length]);
|
|
1209
|
+
const leftOverlayRef = useRef(null);
|
|
1210
|
+
const rightOverlayRef = useRef(null);
|
|
1211
|
+
const selectionRangeRef = useRef(null);
|
|
1212
|
+
const leftHandleRef = useRef(null);
|
|
1213
|
+
const rightHandleRef = useRef(null);
|
|
1214
|
+
const updateNativeRefs = (newStartX, newEndX) => {
|
|
1215
|
+
leftOverlayRef.current?.setNativeProps({
|
|
1216
|
+
style: {
|
|
1217
|
+
width: newStartX
|
|
1218
|
+
}
|
|
1219
|
+
});
|
|
1220
|
+
rightOverlayRef.current?.setNativeProps({
|
|
1221
|
+
style: {
|
|
1222
|
+
left: newEndX
|
|
1223
|
+
}
|
|
1224
|
+
});
|
|
1225
|
+
selectionRangeRef.current?.setNativeProps({
|
|
1226
|
+
style: {
|
|
1227
|
+
left: newStartX,
|
|
1228
|
+
width: newEndX - newStartX
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
leftHandleRef.current?.setNativeProps({
|
|
1232
|
+
style: {
|
|
1233
|
+
left: newStartX - 16
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
rightHandleRef.current?.setNativeProps({
|
|
1237
|
+
style: {
|
|
1238
|
+
left: newEndX - 16
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
};
|
|
1109
1242
|
const startPanOffset = useRef(0);
|
|
1110
1243
|
const startPan = useRef(PanResponder.create({
|
|
1111
1244
|
onStartShouldSetPanResponder: () => true,
|
|
@@ -1119,20 +1252,76 @@ export function EditorScreen({
|
|
|
1119
1252
|
setScrollEnabled(false);
|
|
1120
1253
|
},
|
|
1121
1254
|
onPanResponderMove: (_, gesture) => {
|
|
1122
|
-
|
|
1255
|
+
let newX = Math.max(0, Math.min(endX.current - 32, startPanOffset.current + gesture.dx));
|
|
1256
|
+
let newTime = newX / TIMELINE_WIDTH * durationRef.current;
|
|
1257
|
+
const currentTrimEnd = endX.current / TIMELINE_WIDTH * durationRef.current;
|
|
1258
|
+
if (maxVideoDurationMs && currentTrimEnd - newTime > maxVideoDurationMs) {
|
|
1259
|
+
newTime = currentTrimEnd - maxVideoDurationMs;
|
|
1260
|
+
newX = newTime / durationRef.current * TIMELINE_WIDTH;
|
|
1261
|
+
}
|
|
1123
1262
|
startX.current = newX;
|
|
1124
|
-
|
|
1125
|
-
setTrimStart(newTime);
|
|
1263
|
+
updateNativeRefs(newX, endX.current);
|
|
1126
1264
|
throttledSeek(newTime);
|
|
1127
1265
|
},
|
|
1128
1266
|
onPanResponderRelease: () => {
|
|
1129
1267
|
isDraggingHandle.current = false;
|
|
1130
1268
|
setScrollEnabled(true);
|
|
1269
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1270
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1271
|
+
setSeekToMs(-1);
|
|
1272
|
+
},
|
|
1273
|
+
onPanResponderTerminate: () => {
|
|
1274
|
+
isDraggingHandle.current = false;
|
|
1275
|
+
setScrollEnabled(true);
|
|
1276
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1277
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1278
|
+
setSeekToMs(-1);
|
|
1279
|
+
}
|
|
1280
|
+
})).current;
|
|
1281
|
+
const middlePanOffsetStart = useRef(0);
|
|
1282
|
+
const middlePanOffsetEnd = useRef(0);
|
|
1283
|
+
const middlePan = useRef(PanResponder.create({
|
|
1284
|
+
onStartShouldSetPanResponder: () => true,
|
|
1285
|
+
onStartShouldSetPanResponderCapture: () => true,
|
|
1286
|
+
onMoveShouldSetPanResponder: () => true,
|
|
1287
|
+
onMoveShouldSetPanResponderCapture: () => true,
|
|
1288
|
+
onPanResponderGrant: () => {
|
|
1289
|
+
pushToHistory();
|
|
1290
|
+
middlePanOffsetStart.current = startX.current;
|
|
1291
|
+
middlePanOffsetEnd.current = endX.current;
|
|
1292
|
+
isDraggingHandle.current = true;
|
|
1293
|
+
setScrollEnabled(false);
|
|
1294
|
+
},
|
|
1295
|
+
onPanResponderMove: (_, gesture) => {
|
|
1296
|
+
const windowWidth = middlePanOffsetEnd.current - middlePanOffsetStart.current;
|
|
1297
|
+
let newStartX = middlePanOffsetStart.current + gesture.dx;
|
|
1298
|
+
let newEndX = middlePanOffsetEnd.current + gesture.dx;
|
|
1299
|
+
if (newStartX < 0) {
|
|
1300
|
+
newStartX = 0;
|
|
1301
|
+
newEndX = windowWidth;
|
|
1302
|
+
}
|
|
1303
|
+
if (newEndX > TIMELINE_WIDTH) {
|
|
1304
|
+
newEndX = TIMELINE_WIDTH;
|
|
1305
|
+
newStartX = TIMELINE_WIDTH - windowWidth;
|
|
1306
|
+
}
|
|
1307
|
+
startX.current = newStartX;
|
|
1308
|
+
endX.current = newEndX;
|
|
1309
|
+
const newStartTime = newStartX / TIMELINE_WIDTH * durationRef.current;
|
|
1310
|
+
updateNativeRefs(newStartX, newEndX);
|
|
1311
|
+
throttledSeek(newStartTime);
|
|
1312
|
+
},
|
|
1313
|
+
onPanResponderRelease: () => {
|
|
1314
|
+
isDraggingHandle.current = false;
|
|
1315
|
+
setScrollEnabled(true);
|
|
1316
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1317
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1131
1318
|
setSeekToMs(-1);
|
|
1132
1319
|
},
|
|
1133
1320
|
onPanResponderTerminate: () => {
|
|
1134
1321
|
isDraggingHandle.current = false;
|
|
1135
1322
|
setScrollEnabled(true);
|
|
1323
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1324
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1136
1325
|
setSeekToMs(-1);
|
|
1137
1326
|
}
|
|
1138
1327
|
})).current;
|
|
@@ -1149,20 +1338,29 @@ export function EditorScreen({
|
|
|
1149
1338
|
setScrollEnabled(false);
|
|
1150
1339
|
},
|
|
1151
1340
|
onPanResponderMove: (_, gesture) => {
|
|
1152
|
-
|
|
1341
|
+
let newX = Math.min(TIMELINE_WIDTH, Math.max(startX.current + 32, endPanOffset.current + gesture.dx));
|
|
1342
|
+
let newTime = newX / TIMELINE_WIDTH * durationRef.current;
|
|
1343
|
+
const currentTrimStart = startX.current / TIMELINE_WIDTH * durationRef.current;
|
|
1344
|
+
if (maxVideoDurationMs && newTime - currentTrimStart > maxVideoDurationMs) {
|
|
1345
|
+
newTime = currentTrimStart + maxVideoDurationMs;
|
|
1346
|
+
newX = newTime / durationRef.current * TIMELINE_WIDTH;
|
|
1347
|
+
}
|
|
1153
1348
|
endX.current = newX;
|
|
1154
|
-
|
|
1155
|
-
setTrimEnd(newTime);
|
|
1349
|
+
updateNativeRefs(startX.current, newX);
|
|
1156
1350
|
throttledSeek(newTime);
|
|
1157
1351
|
},
|
|
1158
1352
|
onPanResponderRelease: () => {
|
|
1159
1353
|
isDraggingHandle.current = false;
|
|
1160
1354
|
setScrollEnabled(true);
|
|
1355
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1356
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1161
1357
|
setSeekToMs(-1);
|
|
1162
1358
|
},
|
|
1163
1359
|
onPanResponderTerminate: () => {
|
|
1164
1360
|
isDraggingHandle.current = false;
|
|
1165
1361
|
setScrollEnabled(true);
|
|
1362
|
+
setTrimStart(startX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1363
|
+
setTrimEnd(endX.current / TIMELINE_WIDTH * durationRef.current);
|
|
1166
1364
|
setSeekToMs(-1);
|
|
1167
1365
|
}
|
|
1168
1366
|
})).current;
|
|
@@ -1937,11 +2135,16 @@ export function EditorScreen({
|
|
|
1937
2135
|
});
|
|
1938
2136
|
}
|
|
1939
2137
|
} else {
|
|
2138
|
+
const safeEndMs = Math.min(trimEnd, item.durationMs || 10000);
|
|
2139
|
+
const safeStartMs = Math.min(trimStart, Math.max(0, safeEndMs - 100));
|
|
2140
|
+
const isFullTrim = trimStart === 0 && trimEnd >= (item.durationMs || 10000);
|
|
1940
2141
|
exportUri = await trimVideo(item.uri, {
|
|
1941
|
-
startMs:
|
|
1942
|
-
endMs:
|
|
2142
|
+
startMs: safeStartMs,
|
|
2143
|
+
endMs: safeEndMs,
|
|
1943
2144
|
mute: isMuted,
|
|
1944
|
-
|
|
2145
|
+
...(selectedMusic?.url ? {
|
|
2146
|
+
musicUri: selectedMusic.url
|
|
2147
|
+
} : {}),
|
|
1945
2148
|
...activeOptions
|
|
1946
2149
|
});
|
|
1947
2150
|
}
|
|
@@ -1958,6 +2161,7 @@ export function EditorScreen({
|
|
|
1958
2161
|
setSaving(true);
|
|
1959
2162
|
saveEditsForIndex(activeIndex);
|
|
1960
2163
|
const updatedItems = [...items];
|
|
2164
|
+
let cumulativeMusicOffsetMs = 0;
|
|
1961
2165
|
for (let i = 0; i < items.length; i++) {
|
|
1962
2166
|
const targetItem = items[i];
|
|
1963
2167
|
let edits = editsHistoryRef.current[targetItem.id];
|
|
@@ -1983,6 +2187,7 @@ export function EditorScreen({
|
|
|
1983
2187
|
outUri = await trimVideo(outUri, {
|
|
1984
2188
|
isImage: true,
|
|
1985
2189
|
musicUri: selectedMusic.url,
|
|
2190
|
+
musicOffsetMs: cumulativeMusicOffsetMs,
|
|
1986
2191
|
rotateDegrees: 0,
|
|
1987
2192
|
flipX: false,
|
|
1988
2193
|
flipY: false,
|
|
@@ -1997,12 +2202,20 @@ export function EditorScreen({
|
|
|
1997
2202
|
uri: outUri,
|
|
1998
2203
|
thumbnailUri: outUri
|
|
1999
2204
|
};
|
|
2205
|
+
cumulativeMusicOffsetMs += 10000; // Images are 10s by default
|
|
2000
2206
|
} else {
|
|
2207
|
+
const originalDuration = targetItem.durationMs || maxVideoDurationMs || 10000;
|
|
2208
|
+
const safeEndMs = Math.min(edits.trimEnd, originalDuration);
|
|
2209
|
+
const safeStartMs = Math.min(edits.trimStart, Math.max(0, safeEndMs - 100));
|
|
2210
|
+
const isFullTrim = edits.trimStart === 0 && edits.trimEnd >= originalDuration;
|
|
2001
2211
|
const outUri = await trimVideo(targetItem.uri, {
|
|
2002
|
-
startMs:
|
|
2003
|
-
endMs:
|
|
2212
|
+
startMs: safeStartMs,
|
|
2213
|
+
endMs: safeEndMs,
|
|
2004
2214
|
mute: edits.isMuted,
|
|
2005
|
-
|
|
2215
|
+
...(selectedMusic?.url ? {
|
|
2216
|
+
musicUri: selectedMusic.url,
|
|
2217
|
+
musicOffsetMs: cumulativeMusicOffsetMs
|
|
2218
|
+
} : {}),
|
|
2006
2219
|
...opts
|
|
2007
2220
|
});
|
|
2008
2221
|
let newThumb = undefined;
|
|
@@ -2020,6 +2233,7 @@ export function EditorScreen({
|
|
|
2020
2233
|
thumbnailUri: newThumb ? newThumb : targetItem.thumbnailUri,
|
|
2021
2234
|
durationMs: newDuration
|
|
2022
2235
|
};
|
|
2236
|
+
cumulativeMusicOffsetMs += newDuration;
|
|
2023
2237
|
}
|
|
2024
2238
|
} else {
|
|
2025
2239
|
if (selectedMusic) {
|
|
@@ -2028,6 +2242,7 @@ export function EditorScreen({
|
|
|
2028
2242
|
outUri = await trimVideo(targetItem.uri, {
|
|
2029
2243
|
isImage: true,
|
|
2030
2244
|
musicUri: selectedMusic.url,
|
|
2245
|
+
musicOffsetMs: cumulativeMusicOffsetMs,
|
|
2031
2246
|
rotateDegrees: 0,
|
|
2032
2247
|
flipX: false,
|
|
2033
2248
|
flipY: false,
|
|
@@ -2036,12 +2251,17 @@ export function EditorScreen({
|
|
|
2036
2251
|
saturation: 1,
|
|
2037
2252
|
grayscale: false
|
|
2038
2253
|
});
|
|
2254
|
+
cumulativeMusicOffsetMs += 10000;
|
|
2039
2255
|
} else {
|
|
2256
|
+
const safeEndMs = targetItem.durationMs || 10000;
|
|
2040
2257
|
outUri = await trimVideo(targetItem.uri, {
|
|
2041
2258
|
startMs: 0,
|
|
2042
|
-
endMs:
|
|
2259
|
+
endMs: safeEndMs,
|
|
2043
2260
|
mute: isMuted,
|
|
2044
|
-
|
|
2261
|
+
...(selectedMusic?.url ? {
|
|
2262
|
+
musicUri: selectedMusic.url,
|
|
2263
|
+
musicOffsetMs: cumulativeMusicOffsetMs
|
|
2264
|
+
} : {}),
|
|
2045
2265
|
rotateDegrees: 0,
|
|
2046
2266
|
flipX: false,
|
|
2047
2267
|
flipY: false,
|
|
@@ -2050,6 +2270,7 @@ export function EditorScreen({
|
|
|
2050
2270
|
saturation: 1,
|
|
2051
2271
|
grayscale: false
|
|
2052
2272
|
});
|
|
2273
|
+
cumulativeMusicOffsetMs += safeEndMs;
|
|
2053
2274
|
}
|
|
2054
2275
|
updatedItems[i] = {
|
|
2055
2276
|
...targetItem,
|
|
@@ -2223,20 +2444,9 @@ export function EditorScreen({
|
|
|
2223
2444
|
zIndex: 20
|
|
2224
2445
|
}, isSelected && styles.selectedTextContainer],
|
|
2225
2446
|
...responder.panHandlers,
|
|
2226
|
-
children: /*#__PURE__*/_jsx(
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
pushToHistory();
|
|
2230
|
-
// Backup original state (text, color, position, size, etc.)
|
|
2231
|
-
const found = overlays.find(o => o.id === overlay.id);
|
|
2232
|
-
if (found) {
|
|
2233
|
-
originalOverlayBackup.current = {
|
|
2234
|
-
...found
|
|
2235
|
-
};
|
|
2236
|
-
}
|
|
2237
|
-
isNewOverlay.current = false;
|
|
2238
|
-
setEditingTextId(overlay.id);
|
|
2239
|
-
setNewText(overlay.text);
|
|
2447
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
2448
|
+
style: {
|
|
2449
|
+
padding: 4
|
|
2240
2450
|
},
|
|
2241
2451
|
children: /*#__PURE__*/_jsx(Text, {
|
|
2242
2452
|
style: [styles.textOverlay, {
|
|
@@ -2466,19 +2676,9 @@ export function EditorScreen({
|
|
|
2466
2676
|
zIndex: 20
|
|
2467
2677
|
}, isSelected && styles.selectedTextContainer],
|
|
2468
2678
|
...responder.panHandlers,
|
|
2469
|
-
children: /*#__PURE__*/_jsx(
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
pushToHistory();
|
|
2473
|
-
const found = overlays.find(o => o.id === overlay.id);
|
|
2474
|
-
if (found) {
|
|
2475
|
-
originalOverlayBackup.current = {
|
|
2476
|
-
...found
|
|
2477
|
-
};
|
|
2478
|
-
}
|
|
2479
|
-
isNewOverlay.current = false;
|
|
2480
|
-
setEditingTextId(overlay.id);
|
|
2481
|
-
setNewText(overlay.text);
|
|
2679
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
2680
|
+
style: {
|
|
2681
|
+
padding: 4
|
|
2482
2682
|
},
|
|
2483
2683
|
children: /*#__PURE__*/_jsx(Text, {
|
|
2484
2684
|
style: [styles.textOverlay, {
|
|
@@ -2612,7 +2812,15 @@ export function EditorScreen({
|
|
|
2612
2812
|
},
|
|
2613
2813
|
style: styles.filmstripImage
|
|
2614
2814
|
}, idx)), /*#__PURE__*/_jsx(View, {
|
|
2615
|
-
style: styles.timelineOverlay
|
|
2815
|
+
style: [styles.timelineOverlay, {
|
|
2816
|
+
left: 0,
|
|
2817
|
+
width: trimStart / duration * TIMELINE_WIDTH
|
|
2818
|
+
}]
|
|
2819
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
2820
|
+
style: [styles.timelineOverlay, {
|
|
2821
|
+
left: trimEnd / duration * TIMELINE_WIDTH,
|
|
2822
|
+
right: 0
|
|
2823
|
+
}]
|
|
2616
2824
|
}), /*#__PURE__*/_jsx(View, {
|
|
2617
2825
|
style: [styles.selectionRange, {
|
|
2618
2826
|
left: trimStart / duration * TIMELINE_WIDTH,
|
|
@@ -2623,20 +2831,18 @@ export function EditorScreen({
|
|
|
2623
2831
|
style: [styles.customHandle, styles.customHandleLeft, {
|
|
2624
2832
|
left: trimStart / duration * TIMELINE_WIDTH - 16
|
|
2625
2833
|
}],
|
|
2626
|
-
...startPan.panHandlers,
|
|
2627
2834
|
children: /*#__PURE__*/_jsx(View, {
|
|
2628
2835
|
style: styles.handleBarLine
|
|
2629
2836
|
})
|
|
2630
2837
|
}), /*#__PURE__*/_jsx(View, {
|
|
2631
2838
|
style: [styles.customHandle, styles.customHandleRight, {
|
|
2632
|
-
left: trimEnd / duration * TIMELINE_WIDTH
|
|
2839
|
+
left: trimEnd / duration * TIMELINE_WIDTH - 16
|
|
2633
2840
|
}],
|
|
2634
|
-
...endPan.panHandlers,
|
|
2635
2841
|
children: /*#__PURE__*/_jsx(View, {
|
|
2636
2842
|
style: styles.handleBarLine
|
|
2637
2843
|
})
|
|
2638
2844
|
})]
|
|
2639
|
-
}), /*#__PURE__*/_jsxs(Pressable, {
|
|
2845
|
+
}), resolvedMusicList.length > 0 && /*#__PURE__*/_jsxs(Pressable, {
|
|
2640
2846
|
style: styles.subTrackRow,
|
|
2641
2847
|
onPress: () => setShowMusicModal(true),
|
|
2642
2848
|
children: [/*#__PURE__*/_jsx(Text, {
|
|
@@ -2917,7 +3123,7 @@ export function EditorScreen({
|
|
|
2917
3123
|
style: styles.toolLabel,
|
|
2918
3124
|
children: "Text"
|
|
2919
3125
|
})]
|
|
2920
|
-
}), /*#__PURE__*/_jsxs(Pressable, {
|
|
3126
|
+
}), resolvedMusicList.length > 0 && /*#__PURE__*/_jsxs(Pressable, {
|
|
2921
3127
|
style: [styles.toolButton, showMusicModal && styles.toolButtonActive],
|
|
2922
3128
|
onPress: () => setShowMusicModal(true),
|
|
2923
3129
|
children: [/*#__PURE__*/_jsx(View, {
|
|
@@ -3057,19 +3263,9 @@ export function EditorScreen({
|
|
|
3057
3263
|
zIndex: 20
|
|
3058
3264
|
}, isSelected && styles.selectedTextContainer],
|
|
3059
3265
|
...responder.panHandlers,
|
|
3060
|
-
children: /*#__PURE__*/_jsx(
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
pushToHistory();
|
|
3064
|
-
const found = overlays.find(o => o.id === overlay.id);
|
|
3065
|
-
if (found) {
|
|
3066
|
-
originalOverlayBackup.current = {
|
|
3067
|
-
...found
|
|
3068
|
-
};
|
|
3069
|
-
}
|
|
3070
|
-
isNewOverlay.current = false;
|
|
3071
|
-
setEditingTextId(overlay.id);
|
|
3072
|
-
setNewText(overlay.text);
|
|
3266
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
3267
|
+
style: {
|
|
3268
|
+
padding: 4
|
|
3073
3269
|
},
|
|
3074
3270
|
children: /*#__PURE__*/_jsx(Text, {
|
|
3075
3271
|
style: [styles.textOverlay, {
|
|
@@ -3089,7 +3285,7 @@ export function EditorScreen({
|
|
|
3089
3285
|
contentContainerStyle: [styles.toolButtonsRow, {
|
|
3090
3286
|
flexGrow: 1
|
|
3091
3287
|
}],
|
|
3092
|
-
children: [/*#__PURE__*/_jsxs(Pressable, {
|
|
3288
|
+
children: [resolvedMusicList.length > 0 && /*#__PURE__*/_jsxs(Pressable, {
|
|
3093
3289
|
style: [styles.toolButton, showMusicModal && styles.toolButtonActive],
|
|
3094
3290
|
onPress: () => setShowMusicModal(true),
|
|
3095
3291
|
children: [/*#__PURE__*/_jsx(View, {
|
|
@@ -3258,6 +3454,12 @@ export function EditorScreen({
|
|
|
3258
3454
|
data: items,
|
|
3259
3455
|
extraData: [overlays, editingTextId, editsHistory, activeFilter, imageOptions, trimStart, trimEnd, isMuted, activeIndex],
|
|
3260
3456
|
keyExtractor: it => it.id,
|
|
3457
|
+
initialScrollIndex: activeIndex,
|
|
3458
|
+
getItemLayout: (_, index) => ({
|
|
3459
|
+
length: SCREEN_WIDTH,
|
|
3460
|
+
offset: SCREEN_WIDTH * index,
|
|
3461
|
+
index
|
|
3462
|
+
}),
|
|
3261
3463
|
horizontal: true,
|
|
3262
3464
|
pagingEnabled: false,
|
|
3263
3465
|
showsHorizontalScrollIndicator: false,
|
|
@@ -3368,7 +3570,7 @@ export function EditorScreen({
|
|
|
3368
3570
|
fontWeight: '700'
|
|
3369
3571
|
},
|
|
3370
3572
|
children: (() => {
|
|
3371
|
-
const selMs =
|
|
3573
|
+
const selMs = (endX.current - startX.current) / TIMELINE_WIDTH * duration;
|
|
3372
3574
|
const totalSec = Math.floor(selMs / 1000);
|
|
3373
3575
|
return totalSec >= 60 ? `${Math.floor(totalSec / 60)}:${(totalSec % 60).toString().padStart(2, '0')} selected` : `${(selMs / 1000).toFixed(1)}s selected`;
|
|
3374
3576
|
})()
|
|
@@ -3379,30 +3581,54 @@ export function EditorScreen({
|
|
|
3379
3581
|
}],
|
|
3380
3582
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
3381
3583
|
style: styles.filmstrip,
|
|
3382
|
-
children: [thumbnails.
|
|
3584
|
+
children: [thumbnails.length === 0 ? /*#__PURE__*/_jsx(View, {
|
|
3585
|
+
style: {
|
|
3586
|
+
flex: 1,
|
|
3587
|
+
justifyContent: 'center',
|
|
3588
|
+
alignItems: 'center'
|
|
3589
|
+
},
|
|
3590
|
+
children: /*#__PURE__*/_jsx(ActivityIndicator, {
|
|
3591
|
+
color: "#ffffff",
|
|
3592
|
+
size: "small"
|
|
3593
|
+
})
|
|
3594
|
+
}) : thumbnails.map((uri, idx) => /*#__PURE__*/_jsx(Image, {
|
|
3383
3595
|
source: {
|
|
3384
3596
|
uri
|
|
3385
3597
|
},
|
|
3386
3598
|
style: styles.filmstripImage
|
|
3387
3599
|
}, idx)), /*#__PURE__*/_jsx(View, {
|
|
3388
|
-
|
|
3600
|
+
ref: leftOverlayRef,
|
|
3601
|
+
style: [styles.timelineOverlay, {
|
|
3602
|
+
left: 0,
|
|
3603
|
+
width: startX.current
|
|
3604
|
+
}]
|
|
3389
3605
|
}), /*#__PURE__*/_jsx(View, {
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3606
|
+
ref: rightOverlayRef,
|
|
3607
|
+
style: [styles.timelineOverlay, {
|
|
3608
|
+
left: endX.current,
|
|
3609
|
+
right: 0
|
|
3393
3610
|
}]
|
|
3611
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
3612
|
+
ref: selectionRangeRef,
|
|
3613
|
+
style: [styles.selectionRange, {
|
|
3614
|
+
left: startX.current,
|
|
3615
|
+
width: endX.current - startX.current
|
|
3616
|
+
}],
|
|
3617
|
+
...middlePan.panHandlers
|
|
3394
3618
|
})]
|
|
3395
3619
|
}), /*#__PURE__*/_jsx(View, {
|
|
3620
|
+
ref: leftHandleRef,
|
|
3396
3621
|
style: [styles.customHandle, styles.customHandleLeft, {
|
|
3397
|
-
left:
|
|
3622
|
+
left: startX.current - 16
|
|
3398
3623
|
}],
|
|
3399
3624
|
...startPan.panHandlers,
|
|
3400
3625
|
children: /*#__PURE__*/_jsx(View, {
|
|
3401
3626
|
style: styles.handleBarLine
|
|
3402
3627
|
})
|
|
3403
3628
|
}), /*#__PURE__*/_jsx(View, {
|
|
3629
|
+
ref: rightHandleRef,
|
|
3404
3630
|
style: [styles.customHandle, styles.customHandleRight, {
|
|
3405
|
-
left:
|
|
3631
|
+
left: endX.current - 16
|
|
3406
3632
|
}],
|
|
3407
3633
|
...endPan.panHandlers,
|
|
3408
3634
|
children: /*#__PURE__*/_jsx(View, {
|
|
@@ -3680,7 +3906,7 @@ export function EditorScreen({
|
|
|
3680
3906
|
contentContainerStyle: [styles.toolButtonsRow, {
|
|
3681
3907
|
flexGrow: 1
|
|
3682
3908
|
}],
|
|
3683
|
-
children: [/*#__PURE__*/_jsxs(Pressable, {
|
|
3909
|
+
children: [resolvedMusicList.length > 0 && /*#__PURE__*/_jsxs(Pressable, {
|
|
3684
3910
|
style: [styles.toolButton, showMusicModal && styles.toolButtonActive],
|
|
3685
3911
|
onPress: () => setShowMusicModal(true),
|
|
3686
3912
|
children: [/*#__PURE__*/_jsx(View, {
|
|
@@ -3988,6 +4214,7 @@ export function EditorScreen({
|
|
|
3988
4214
|
onPress: () => {
|
|
3989
4215
|
setSelectedMusic(null);
|
|
3990
4216
|
setMusicPaused(true);
|
|
4217
|
+
setIsMuted(false);
|
|
3991
4218
|
},
|
|
3992
4219
|
style: styles.musicFooterRemoveBtn,
|
|
3993
4220
|
children: /*#__PURE__*/_jsx(Text, {
|
|
@@ -4097,6 +4324,24 @@ export function EditorScreen({
|
|
|
4097
4324
|
})]
|
|
4098
4325
|
})
|
|
4099
4326
|
})
|
|
4327
|
+
}), activeDraggingId !== null && /*#__PURE__*/_jsx(View, {
|
|
4328
|
+
style: styles.globalTrashZone,
|
|
4329
|
+
pointerEvents: "none",
|
|
4330
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
4331
|
+
style: [styles.trashZoneContainer, isOverTrash && styles.trashZoneActive, isOverTrash ? {
|
|
4332
|
+
transform: [{
|
|
4333
|
+
scale: 1.15
|
|
4334
|
+
}]
|
|
4335
|
+
} : {}],
|
|
4336
|
+
children: [/*#__PURE__*/_jsx(Ionicons, {
|
|
4337
|
+
name: isOverTrash ? "trash" : "trash-outline",
|
|
4338
|
+
size: 20,
|
|
4339
|
+
color: "#fff"
|
|
4340
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
4341
|
+
style: styles.trashZoneText,
|
|
4342
|
+
children: isOverTrash ? "Release to Delete" : "Drag here to delete"
|
|
4343
|
+
})]
|
|
4344
|
+
})
|
|
4100
4345
|
})]
|
|
4101
4346
|
});
|
|
4102
4347
|
}
|
|
@@ -4737,7 +4982,9 @@ const styles = StyleSheet.create({
|
|
|
4737
4982
|
height: 60
|
|
4738
4983
|
},
|
|
4739
4984
|
timelineOverlay: {
|
|
4740
|
-
|
|
4985
|
+
position: 'absolute',
|
|
4986
|
+
top: 0,
|
|
4987
|
+
bottom: 0,
|
|
4741
4988
|
backgroundColor: 'rgba(0,0,0,0.6)'
|
|
4742
4989
|
},
|
|
4743
4990
|
selectionRange: {
|
|
@@ -4747,7 +4994,7 @@ const styles = StyleSheet.create({
|
|
|
4747
4994
|
backgroundColor: 'transparent',
|
|
4748
4995
|
borderTopWidth: 2,
|
|
4749
4996
|
borderBottomWidth: 2,
|
|
4750
|
-
borderColor: '#
|
|
4997
|
+
borderColor: '#FFD60A'
|
|
4751
4998
|
},
|
|
4752
4999
|
handle: {
|
|
4753
5000
|
position: 'absolute',
|
|
@@ -4773,7 +5020,7 @@ const styles = StyleSheet.create({
|
|
|
4773
5020
|
top: 0,
|
|
4774
5021
|
width: 16,
|
|
4775
5022
|
height: 60,
|
|
4776
|
-
backgroundColor: '#
|
|
5023
|
+
backgroundColor: '#FFD60A',
|
|
4777
5024
|
justifyContent: 'center',
|
|
4778
5025
|
alignItems: 'center',
|
|
4779
5026
|
zIndex: 20
|
|
@@ -5375,6 +5622,44 @@ const styles = StyleSheet.create({
|
|
|
5375
5622
|
borderWidth: 1,
|
|
5376
5623
|
borderColor: 'rgba(255, 255, 255, 0.3)'
|
|
5377
5624
|
},
|
|
5625
|
+
globalTrashZone: {
|
|
5626
|
+
position: 'absolute',
|
|
5627
|
+
bottom: Platform.OS === 'ios' ? 48 : 28,
|
|
5628
|
+
left: 0,
|
|
5629
|
+
right: 0,
|
|
5630
|
+
alignItems: 'center',
|
|
5631
|
+
justifyContent: 'center',
|
|
5632
|
+
zIndex: 9999
|
|
5633
|
+
},
|
|
5634
|
+
trashZoneContainer: {
|
|
5635
|
+
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
|
5636
|
+
paddingHorizontal: 20,
|
|
5637
|
+
paddingVertical: 12,
|
|
5638
|
+
borderRadius: 24,
|
|
5639
|
+
flexDirection: 'row',
|
|
5640
|
+
alignItems: 'center',
|
|
5641
|
+
justifyContent: 'center',
|
|
5642
|
+
borderWidth: 1.5,
|
|
5643
|
+
borderColor: 'rgba(255, 255, 255, 0.25)',
|
|
5644
|
+
shadowColor: '#000',
|
|
5645
|
+
shadowOffset: {
|
|
5646
|
+
width: 0,
|
|
5647
|
+
height: 4
|
|
5648
|
+
},
|
|
5649
|
+
shadowOpacity: 0.4,
|
|
5650
|
+
shadowRadius: 6,
|
|
5651
|
+
elevation: 8
|
|
5652
|
+
},
|
|
5653
|
+
trashZoneActive: {
|
|
5654
|
+
backgroundColor: '#ef4444',
|
|
5655
|
+
borderColor: '#fca5a5'
|
|
5656
|
+
},
|
|
5657
|
+
trashZoneText: {
|
|
5658
|
+
color: '#ffffff',
|
|
5659
|
+
fontSize: 12,
|
|
5660
|
+
fontWeight: '700',
|
|
5661
|
+
marginLeft: 8
|
|
5662
|
+
},
|
|
5378
5663
|
cropIconText: {
|
|
5379
5664
|
color: '#FFFFFF',
|
|
5380
5665
|
fontSize: 18,
|