@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.
Files changed (63) hide show
  1. package/README.md +17 -3
  2. package/android/src/main/java/com/technotoil/image_videoeditor/FrameGrabberModule.kt +2 -6
  3. package/android/src/main/java/com/technotoil/image_videoeditor/MediaEditorModule.kt +75 -35
  4. package/android/src/main/java/com/technotoil/image_videoeditor/MediaLibraryModule.kt +51 -35
  5. package/android/src/main/java/com/technotoil/image_videoeditor/RNVideoPreviewManager.kt +98 -117
  6. package/ios/RNMediaEditor.m +38 -7
  7. package/ios/RNMediaLibrary.m +19 -15
  8. package/ios/RNVideoPreviewManager.m +2 -0
  9. package/lib/commonjs/assets/frames/film_vintage.png +0 -0
  10. package/lib/commonjs/assets/frames/floral_gold.png +0 -0
  11. package/lib/commonjs/assets/frames/minimal_double.png +0 -0
  12. package/lib/commonjs/assets/frames/polaroid_white.png +0 -0
  13. package/lib/commonjs/assets/frames/watercolor_floral.png +0 -0
  14. package/lib/commonjs/components/VideoEditor.js +235 -0
  15. package/lib/commonjs/components/VideoEditor.js.map +1 -0
  16. package/lib/commonjs/index.js +14 -0
  17. package/lib/commonjs/index.js.map +1 -0
  18. package/lib/commonjs/native/CameraView.js +109 -0
  19. package/lib/commonjs/native/CameraView.js.map +1 -0
  20. package/lib/commonjs/native/FrameGrabber.js +17 -0
  21. package/lib/commonjs/native/FrameGrabber.js.map +1 -0
  22. package/lib/commonjs/native/MediaEditor.js +24 -0
  23. package/lib/commonjs/native/MediaEditor.js.map +1 -0
  24. package/lib/commonjs/native/MediaLibrary.js +45 -0
  25. package/lib/commonjs/native/MediaLibrary.js.map +1 -0
  26. package/lib/commonjs/native/MediaPicker.js +17 -0
  27. package/lib/commonjs/native/MediaPicker.js.map +1 -0
  28. package/lib/commonjs/native/MediaPlayer.js +17 -0
  29. package/lib/commonjs/native/MediaPlayer.js.map +1 -0
  30. package/lib/commonjs/native/VideoPreview.js +17 -0
  31. package/lib/commonjs/native/VideoPreview.js.map +1 -0
  32. package/lib/commonjs/package.json +1 -0
  33. package/lib/commonjs/screens/CropScreen.js +1233 -0
  34. package/lib/commonjs/screens/CropScreen.js.map +1 -0
  35. package/lib/commonjs/screens/EditorScreen.js +6043 -0
  36. package/lib/commonjs/screens/EditorScreen.js.map +1 -0
  37. package/lib/commonjs/screens/ExportScreen.js +294 -0
  38. package/lib/commonjs/screens/ExportScreen.js.map +1 -0
  39. package/lib/commonjs/screens/GalleryScreen.js +510 -0
  40. package/lib/commonjs/screens/GalleryScreen.js.map +1 -0
  41. package/lib/commonjs/screens/PickScreen.js +1353 -0
  42. package/lib/commonjs/screens/PickScreen.js.map +1 -0
  43. package/lib/commonjs/types.js +2 -0
  44. package/lib/commonjs/types.js.map +1 -0
  45. package/lib/module/components/VideoEditor.js +104 -31
  46. package/lib/module/components/VideoEditor.js.map +1 -1
  47. package/lib/module/screens/CropScreen.js +26 -9
  48. package/lib/module/screens/CropScreen.js.map +1 -1
  49. package/lib/module/screens/EditorScreen.js +371 -86
  50. package/lib/module/screens/EditorScreen.js.map +1 -1
  51. package/lib/module/screens/PickScreen.js +245 -93
  52. package/lib/module/screens/PickScreen.js.map +1 -1
  53. package/lib/typescript/src/components/VideoEditor.d.ts +18 -2
  54. package/lib/typescript/src/screens/CropScreen.d.ts +3 -1
  55. package/lib/typescript/src/screens/EditorScreen.d.ts +2 -1
  56. package/lib/typescript/src/screens/PickScreen.d.ts +6 -1
  57. package/lib/typescript/src/types.d.ts +1 -0
  58. package/package.json +17 -8
  59. package/src/components/VideoEditor.tsx +82 -11
  60. package/src/screens/CropScreen.tsx +54 -33
  61. package/src/screens/EditorScreen.tsx +366 -106
  62. package/src/screens/PickScreen.tsx +231 -76
  63. package/src/types.ts +1 -0
@@ -0,0 +1,1353 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PickScreen = PickScreen;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _Ionicons = _interopRequireDefault(require("react-native-vector-icons/Ionicons"));
10
+ var _reactNativeImageCropPicker = _interopRequireDefault(require("react-native-image-crop-picker"));
11
+ var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
12
+ var _CameraView = require("../native/CameraView");
13
+ var _MediaLibrary = require("../native/MediaLibrary");
14
+ var _VideoPreview = require("../native/VideoPreview");
15
+ var _jsxRuntime = require("react/jsx-runtime");
16
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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); }
18
+ const TABS = ['GALLERY', 'PHOTO', 'VIDEO'];
19
+ const POST_TYPES = ['POST', 'STORY', 'REEL'];
20
+ const CameraIcon = () => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
21
+ style: {
22
+ width: 30,
23
+ height: 22,
24
+ borderWidth: 2,
25
+ borderColor: '#fff',
26
+ borderRadius: 4,
27
+ alignItems: 'center',
28
+ justifyContent: 'center',
29
+ position: 'relative'
30
+ },
31
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
32
+ style: {
33
+ width: 10,
34
+ height: 10,
35
+ borderRadius: 5,
36
+ borderWidth: 2,
37
+ borderColor: '#fff'
38
+ }
39
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
40
+ style: {
41
+ width: 6,
42
+ height: 3,
43
+ backgroundColor: '#fff',
44
+ position: 'absolute',
45
+ top: -4,
46
+ left: 4,
47
+ borderRadius: 1
48
+ }
49
+ })]
50
+ });
51
+ function formatDuration(ms) {
52
+ if (!ms || ms <= 0) return '';
53
+ const total = Math.floor(ms / 1000);
54
+ const m = Math.floor(total / 60);
55
+ const s = total % 60;
56
+ return `${m}:${s.toString().padStart(2, '0')}`;
57
+ }
58
+ function PickScreen({
59
+ isActive = true,
60
+ items,
61
+ onPicked,
62
+ onNext,
63
+ headerTitle = 'New post',
64
+ customCancelIcon,
65
+ onCancelPress,
66
+ cameraModes = ['POST', 'STORY', 'REEL'],
67
+ onCameraModeChange,
68
+ defaultCameraMode,
69
+ maxSelection = 1,
70
+ aspectRatio = 'free',
71
+ mediaType = 'any',
72
+ mediaTabs = ['GALLERY', 'PHOTO', 'VIDEO']
73
+ }) {
74
+ const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
75
+ const [tab, setTab] = (0, _react.useState)(mediaTabs[0] || 'GALLERY');
76
+ const [activeAlbum, setActiveAlbum] = (0, _react.useState)({
77
+ id: 'all',
78
+ title: 'Recents'
79
+ });
80
+ const [showAlbumPicker, setShowAlbumPicker] = (0, _react.useState)(false);
81
+ const [postType, setPostType] = (0, _react.useState)('POST');
82
+ const [multiSelect, setMultiSelect] = (0, _react.useState)(false);
83
+ const [selectedItems, setSelectedItems] = (0, _react.useState)([]);
84
+ const [selectedMedia, setSelectedMedia] = (0, _react.useState)(null);
85
+ const [library, setLibrary] = (0, _react.useState)([]);
86
+ const [albums, setAlbums] = (0, _react.useState)([]);
87
+ const [loading, setLoading] = (0, _react.useState)(false);
88
+ const [previewUri, setPreviewUri] = (0, _react.useState)(null);
89
+
90
+ // Aspect ratio logic
91
+ const isRatioLocked = aspectRatio !== 'free';
92
+ const ratioMap = {
93
+ '1:1': 1,
94
+ '4:3': 4 / 3,
95
+ '4:5': 4 / 5,
96
+ '16:9': 16 / 9,
97
+ '9:16': 9 / 16
98
+ };
99
+ const previewAspectRatio = isRatioLocked ? ratioMap[aspectRatio] ?? 1 : undefined;
100
+ // When ratio is locked, always use 'cover' (fills the fixed frame)
101
+ const [cropMode, setCropMode] = (0, _react.useState)(isRatioLocked ? '1:1' : '1:1');
102
+ const [videoPaused, setVideoPaused] = (0, _react.useState)(false);
103
+ const scaleAnim = (0, _react.useRef)(new _reactNative.Animated.Value(1)).current;
104
+ const [showCustomCamera, setShowCustomCamera] = (0, _react.useState)(false);
105
+ const [facing, setFacing] = (0, _react.useState)('front');
106
+ const [flashMode, setFlashMode] = (0, _react.useState)('off');
107
+ const [isRecording, setIsRecording] = (0, _react.useState)(false);
108
+ const isRecordingRef = (0, _react.useRef)(false);
109
+ const cameraRef = (0, _react.useRef)(null);
110
+ const [activeCameraMode, setActiveCameraMode] = (0, _react.useState)(() => {
111
+ if (defaultCameraMode) {
112
+ const matched = cameraModes.find(m => m.toUpperCase() === defaultCameraMode.toUpperCase());
113
+ if (matched) return matched;
114
+ }
115
+ return cameraModes.includes('STORY') ? 'STORY' : cameraModes[0] || 'STORY';
116
+ });
117
+ (0, _react.useEffect)(() => {
118
+ onCameraModeChange?.(activeCameraMode);
119
+ }, [activeCameraMode, onCameraModeChange]);
120
+ const handleCameraMediaCaptured = (uri, type, width, height, durationMs) => {
121
+ setShowCustomCamera(false);
122
+ const item = {
123
+ id: 'camera_' + Date.now(),
124
+ uri: uri,
125
+ type: type,
126
+ thumbnailUri: uri,
127
+ width: width,
128
+ height: height,
129
+ durationMs: durationMs
130
+ };
131
+ setLibrary(prev => [item, ...prev]);
132
+ setSelectedMedia(item);
133
+ setSelectedItems([item]);
134
+ onPicked([item]);
135
+ onNext([item]);
136
+ };
137
+ const handlePress = async () => {
138
+ if (isRecordingRef.current) {
139
+ return;
140
+ }
141
+ try {
142
+ const photo = await cameraRef.current?.capturePhoto();
143
+ if (photo) {
144
+ handleCameraMediaCaptured(photo.uri, 'image', photo.width, photo.height);
145
+ }
146
+ } catch (err) {
147
+ console.error('PickScreen: capturePhoto error:', err);
148
+ _reactNative.Alert.alert('Capture Error', err?.message ?? 'Failed to capture photo');
149
+ }
150
+ };
151
+ const handleLongPress = async () => {
152
+ try {
153
+ isRecordingRef.current = true;
154
+ setIsRecording(true);
155
+ await cameraRef.current?.startRecording();
156
+ } catch (err) {
157
+ isRecordingRef.current = false;
158
+ setIsRecording(false);
159
+ _reactNative.Alert.alert('Recording Error', err?.message ?? 'Failed to start recording');
160
+ }
161
+ };
162
+ const handlePressOut = async () => {
163
+ if (!isRecordingRef.current) return;
164
+ try {
165
+ const video = await cameraRef.current?.stopRecording();
166
+ isRecordingRef.current = false;
167
+ setIsRecording(false);
168
+ if (video) {
169
+ handleCameraMediaCaptured(video.uri, 'video', video.width, video.height, video.durationMs);
170
+ }
171
+ } catch (err) {
172
+ isRecordingRef.current = false;
173
+ setIsRecording(false);
174
+ _reactNative.Alert.alert('Recording Error', err?.message ?? 'Failed to stop recording');
175
+ }
176
+ };
177
+ const loadMedia = async albumId => {
178
+ try {
179
+ console.log('loadMedia called with albumId:', albumId);
180
+ setLoading(true);
181
+ const assets = await (0, _MediaLibrary.listMedia)({
182
+ limit: 200,
183
+ offset: 0,
184
+ type: mediaType === 'photo' ? 'image' : mediaType === 'video' ? 'video' : 'all',
185
+ albumId: albumId === 'all' ? undefined : albumId
186
+ });
187
+ console.log('loadMedia got assets:', assets.length);
188
+ setLibrary(assets);
189
+ if (assets[0] && !multiSelect) {
190
+ setSelectedMedia(assets[0]);
191
+ }
192
+ } catch (err) {
193
+ console.error('loadMedia error:', err);
194
+ _reactNative.Alert.alert('Library error', err?.message ?? 'Failed to load library.');
195
+ } finally {
196
+ setLoading(false);
197
+ }
198
+ };
199
+ (0, _react.useEffect)(() => {
200
+ console.log('PickScreen mounted!');
201
+ (async () => {
202
+ try {
203
+ const ok = await (0, _MediaLibrary.requestMediaAccess)();
204
+ console.log('requestMediaAccess ok?', ok);
205
+ if (!ok) {
206
+ _reactNative.Alert.alert('Permission needed', 'Allow photo access to continue.');
207
+ return;
208
+ }
209
+ const fetchedAlbums = await (0, _MediaLibrary.listAlbums)();
210
+ setAlbums([{
211
+ id: 'all',
212
+ title: 'Recents'
213
+ }, ...fetchedAlbums]);
214
+ loadMedia('all');
215
+ } catch (err) {
216
+ console.error('Initial load failed', err);
217
+ }
218
+ })();
219
+ }, []);
220
+ const filtered = (0, _react.useMemo)(() => {
221
+ let list = library;
222
+ if (tab === 'PHOTO') list = library.filter(i => i.type === 'image');else if (tab === 'VIDEO') list = library.filter(i => i.type === 'video');
223
+ const cameraItem = {
224
+ id: 'camera_trigger',
225
+ uri: 'camera_trigger',
226
+ type: 'image'
227
+ };
228
+ return [cameraItem, ...list];
229
+ }, [library, tab]);
230
+ const listData = (0, _react.useMemo)(() => {
231
+ const rows = Array.from({
232
+ length: Math.ceil(filtered.length / 4)
233
+ }).map((_, i) => ({
234
+ id: `row_${i}`,
235
+ type: 'row',
236
+ items: filtered.slice(i * 4, i * 4 + 4)
237
+ }));
238
+ return [{
239
+ id: 'header_preview',
240
+ type: 'preview'
241
+ }, {
242
+ id: 'header_albumRow',
243
+ type: 'albumRow'
244
+ }, ...rows];
245
+ }, [filtered]);
246
+ (0, _react.useEffect)(() => {
247
+ let cancelled = false;
248
+ setVideoPaused(false);
249
+ (async () => {
250
+ if (!selectedMedia) {
251
+ setPreviewUri(null);
252
+ return;
253
+ }
254
+ if (!selectedMedia.uri.startsWith('ph://') && !selectedMedia.uri.startsWith('content://')) {
255
+ setPreviewUri(selectedMedia.uri);
256
+ return;
257
+ }
258
+ setPreviewUri(null);
259
+ try {
260
+ const fileUri = await (0, _MediaLibrary.exportAsset)(selectedMedia.id);
261
+ if (!cancelled) setPreviewUri(fileUri);
262
+ } catch {
263
+ if (!cancelled) setPreviewUri(null);
264
+ }
265
+ })();
266
+ return () => {
267
+ cancelled = true;
268
+ };
269
+ }, [selectedMedia]);
270
+ const playableUri = (0, _react.useMemo)(() => {
271
+ if (!selectedMedia) return null;
272
+ if (previewUri) return previewUri;
273
+ return selectedMedia.uri;
274
+ }, [previewUri, selectedMedia]);
275
+ const toggleMultiSelect = () => {
276
+ setMultiSelect(v => {
277
+ if (!v && selectedMedia) {
278
+ setSelectedItems([selectedMedia]);
279
+ } else {
280
+ setSelectedItems([]);
281
+ }
282
+ return !v;
283
+ });
284
+ };
285
+ const handleSelectItem = item => {
286
+ if (multiSelect) {
287
+ setSelectedItems(prev => {
288
+ const exists = prev.find(i => i.id === item.id);
289
+ if (exists) {
290
+ const newItems = prev.filter(i => i.id !== item.id);
291
+ setSelectedMedia(newItems.length > 0 ? newItems[newItems.length - 1] : null);
292
+ return newItems;
293
+ }
294
+ if (prev.length >= maxSelection) return prev;
295
+ setSelectedMedia(item);
296
+ return [...prev, item];
297
+ });
298
+ } else {
299
+ setSelectedMedia(item);
300
+ }
301
+ _reactNative.Animated.sequence([_reactNative.Animated.timing(scaleAnim, {
302
+ toValue: 0.97,
303
+ duration: 80,
304
+ useNativeDriver: true
305
+ }), _reactNative.Animated.timing(scaleAnim, {
306
+ toValue: 1,
307
+ duration: 80,
308
+ useNativeDriver: true
309
+ })]).start();
310
+ };
311
+ const handleLongPressItem = item => {
312
+ if (!multiSelect) {
313
+ setMultiSelect(true);
314
+ setSelectedItems([item]);
315
+ setSelectedMedia(item);
316
+ _reactNative.Animated.sequence([_reactNative.Animated.timing(scaleAnim, {
317
+ toValue: 0.97,
318
+ duration: 80,
319
+ useNativeDriver: true
320
+ }), _reactNative.Animated.timing(scaleAnim, {
321
+ toValue: 1,
322
+ duration: 80,
323
+ useNativeDriver: true
324
+ })]).start();
325
+ }
326
+ };
327
+ const openImageCropPickerCamera = async type => {
328
+ try {
329
+ const result = await _reactNativeImageCropPicker.default.openCamera({
330
+ mediaType: type
331
+ });
332
+ if (result) {
333
+ const item = {
334
+ id: 'camera_' + Date.now(),
335
+ uri: result.path,
336
+ type: type === 'photo' ? 'image' : 'video',
337
+ thumbnailUri: result.path,
338
+ width: result.width,
339
+ height: result.height,
340
+ durationMs: type === 'video' ? result.duration || 10000 : undefined
341
+ };
342
+ setLibrary(prev => [item, ...prev]);
343
+ setSelectedMedia(item);
344
+ setSelectedItems([item]);
345
+ onPicked([item]);
346
+ onNext([item]);
347
+ }
348
+ } catch (err) {
349
+ if (err?.message !== 'User cancelled image selection' && err?.message !== 'User cancelled image selection.') {
350
+ _reactNative.Alert.alert('Camera error', err?.message ?? 'Failed to open camera.');
351
+ }
352
+ }
353
+ };
354
+ const handleOpenCamera = async () => {
355
+ if (_reactNative.Platform.OS === 'android') {
356
+ try {
357
+ const cameraGranted = await _reactNative.PermissionsAndroid.request(_reactNative.PermissionsAndroid.PERMISSIONS.CAMERA, {
358
+ title: 'Camera Permission',
359
+ message: 'App needs access to your camera to take photos and record videos.',
360
+ buttonNeutral: 'Ask Me Later',
361
+ buttonNegative: 'Cancel',
362
+ buttonPositive: 'OK'
363
+ });
364
+ const audioGranted = await _reactNative.PermissionsAndroid.request(_reactNative.PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, {
365
+ title: 'Microphone Permission',
366
+ message: 'App needs access to your microphone to record audio for videos.',
367
+ buttonNeutral: 'Ask Me Later',
368
+ buttonNegative: 'Cancel',
369
+ buttonPositive: 'OK'
370
+ });
371
+ if (cameraGranted !== _reactNative.PermissionsAndroid.RESULTS.GRANTED || audioGranted !== _reactNative.PermissionsAndroid.RESULTS.GRANTED) {
372
+ _reactNative.Alert.alert('Permissions Required', 'Camera and Microphone permissions are required to use the custom camera.');
373
+ return;
374
+ }
375
+ } catch (err) {
376
+ console.warn(err);
377
+ return;
378
+ }
379
+ }
380
+ setFacing('front');
381
+ setShowCustomCamera(true);
382
+ };
383
+ const getSelectionIndex = id => {
384
+ const idx = selectedItems.findIndex(i => i.id === id);
385
+ return idx === -1 ? null : idx + 1;
386
+ };
387
+ const handleNext = () => {
388
+ const picked = multiSelect ? selectedItems : selectedMedia ? [selectedMedia] : [];
389
+ if (picked.length === 0) {
390
+ _reactNative.Alert.alert('Select media', 'Choose at least one item.');
391
+ return;
392
+ }
393
+ onPicked(picked);
394
+ onNext(picked);
395
+ };
396
+ const renderThumb = ({
397
+ item
398
+ }) => {
399
+ if (item.id === 'camera_trigger') {
400
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
401
+ style: styles.cameraGridContainer,
402
+ onPress: handleOpenCamera,
403
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
404
+ style: styles.cameraGridBox,
405
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(CameraIcon, {})
406
+ })
407
+ });
408
+ }
409
+ const thumbUri = item.thumbnailUri;
410
+ const selIdx = getSelectionIndex(item.id);
411
+ const isActive = multiSelect ? !!selIdx : selectedMedia?.id === item.id;
412
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
413
+ style: styles.thumbContainer,
414
+ onPress: () => handleSelectItem(item),
415
+ onLongPress: () => handleLongPressItem(item),
416
+ children: [thumbUri ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
417
+ source: {
418
+ uri: thumbUri
419
+ },
420
+ style: styles.thumb
421
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
422
+ style: [styles.thumb, styles.thumbFallback]
423
+ }), isActive && !multiSelect && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
424
+ style: styles.activeOverlay
425
+ }), multiSelect && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
426
+ style: [styles.multiOverlay, isActive && styles.multiOverlayActive],
427
+ children: isActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
428
+ style: styles.selectionBadge,
429
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
430
+ style: styles.selectionNumber,
431
+ children: selIdx
432
+ })
433
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
434
+ style: styles.emptyBadge
435
+ })
436
+ }), item.type === 'video' && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
437
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
438
+ style: styles.videoPlayBadge,
439
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
440
+ name: "play",
441
+ size: 10,
442
+ color: "#fff"
443
+ })
444
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
445
+ style: styles.videoBadge,
446
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
447
+ style: styles.videoDuration,
448
+ children: formatDuration(item.durationMs)
449
+ })
450
+ })]
451
+ })]
452
+ });
453
+ };
454
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
455
+ style: styles.container,
456
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
457
+ style: styles.header,
458
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
459
+ onPress: () => {
460
+ if (onCancelPress) {
461
+ onCancelPress();
462
+ } else {
463
+ onNext([]);
464
+ }
465
+ },
466
+ children: customCancelIcon ? customCancelIcon : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
467
+ name: "close",
468
+ size: 22,
469
+ color: "#fff"
470
+ })
471
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
472
+ style: styles.headerTitle,
473
+ children: headerTitle
474
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
475
+ style: styles.nextBtn,
476
+ onPress: handleNext,
477
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
478
+ style: styles.nextText,
479
+ children: "Next"
480
+ })
481
+ })]
482
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Modal, {
483
+ visible: showAlbumPicker,
484
+ transparent: true,
485
+ animationType: "slide",
486
+ onRequestClose: () => setShowAlbumPicker(false),
487
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
488
+ style: styles.albumSheetBackdrop,
489
+ onPress: () => setShowAlbumPicker(false)
490
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
491
+ style: styles.albumSheet,
492
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
493
+ style: styles.albumSheetHandle
494
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
495
+ style: styles.albumSheetTitle,
496
+ children: "Select Album"
497
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
498
+ bounces: false,
499
+ children: albums.map(album => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
500
+ style: styles.albumSheetOption,
501
+ onPress: () => {
502
+ setActiveAlbum(album);
503
+ setShowAlbumPicker(false);
504
+ loadMedia(album.id);
505
+ },
506
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
507
+ style: [styles.albumSheetOptionText, activeAlbum.id === album.id && styles.albumSheetOptionActive],
508
+ children: album.title
509
+ }), activeAlbum.id === album.id && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
510
+ name: "checkmark",
511
+ size: 20,
512
+ color: "#3b82f6"
513
+ })]
514
+ }, album.id))
515
+ })]
516
+ })]
517
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
518
+ data: listData,
519
+ extraData: {
520
+ selectedMedia,
521
+ previewUri,
522
+ playableUri,
523
+ videoPaused,
524
+ cropMode,
525
+ isRatioLocked,
526
+ activeAlbum,
527
+ multiSelect,
528
+ selectedItems,
529
+ showAlbumPicker,
530
+ loading
531
+ },
532
+ keyExtractor: item => item.id,
533
+ stickyHeaderIndices: [1],
534
+ style: styles.libraryList,
535
+ contentContainerStyle: styles.grid,
536
+ getItemLayout: (data, index) => {
537
+ const previewHeight = isRatioLocked && previewAspectRatio ? _reactNative.Dimensions.get('window').width / previewAspectRatio : 420;
538
+ const albumRowHeight = 48;
539
+ const rowHeight = _reactNative.Dimensions.get('window').width / 4;
540
+ if (index === 0) return {
541
+ length: previewHeight,
542
+ offset: 0,
543
+ index
544
+ };
545
+ if (index === 1) return {
546
+ length: albumRowHeight,
547
+ offset: previewHeight,
548
+ index
549
+ };
550
+ const offset = previewHeight + albumRowHeight + (index - 2) * rowHeight;
551
+ return {
552
+ length: rowHeight,
553
+ offset,
554
+ index
555
+ };
556
+ },
557
+ removeClippedSubviews: false,
558
+ windowSize: 11,
559
+ ListEmptyComponent: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
560
+ style: styles.empty,
561
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
562
+ style: styles.emptyText,
563
+ children: loading ? 'Loading…' : 'No media found'
564
+ })
565
+ }),
566
+ renderItem: ({
567
+ item
568
+ }) => {
569
+ if (item.type === 'preview') {
570
+ const previewStyleHeight = isRatioLocked && previewAspectRatio ? _reactNative.Dimensions.get('window').width / previewAspectRatio : 420;
571
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
572
+ style: [styles.preview, {
573
+ transform: [{
574
+ scale: scaleAnim
575
+ }],
576
+ height: previewStyleHeight
577
+ }],
578
+ children: [selectedMedia?.type === 'video' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
579
+ style: styles.previewImage,
580
+ onPress: () => setVideoPaused(v => !v),
581
+ children: [playableUri && isActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_VideoPreview.VideoPreview, {
582
+ uri: playableUri,
583
+ paused: videoPaused || !isActive,
584
+ muted: false,
585
+ style: styles.previewImage,
586
+ resizeMode: "cover"
587
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
588
+ source: {
589
+ uri: selectedMedia.thumbnailUri || selectedMedia.uri
590
+ },
591
+ style: styles.previewImage,
592
+ resizeMode: "cover"
593
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
594
+ style: styles.previewOverlay,
595
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
596
+ style: styles.playPauseCircle,
597
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
598
+ name: videoPaused ? 'play' : 'pause',
599
+ size: 24,
600
+ color: "#fff"
601
+ })
602
+ })
603
+ })]
604
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
605
+ source: {
606
+ uri: previewUri ?? selectedMedia?.uri
607
+ },
608
+ style: [styles.previewImage, cropMode === '1:1' ? styles.squareCrop : styles.originalCrop],
609
+ resizeMode: isRatioLocked ? 'cover' : cropMode === '1:1' ? 'cover' : 'contain'
610
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
611
+ style: styles.previewControls,
612
+ children: [isRatioLocked && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
613
+ style: styles.ratioBadge,
614
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
615
+ style: styles.ratioBadgeText,
616
+ children: aspectRatio
617
+ })
618
+ }), !isRatioLocked && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
619
+ style: styles.cropToggle,
620
+ onPress: () => setCropMode(v => v === '1:1' ? 'original' : '1:1'),
621
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
622
+ name: cropMode === '1:1' ? 'square-outline' : 'expand-outline',
623
+ size: 20,
624
+ color: "#fff"
625
+ })
626
+ })]
627
+ })]
628
+ });
629
+ }
630
+ if (item.type === 'albumRow') {
631
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
632
+ style: [styles.albumRow, {
633
+ backgroundColor: '#0b0f1a',
634
+ zIndex: 999,
635
+ elevation: 5
636
+ }],
637
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
638
+ style: styles.albumSelector,
639
+ onPress: () => setShowAlbumPicker(v => !v),
640
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
641
+ style: styles.albumTitle,
642
+ children: activeAlbum.title
643
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
644
+ name: "chevron-down",
645
+ size: 16,
646
+ color: "#fff",
647
+ style: {
648
+ marginLeft: 6
649
+ }
650
+ })]
651
+ }), maxSelection > 1 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
652
+ style: {
653
+ flexDirection: 'row',
654
+ alignItems: 'center',
655
+ gap: 8
656
+ },
657
+ children: [multiSelect && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
658
+ style: {
659
+ color: '#3b82f6',
660
+ fontSize: 12,
661
+ fontWeight: '700'
662
+ },
663
+ children: [selectedItems.length, "/", maxSelection]
664
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
665
+ style: [styles.multiSelectBtn, multiSelect && styles.multiSelectBtnActive, multiSelect && selectedItems.length === 0 && {
666
+ opacity: 0.35
667
+ }],
668
+ onPress: () => {
669
+ if (multiSelect) {
670
+ handleNext();
671
+ } else {
672
+ toggleMultiSelect();
673
+ }
674
+ },
675
+ disabled: multiSelect && selectedItems.length === 0,
676
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
677
+ style: [styles.multiSelectText, multiSelect && styles.multiSelectTextActive],
678
+ children: multiSelect ? 'Done' : 'Select multiple'
679
+ })
680
+ })]
681
+ })]
682
+ });
683
+ }
684
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
685
+ style: {
686
+ flexDirection: 'row'
687
+ },
688
+ children: item.items.map(mediaItem => renderThumb({
689
+ item: mediaItem
690
+ }))
691
+ });
692
+ }
693
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
694
+ style: styles.tabBar,
695
+ children: mediaTabs.filter(t => mediaType === 'any' || mediaType === 'photo' && t !== 'VIDEO' || mediaType === 'video' && t !== 'PHOTO').map(t => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
696
+ onPress: () => setTab(t),
697
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
698
+ style: [styles.tab, tab === t && styles.tabActive],
699
+ children: t
700
+ })
701
+ }, t))
702
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
703
+ visible: showCustomCamera,
704
+ animationType: "slide",
705
+ transparent: false,
706
+ onRequestClose: () => setShowCustomCamera(false),
707
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
708
+ style: styles.cameraContainer,
709
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CameraView.CameraView, {
710
+ ref: cameraRef,
711
+ facing: facing,
712
+ flashMode: facing === 'front' ? 'off' : flashMode,
713
+ style: _reactNative.StyleSheet.absoluteFillObject
714
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
715
+ style: styles.cameraGridOverlay,
716
+ pointerEvents: "none",
717
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
718
+ style: styles.gridRow,
719
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
720
+ style: styles.gridCell
721
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
722
+ style: [styles.gridCell, styles.gridCellMiddleCol]
723
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
724
+ style: styles.gridCell
725
+ })]
726
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
727
+ style: [styles.gridRow, styles.gridRowMiddleRow],
728
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
729
+ style: styles.gridCell
730
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
731
+ style: [styles.gridCell, styles.gridCellMiddleCol]
732
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
733
+ style: styles.gridCell
734
+ })]
735
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
736
+ style: styles.gridRow,
737
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
738
+ style: styles.gridCell
739
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
740
+ style: [styles.gridCell, styles.gridCellMiddleCol]
741
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
742
+ style: styles.gridCell
743
+ })]
744
+ })]
745
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
746
+ style: [styles.cameraHeader, {
747
+ top: Math.max(insets.top, 16)
748
+ }],
749
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
750
+ style: styles.cameraCloseBtn,
751
+ onPress: () => setShowCustomCamera(false),
752
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
753
+ name: "close",
754
+ size: 22,
755
+ color: "#fff"
756
+ })
757
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
758
+ style: [styles.cameraFlashContainer, facing === 'front' && {
759
+ opacity: 0.3
760
+ }],
761
+ onPress: () => setFlashMode(f => f === 'on' ? 'off' : 'on'),
762
+ disabled: facing === 'front',
763
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
764
+ name: flashMode === 'on' && facing === 'back' ? 'flash' : 'flash-off',
765
+ size: 22,
766
+ color: flashMode === 'on' && facing === 'back' ? '#FFD700' : 'rgba(255,255,255,0.4)'
767
+ })
768
+ })]
769
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
770
+ style: [styles.cameraFooter, {
771
+ bottom: Math.max(insets.bottom + 60, 60)
772
+ }],
773
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
774
+ style: styles.cameraGalleryPreview,
775
+ children: library.length > 1 && library[1].thumbnailUri ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
776
+ source: {
777
+ uri: library[1].thumbnailUri
778
+ },
779
+ style: styles.cameraGalleryThumb
780
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
781
+ style: styles.cameraGalleryThumbPlaceholder
782
+ })
783
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
784
+ style: [styles.captureRing, isRecording && styles.captureRingRecording],
785
+ onPress: handlePress,
786
+ onLongPress: handleLongPress,
787
+ onPressOut: handlePressOut,
788
+ delayLongPress: 200,
789
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
790
+ style: [styles.captureButton, isRecording && styles.captureButtonRecording]
791
+ })
792
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
793
+ style: styles.flipCameraBtn,
794
+ onPress: () => setFacing(f => f === 'front' ? 'back' : 'front'),
795
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Ionicons.default, {
796
+ name: "camera-reverse-outline",
797
+ size: 26,
798
+ color: "#fff"
799
+ })
800
+ })]
801
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
802
+ style: [styles.cameraModeBar, {
803
+ bottom: Math.max(insets.bottom + 12, 16)
804
+ }],
805
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
806
+ horizontal: true,
807
+ showsHorizontalScrollIndicator: false,
808
+ contentContainerStyle: styles.cameraModeScrollContainer,
809
+ children: cameraModes.map(mode => {
810
+ const isActive = mode === activeCameraMode;
811
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
812
+ onPress: () => setActiveCameraMode(mode),
813
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
814
+ style: isActive ? styles.cameraModeTextActive : styles.cameraModeTextInactive,
815
+ children: mode
816
+ })
817
+ }, mode);
818
+ })
819
+ })
820
+ })]
821
+ })
822
+ })]
823
+ });
824
+ }
825
+ const styles = _reactNative.StyleSheet.create({
826
+ container: {
827
+ flex: 1,
828
+ backgroundColor: '#0b0f1a'
829
+ },
830
+ header: {
831
+ flexDirection: 'row',
832
+ justifyContent: 'space-between',
833
+ alignItems: 'center',
834
+ paddingHorizontal: 16,
835
+ paddingVertical: 12,
836
+ borderBottomWidth: 0,
837
+ backgroundColor: '#0b0f1a',
838
+ zIndex: 10,
839
+ elevation: 10
840
+ },
841
+ headerTitle: {
842
+ color: '#fff',
843
+ fontWeight: '700',
844
+ fontSize: 18
845
+ },
846
+ headerCancel: {
847
+ fontSize: 20,
848
+ color: '#fff'
849
+ },
850
+ nextBtn: {
851
+ backgroundColor: '#2563eb',
852
+ paddingHorizontal: 14,
853
+ paddingVertical: 8,
854
+ borderRadius: 20
855
+ },
856
+ nextText: {
857
+ color: '#fff',
858
+ fontWeight: '700'
859
+ },
860
+ albumDropdown: {
861
+ borderBottomWidth: 1,
862
+ borderBottomColor: '#111827',
863
+ backgroundColor: '#0b0f1a'
864
+ },
865
+ albumOption: {
866
+ flexDirection: 'row',
867
+ justifyContent: 'space-between',
868
+ paddingHorizontal: 16,
869
+ paddingVertical: 10
870
+ },
871
+ albumOptionText: {
872
+ fontSize: 14,
873
+ color: '#e5e7eb'
874
+ },
875
+ albumOptionActive: {
876
+ fontWeight: '700'
877
+ },
878
+ checkmark: {
879
+ color: '#2563eb',
880
+ fontWeight: '700'
881
+ },
882
+ // Bottom sheet styles
883
+ albumSheetBackdrop: {
884
+ ..._reactNative.StyleSheet.absoluteFillObject,
885
+ backgroundColor: 'rgba(0,0,0,0.55)'
886
+ },
887
+ albumSheet: {
888
+ position: 'absolute',
889
+ bottom: 0,
890
+ left: 0,
891
+ right: 0,
892
+ backgroundColor: '#161b2e',
893
+ borderTopLeftRadius: 20,
894
+ borderTopRightRadius: 20,
895
+ paddingBottom: 32,
896
+ maxHeight: '60%'
897
+ },
898
+ albumSheetHandle: {
899
+ width: 40,
900
+ height: 4,
901
+ borderRadius: 2,
902
+ backgroundColor: '#3f4a6e',
903
+ alignSelf: 'center',
904
+ marginTop: 12,
905
+ marginBottom: 6
906
+ },
907
+ albumSheetTitle: {
908
+ color: '#fff',
909
+ fontSize: 16,
910
+ fontWeight: '700',
911
+ textAlign: 'center',
912
+ paddingVertical: 12,
913
+ borderBottomWidth: 1,
914
+ borderBottomColor: '#1f2a45'
915
+ },
916
+ albumSheetOption: {
917
+ flexDirection: 'row',
918
+ justifyContent: 'space-between',
919
+ alignItems: 'center',
920
+ paddingHorizontal: 20,
921
+ paddingVertical: 16,
922
+ borderBottomWidth: 1,
923
+ borderBottomColor: '#1a2240'
924
+ },
925
+ albumSheetOptionText: {
926
+ fontSize: 15,
927
+ color: '#cbd5e1'
928
+ },
929
+ albumSheetOptionActive: {
930
+ color: '#fff',
931
+ fontWeight: '700'
932
+ },
933
+ albumSheetCheckmark: {
934
+ color: '#3b82f6',
935
+ fontSize: 18,
936
+ fontWeight: '700'
937
+ },
938
+ preview: {
939
+ width: '100%',
940
+ height: 420,
941
+ backgroundColor: '#0f172a',
942
+ overflow: 'hidden'
943
+ },
944
+ previewImage: {
945
+ width: '100%',
946
+ height: '100%',
947
+ overflow: 'hidden'
948
+ },
949
+ squareCrop: {
950
+ height: '100%'
951
+ },
952
+ originalCrop: {
953
+ height: '100%'
954
+ },
955
+ previewControls: {
956
+ position: 'absolute',
957
+ left: 16,
958
+ right: 16,
959
+ bottom: 16,
960
+ flexDirection: 'row',
961
+ justifyContent: 'flex-start',
962
+ alignItems: 'center'
963
+ },
964
+ cropToggle: {
965
+ backgroundColor: 'rgba(0,0,0,0.65)',
966
+ width: 34,
967
+ height: 34,
968
+ borderRadius: 17,
969
+ alignItems: 'center',
970
+ justifyContent: 'center'
971
+ },
972
+ cropIcon: {
973
+ color: '#fff',
974
+ fontSize: 16
975
+ },
976
+ ratioBadge: {
977
+ backgroundColor: 'rgba(0,0,0,0.65)',
978
+ paddingHorizontal: 10,
979
+ paddingVertical: 5,
980
+ borderRadius: 12,
981
+ borderWidth: 1,
982
+ borderColor: 'rgba(255,255,255,0.3)'
983
+ },
984
+ ratioBadgeText: {
985
+ color: '#fff',
986
+ fontSize: 12,
987
+ fontWeight: '700',
988
+ letterSpacing: 0.5
989
+ },
990
+ albumRow: {
991
+ flexDirection: 'row',
992
+ justifyContent: 'space-between',
993
+ alignItems: 'center',
994
+ paddingHorizontal: 16,
995
+ height: 48
996
+ },
997
+ albumSelector: {
998
+ flexDirection: 'row',
999
+ alignItems: 'center'
1000
+ },
1001
+ albumTitle: {
1002
+ fontSize: 16,
1003
+ fontWeight: '700',
1004
+ color: '#fff'
1005
+ },
1006
+ albumArrow: {
1007
+ width: 10,
1008
+ height: 10,
1009
+ borderRightWidth: 2,
1010
+ borderBottomWidth: 2,
1011
+ borderColor: '#fff',
1012
+ marginLeft: 8,
1013
+ marginTop: -4,
1014
+ transform: [{
1015
+ rotate: '45deg'
1016
+ }]
1017
+ },
1018
+ multiSelectBtn: {
1019
+ backgroundColor: '#111827',
1020
+ paddingHorizontal: 16,
1021
+ paddingVertical: 8,
1022
+ borderRadius: 18
1023
+ },
1024
+ cameraGridContainer: {
1025
+ width: '25%',
1026
+ aspectRatio: 1,
1027
+ padding: 1
1028
+ },
1029
+ cameraGridBox: {
1030
+ flex: 1,
1031
+ backgroundColor: '#262626',
1032
+ borderRadius: 8,
1033
+ alignItems: 'center',
1034
+ justifyContent: 'center'
1035
+ },
1036
+ multiSelectBtnActive: {
1037
+ backgroundColor: '#2563eb'
1038
+ },
1039
+ multiSelectText: {
1040
+ color: '#e5e7eb',
1041
+ fontSize: 12,
1042
+ fontWeight: '700'
1043
+ },
1044
+ multiSelectTextActive: {
1045
+ color: '#fff'
1046
+ },
1047
+ postTypeBar: {
1048
+ flexDirection: 'row',
1049
+ justifyContent: 'space-evenly',
1050
+ paddingVertical: 12,
1051
+ backgroundColor: '#0b0f1a'
1052
+ },
1053
+ postTypeChip: {
1054
+ paddingHorizontal: 28,
1055
+ paddingVertical: 10,
1056
+ borderRadius: 20,
1057
+ backgroundColor: '#111827'
1058
+ },
1059
+ postTypeChipActive: {
1060
+ backgroundColor: '#1d4ed8'
1061
+ },
1062
+ postTypeText: {
1063
+ color: '#9ca3af',
1064
+ fontWeight: '700',
1065
+ letterSpacing: 0.4
1066
+ },
1067
+ postTypeTextActive: {
1068
+ color: '#fff'
1069
+ },
1070
+ grid: {
1071
+ paddingBottom: 80
1072
+ },
1073
+ libraryList: {
1074
+ flex: 1
1075
+ },
1076
+ thumbContainer: {
1077
+ width: '25%',
1078
+ aspectRatio: 1,
1079
+ padding: 1
1080
+ },
1081
+ thumb: {
1082
+ width: '100%',
1083
+ height: '100%',
1084
+ borderRadius: 8
1085
+ },
1086
+ thumbFallback: {
1087
+ backgroundColor: '#111'
1088
+ },
1089
+ activeOverlay: {
1090
+ ..._reactNative.StyleSheet.absoluteFillObject,
1091
+ backgroundColor: 'rgba(255,255,255,0.18)'
1092
+ },
1093
+ multiOverlay: {
1094
+ position: 'absolute',
1095
+ right: 6,
1096
+ top: 6
1097
+ },
1098
+ multiOverlayActive: {},
1099
+ selectionBadge: {
1100
+ width: 22,
1101
+ height: 22,
1102
+ borderRadius: 11,
1103
+ backgroundColor: '#2563eb',
1104
+ alignItems: 'center',
1105
+ justifyContent: 'center',
1106
+ borderWidth: 1.5,
1107
+ borderColor: '#fff'
1108
+ },
1109
+ selectionNumber: {
1110
+ color: '#fff',
1111
+ fontSize: 11,
1112
+ fontWeight: '700'
1113
+ },
1114
+ emptyBadge: {
1115
+ width: 22,
1116
+ height: 22,
1117
+ borderRadius: 11,
1118
+ borderWidth: 1.5,
1119
+ borderColor: '#fff',
1120
+ backgroundColor: 'rgba(0,0,0,0.25)'
1121
+ },
1122
+ videoBadge: {
1123
+ position: 'absolute',
1124
+ right: 6,
1125
+ bottom: 6,
1126
+ backgroundColor: 'rgba(0,0,0,0.6)',
1127
+ paddingHorizontal: 6,
1128
+ paddingVertical: 2,
1129
+ borderRadius: 6
1130
+ },
1131
+ videoDuration: {
1132
+ color: '#fff',
1133
+ fontSize: 10,
1134
+ fontWeight: '600'
1135
+ },
1136
+ videoPlayBadge: {
1137
+ position: 'absolute',
1138
+ left: 6,
1139
+ top: 6,
1140
+ width: 20,
1141
+ height: 20,
1142
+ borderRadius: 10,
1143
+ backgroundColor: 'rgba(0,0,0,0.6)',
1144
+ alignItems: 'center',
1145
+ justifyContent: 'center'
1146
+ },
1147
+ videoPlayIcon: {
1148
+ color: '#fff',
1149
+ fontSize: 10,
1150
+ fontWeight: '700'
1151
+ },
1152
+ previewOverlay: {
1153
+ position: 'absolute',
1154
+ left: 0,
1155
+ right: 0,
1156
+ bottom: 14,
1157
+ alignItems: 'center'
1158
+ },
1159
+ playPauseCircle: {
1160
+ width: 44,
1161
+ height: 44,
1162
+ borderRadius: 22,
1163
+ backgroundColor: 'rgba(0,0,0,0.55)',
1164
+ alignItems: 'center',
1165
+ justifyContent: 'center'
1166
+ },
1167
+ playPauseText: {
1168
+ color: '#fff',
1169
+ fontSize: 18,
1170
+ fontWeight: '700'
1171
+ },
1172
+ empty: {
1173
+ padding: 24,
1174
+ alignItems: 'center'
1175
+ },
1176
+ emptyText: {
1177
+ color: '#6b7280'
1178
+ },
1179
+ tabBar: {
1180
+ flexDirection: 'row',
1181
+ justifyContent: 'space-around',
1182
+ paddingVertical: 10,
1183
+ borderTopWidth: 1,
1184
+ borderTopColor: '#111827'
1185
+ },
1186
+ tab: {
1187
+ color: '#6b7280',
1188
+ fontWeight: '700'
1189
+ },
1190
+ tabActive: {
1191
+ color: '#fff'
1192
+ },
1193
+ cameraContainer: {
1194
+ flex: 1,
1195
+ backgroundColor: '#000'
1196
+ },
1197
+ cameraGridOverlay: {
1198
+ ..._reactNative.StyleSheet.absoluteFillObject,
1199
+ justifyContent: 'space-between',
1200
+ paddingVertical: 120
1201
+ },
1202
+ gridRow: {
1203
+ flex: 1,
1204
+ flexDirection: 'row'
1205
+ },
1206
+ gridRowMiddleRow: {
1207
+ borderTopWidth: 1,
1208
+ borderBottomWidth: 1,
1209
+ borderColor: 'rgba(255, 255, 255, 0.15)'
1210
+ },
1211
+ gridCell: {
1212
+ flex: 1
1213
+ },
1214
+ gridCellMiddleCol: {
1215
+ borderLeftWidth: 1,
1216
+ borderRightWidth: 1,
1217
+ borderColor: 'rgba(255, 255, 255, 0.15)'
1218
+ },
1219
+ cameraHeader: {
1220
+ position: 'absolute',
1221
+ top: 40,
1222
+ left: 0,
1223
+ right: 0,
1224
+ flexDirection: 'row',
1225
+ justifyContent: 'space-between',
1226
+ alignItems: 'center',
1227
+ paddingHorizontal: 20,
1228
+ zIndex: 10
1229
+ },
1230
+ cameraCloseBtn: {
1231
+ width: 40,
1232
+ height: 40,
1233
+ borderRadius: 20,
1234
+ backgroundColor: 'rgba(0,0,0,0.3)',
1235
+ alignItems: 'center',
1236
+ justifyContent: 'center'
1237
+ },
1238
+ cameraCloseText: {
1239
+ color: '#fff',
1240
+ fontSize: 20,
1241
+ fontWeight: '300'
1242
+ },
1243
+ cameraFlashContainer: {
1244
+ width: 40,
1245
+ height: 40,
1246
+ borderRadius: 20,
1247
+ backgroundColor: 'rgba(0,0,0,0.3)',
1248
+ alignItems: 'center',
1249
+ justifyContent: 'center'
1250
+ },
1251
+ cameraHeaderText: {
1252
+ color: '#fff',
1253
+ fontSize: 20
1254
+ },
1255
+ cameraHeaderActiveText: {
1256
+ color: '#FFD700'
1257
+ },
1258
+ cameraFooter: {
1259
+ position: 'absolute',
1260
+ bottom: 80,
1261
+ left: 0,
1262
+ right: 0,
1263
+ flexDirection: 'row',
1264
+ justifyContent: 'space-between',
1265
+ alignItems: 'center',
1266
+ paddingHorizontal: 40,
1267
+ zIndex: 10
1268
+ },
1269
+ cameraGalleryPreview: {
1270
+ width: 44,
1271
+ height: 44,
1272
+ borderRadius: 8,
1273
+ borderWidth: 2,
1274
+ borderColor: '#fff',
1275
+ overflow: 'hidden',
1276
+ backgroundColor: '#333'
1277
+ },
1278
+ cameraGalleryThumb: {
1279
+ width: '100%',
1280
+ height: '100%'
1281
+ },
1282
+ cameraGalleryThumbPlaceholder: {
1283
+ width: '100%',
1284
+ height: '100%',
1285
+ backgroundColor: '#333'
1286
+ },
1287
+ captureRing: {
1288
+ width: 84,
1289
+ height: 84,
1290
+ borderRadius: 42,
1291
+ borderWidth: 4,
1292
+ borderColor: '#fff',
1293
+ alignItems: 'center',
1294
+ justifyContent: 'center',
1295
+ backgroundColor: 'transparent'
1296
+ },
1297
+ captureRingRecording: {
1298
+ borderColor: 'rgba(255, 0, 0, 0.4)'
1299
+ },
1300
+ captureButton: {
1301
+ width: 66,
1302
+ height: 66,
1303
+ borderRadius: 33,
1304
+ backgroundColor: '#fff'
1305
+ },
1306
+ captureButtonRecording: {
1307
+ backgroundColor: '#ef4444',
1308
+ borderRadius: 8,
1309
+ width: 32,
1310
+ height: 32
1311
+ },
1312
+ flipCameraBtn: {
1313
+ width: 44,
1314
+ height: 44,
1315
+ borderRadius: 22,
1316
+ backgroundColor: 'rgba(0,0,0,0.3)',
1317
+ alignItems: 'center',
1318
+ justifyContent: 'center'
1319
+ },
1320
+ flipCameraText: {
1321
+ color: '#fff',
1322
+ fontSize: 22
1323
+ },
1324
+ cameraModeBar: {
1325
+ position: 'absolute',
1326
+ bottom: 30,
1327
+ left: 0,
1328
+ right: 0,
1329
+ flexDirection: 'row',
1330
+ zIndex: 10
1331
+ },
1332
+ cameraModeScrollContainer: {
1333
+ alignItems: 'center',
1334
+ justifyContent: 'center',
1335
+ minWidth: '100%',
1336
+ paddingHorizontal: 20
1337
+ },
1338
+ cameraModeTextActive: {
1339
+ color: '#fff',
1340
+ fontSize: 13,
1341
+ fontWeight: 'bold',
1342
+ marginHorizontal: 15,
1343
+ letterSpacing: 1.5
1344
+ },
1345
+ cameraModeTextInactive: {
1346
+ color: 'rgba(255, 255, 255, 0.5)',
1347
+ fontSize: 13,
1348
+ fontWeight: '600',
1349
+ marginHorizontal: 15,
1350
+ letterSpacing: 1.5
1351
+ }
1352
+ });
1353
+ //# sourceMappingURL=PickScreen.js.map