@codewithvincent/react-native-love-chat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +152 -0
- package/dist/Chat.d.ts +3 -0
- package/dist/Chat.js +78 -0
- package/dist/components/Bubble.d.ts +21 -0
- package/dist/components/Bubble.js +55 -0
- package/dist/components/Composer.d.ts +14 -0
- package/dist/components/Composer.js +44 -0
- package/dist/components/FooterReplyPreview.d.ts +7 -0
- package/dist/components/FooterReplyPreview.js +130 -0
- package/dist/components/Icons.d.ts +21 -0
- package/dist/components/Icons.js +71 -0
- package/dist/components/InputToolbar.d.ts +17 -0
- package/dist/components/InputToolbar.js +110 -0
- package/dist/components/Message.d.ts +21 -0
- package/dist/components/Message.js +131 -0
- package/dist/components/MessageList.d.ts +6 -0
- package/dist/components/MessageList.js +111 -0
- package/dist/components/MessageStatus.d.ts +6 -0
- package/dist/components/MessageStatus.js +59 -0
- package/dist/components/ReactionBubble.d.ts +55 -0
- package/dist/components/ReactionBubble.js +262 -0
- package/dist/components/ReplyPreview.d.ts +7 -0
- package/dist/components/ReplyPreview.js +102 -0
- package/dist/components/UploadFooter.d.ts +4 -0
- package/dist/components/UploadFooter.js +33 -0
- package/dist/components/adapters/UniversalAudio.d.ts +8 -0
- package/dist/components/adapters/UniversalAudio.js +23 -0
- package/dist/components/adapters/UniversalBlurView.d.ts +3 -0
- package/dist/components/adapters/UniversalBlurView.js +26 -0
- package/dist/components/adapters/UniversalVideo.d.ts +8 -0
- package/dist/components/adapters/UniversalVideo.js +20 -0
- package/dist/components/media/AudioCard.d.ts +7 -0
- package/dist/components/media/AudioCard.js +187 -0
- package/dist/components/media/FileCard.d.ts +8 -0
- package/dist/components/media/FileCard.js +68 -0
- package/dist/components/media/ImageCard.d.ts +9 -0
- package/dist/components/media/ImageCard.js +76 -0
- package/dist/components/media/VideoCard.d.ts +10 -0
- package/dist/components/media/VideoCard.js +232 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +36 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.js +2 -0
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.js +44 -0
- package/dist/utils/theme.d.ts +77 -0
- package/dist/utils/theme.js +55 -0
- package/package.json +67 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.computePositions = void 0;
|
|
40
|
+
exports.default = ReactionBubble;
|
|
41
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
42
|
+
const react_1 = require("react");
|
|
43
|
+
const react_native_1 = require("react-native");
|
|
44
|
+
const react_native_reanimated_1 = __importStar(require("react-native-reanimated"));
|
|
45
|
+
const react_native_root_siblings_1 = __importDefault(require("react-native-root-siblings"));
|
|
46
|
+
const UniversalBlurView_1 = require("./../components/adapters/UniversalBlurView");
|
|
47
|
+
const utils_1 = require("../utils");
|
|
48
|
+
const theme_1 = require("../utils/theme");
|
|
49
|
+
const Icons_1 = require("./Icons");
|
|
50
|
+
const SCREEN = react_native_1.Dimensions.get('window');
|
|
51
|
+
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
52
|
+
// Helper exported for tests (non-breaking)
|
|
53
|
+
const computePositions = ({ pos, reactionsCount, isMine, screenW, screenH, popupItemWidth = 42, popupHeight = 60, menuWidth = 200, menuItemCount = 3, menuItemHeight = 44, verticalGap = 12, horizontalMargin = 8, reactionCoreWidth = 28, reactionHorizontalPadding = 8, popupHorizontalPadding = 12, }) => {
|
|
54
|
+
// More accurate width estimation: per-reaction width + container paddings
|
|
55
|
+
const perReactionWidth = reactionCoreWidth + reactionHorizontalPadding * 2;
|
|
56
|
+
const emojiPanelWidth = reactionsCount * perReactionWidth + popupHorizontalPadding * 2;
|
|
57
|
+
let left = pos.x + pos.width / 2 - emojiPanelWidth / 2;
|
|
58
|
+
if (isMine) {
|
|
59
|
+
left = pos.x + pos.width - emojiPanelWidth - utils_1.appSize.width(6.5);
|
|
60
|
+
}
|
|
61
|
+
left = clamp(left, horizontalMargin, screenW - emojiPanelWidth - horizontalMargin);
|
|
62
|
+
let top = pos.y - popupHeight - verticalGap;
|
|
63
|
+
let emojiBelow = false;
|
|
64
|
+
if (top < horizontalMargin) {
|
|
65
|
+
top = pos.y + pos.height + verticalGap;
|
|
66
|
+
emojiBelow = true;
|
|
67
|
+
}
|
|
68
|
+
// Compute menu height based on visible items
|
|
69
|
+
const menuHeight = menuItemCount * menuItemHeight + verticalGap; // include gap/padding
|
|
70
|
+
// Default: menu below the message
|
|
71
|
+
let menuTop = emojiBelow ? top + popupHeight + verticalGap : pos.y + pos.height + verticalGap;
|
|
72
|
+
let menuLeft = isMine ? pos.x + pos.width - menuWidth : pos.x;
|
|
73
|
+
menuLeft = clamp(menuLeft, horizontalMargin, screenW - menuWidth - horizontalMargin);
|
|
74
|
+
// Check bottom space and reposition menu above if insufficient
|
|
75
|
+
const bottomSpace = screenH - menuTop;
|
|
76
|
+
const neededSpace = menuHeight + 16;
|
|
77
|
+
const placeAbove = bottomSpace < neededSpace;
|
|
78
|
+
if (placeAbove) {
|
|
79
|
+
menuTop = emojiBelow ? pos.y - menuHeight - verticalGap : top - menuHeight - verticalGap;
|
|
80
|
+
if (menuTop < horizontalMargin) {
|
|
81
|
+
menuTop = horizontalMargin;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
emojiPanel: { left, top, width: emojiPanelWidth, height: popupHeight },
|
|
86
|
+
menu: { left: menuLeft, top: menuTop, width: menuWidth, height: menuHeight, above: placeAbove },
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
exports.computePositions = computePositions;
|
|
90
|
+
function ReactionBubble({ reactions, selectedReaction, onReactionPress, style, bubbleStyle, reactionStyle, highlightColor, children, isMine, onPress, onLongPress, onReply, onDelete, onDownload, isFile, ...rest }) {
|
|
91
|
+
const triggerRef = (0, react_1.useRef)(null);
|
|
92
|
+
const siblingRef = (0, react_1.useRef)(null);
|
|
93
|
+
const theme = (0, theme_1.useTheme)();
|
|
94
|
+
const scale = (0, react_native_reanimated_1.useSharedValue)(0);
|
|
95
|
+
const animStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => ({
|
|
96
|
+
transform: [
|
|
97
|
+
{
|
|
98
|
+
scale: (0, react_native_reanimated_1.withSpring)(scale.value, {
|
|
99
|
+
damping: 12,
|
|
100
|
+
stiffness: 220,
|
|
101
|
+
mass: 0.25,
|
|
102
|
+
}),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}));
|
|
106
|
+
const showPopup = (pos) => {
|
|
107
|
+
hidePopup();
|
|
108
|
+
scale.value = 0;
|
|
109
|
+
// Feature-detection gate: only use robust positioning when Dimensions exists and measureInWindow is available
|
|
110
|
+
const canMeasure = typeof react_native_1.UIManager.measureInWindow === 'function' && SCREEN && typeof SCREEN.width === 'number';
|
|
111
|
+
let left;
|
|
112
|
+
let top;
|
|
113
|
+
let menuLeft;
|
|
114
|
+
let menuTop;
|
|
115
|
+
const menuWidth = 200;
|
|
116
|
+
if (canMeasure) {
|
|
117
|
+
const positions = (0, exports.computePositions)({
|
|
118
|
+
pos,
|
|
119
|
+
reactionsCount: reactions.length,
|
|
120
|
+
isMine,
|
|
121
|
+
screenW: SCREEN.width,
|
|
122
|
+
screenH: SCREEN.height,
|
|
123
|
+
popupItemWidth: 42,
|
|
124
|
+
popupHeight: 60,
|
|
125
|
+
menuWidth,
|
|
126
|
+
menuItemCount: (onReply ? 1 : 0) + (isFile && onDownload ? 1 : 0) + (onDelete ? 1 : 0),
|
|
127
|
+
menuItemHeight: 44,
|
|
128
|
+
verticalGap: 12,
|
|
129
|
+
horizontalMargin: 8,
|
|
130
|
+
reactionCoreWidth: 28,
|
|
131
|
+
reactionHorizontalPadding: 8,
|
|
132
|
+
popupHorizontalPadding: 12,
|
|
133
|
+
});
|
|
134
|
+
left = positions.emojiPanel.left;
|
|
135
|
+
top = positions.emojiPanel.top;
|
|
136
|
+
menuLeft = positions.menu.left;
|
|
137
|
+
menuTop = positions.menu.top;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Fallback to previous behavior (unchanged)
|
|
141
|
+
const popupWidth = reactions.length * 42;
|
|
142
|
+
const popupHeight = 60;
|
|
143
|
+
const screenW = SCREEN.width;
|
|
144
|
+
top = pos.y - popupHeight - 12;
|
|
145
|
+
left = pos.x + pos.width / 2 - popupWidth / 2;
|
|
146
|
+
if (isMine) {
|
|
147
|
+
left = pos.x + pos.width - popupWidth - utils_1.appSize.width(6.5);
|
|
148
|
+
}
|
|
149
|
+
left = clamp(left, 10, screenW - popupWidth - 10);
|
|
150
|
+
menuTop = pos.y + pos.height + 10;
|
|
151
|
+
let _menuLeft = isMine ? (pos.x + pos.width - menuWidth) : pos.x;
|
|
152
|
+
menuLeft = clamp(_menuLeft, 10, screenW - menuWidth - 10);
|
|
153
|
+
}
|
|
154
|
+
siblingRef.current = new react_native_root_siblings_1.default(((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.overlayContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: react_native_1.StyleSheet.absoluteFill, onPress: hidePopup, children: (0, jsx_runtime_1.jsx)(UniversalBlurView_1.UniversalBlurView, { style: react_native_1.StyleSheet.absoluteFill, blurType: 'dark', blurAmount: 12, tint: "dark", intensity: 60, reducedTransparencyFallbackColor: "#000000CC" }) }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [
|
|
155
|
+
styles.messageDuplicateWrapper,
|
|
156
|
+
{
|
|
157
|
+
top: pos.y,
|
|
158
|
+
left: pos.x,
|
|
159
|
+
width: pos.width,
|
|
160
|
+
},
|
|
161
|
+
], children: children }), (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { entering: react_native_reanimated_1.ZoomIn.duration(100), exiting: react_native_reanimated_1.ZoomOut.duration(100), style: {
|
|
162
|
+
position: 'absolute',
|
|
163
|
+
top,
|
|
164
|
+
left,
|
|
165
|
+
}, children: (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [styles.popup, bubbleStyle, animStyle], children: reactions.map((r, i) => ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => handleReactionPress(r), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.reaction, reactionStyle], children: r }) }, i))) }) }), (0, jsx_runtime_1.jsxs)(react_native_reanimated_1.default.View, { entering: react_native_reanimated_1.ZoomIn.duration(150).delay(50), exiting: react_native_reanimated_1.ZoomOut.duration(150), style: [
|
|
166
|
+
styles.contextMenu,
|
|
167
|
+
{
|
|
168
|
+
top: menuTop,
|
|
169
|
+
left: menuLeft,
|
|
170
|
+
width: menuWidth,
|
|
171
|
+
}
|
|
172
|
+
], children: [onReply && ((0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { style: styles.menuItem, onPress: () => { hidePopup(); onReply(); }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.menuText, children: "Reply" }), (0, jsx_runtime_1.jsx)(Icons_1.ReplyIcon, { size: 18, color: "#fff" })] })), isFile && onDownload && ((0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { style: styles.menuItem, onPress: () => { hidePopup(); onDownload(); }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.menuText, children: "Download" }), (0, jsx_runtime_1.jsx)(Icons_1.DownloadIcon, { size: 18, color: "#fff" })] })), onDelete && ((0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { style: [styles.menuItem, { borderBottomWidth: 0 }], onPress: () => { hidePopup(); onDelete(); }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.menuText, { color: theme_1.defaultTheme.colors.darkRed }], children: "Delete" }), (0, jsx_runtime_1.jsx)(Icons_1.TrashIcon, { size: 18 })] }))] })] })));
|
|
173
|
+
requestAnimationFrame(() => {
|
|
174
|
+
scale.value = 1;
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
const hidePopup = () => {
|
|
178
|
+
if (siblingRef.current) {
|
|
179
|
+
siblingRef.current.destroy();
|
|
180
|
+
siblingRef.current = null;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const handleLongPress = () => {
|
|
184
|
+
const node = (0, react_native_1.findNodeHandle)(triggerRef.current);
|
|
185
|
+
if (!node)
|
|
186
|
+
return;
|
|
187
|
+
react_native_1.UIManager.measureInWindow(node, (x, y, width, height) => {
|
|
188
|
+
showPopup({ x, y, width, height });
|
|
189
|
+
});
|
|
190
|
+
if (onLongPress) {
|
|
191
|
+
onLongPress();
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const handleReactionPress = (reaction) => {
|
|
195
|
+
hidePopup();
|
|
196
|
+
onReactionPress(reaction);
|
|
197
|
+
};
|
|
198
|
+
(0, react_1.useEffect)(() => {
|
|
199
|
+
return hidePopup;
|
|
200
|
+
}, []);
|
|
201
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { children: [(0, jsx_runtime_1.jsx)(react_native_1.Pressable, { ref: triggerRef, onPress: onPress, onLongPress: handleLongPress, style: ({ pressed }) => [
|
|
202
|
+
style,
|
|
203
|
+
{
|
|
204
|
+
backgroundColor: pressed ? highlightColor : style === null || style === void 0 ? void 0 : style.backgroundColor,
|
|
205
|
+
},
|
|
206
|
+
], ...rest, children: children }), selectedReaction && ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: () => onReactionPress(undefined), children: (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [styles.miniReaction, { backgroundColor: theme.colors.primary }], children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { children: selectedReaction }) }) }))] }));
|
|
207
|
+
}
|
|
208
|
+
const styles = react_native_1.StyleSheet.create({
|
|
209
|
+
overlayContainer: {
|
|
210
|
+
...react_native_1.StyleSheet.absoluteFillObject,
|
|
211
|
+
zIndex: 99999,
|
|
212
|
+
},
|
|
213
|
+
messageDuplicateWrapper: {
|
|
214
|
+
position: 'absolute',
|
|
215
|
+
zIndex: 50,
|
|
216
|
+
},
|
|
217
|
+
popup: {
|
|
218
|
+
flexDirection: 'row',
|
|
219
|
+
paddingVertical: 8,
|
|
220
|
+
paddingHorizontal: 12,
|
|
221
|
+
borderRadius: 40,
|
|
222
|
+
backgroundColor: '#202A30',
|
|
223
|
+
zIndex: 100,
|
|
224
|
+
},
|
|
225
|
+
reaction: {
|
|
226
|
+
fontSize: 28,
|
|
227
|
+
paddingHorizontal: 8,
|
|
228
|
+
},
|
|
229
|
+
miniReaction: {
|
|
230
|
+
marginStart: 8,
|
|
231
|
+
padding: 4,
|
|
232
|
+
borderRadius: 100,
|
|
233
|
+
width: utils_1.appSize.width(8),
|
|
234
|
+
height: utils_1.appSize.width(8),
|
|
235
|
+
backgroundColor: theme_1.defaultTheme.colors.primary,
|
|
236
|
+
top: -4,
|
|
237
|
+
alignItems: 'center',
|
|
238
|
+
justifyContent: 'center',
|
|
239
|
+
},
|
|
240
|
+
contextMenu: {
|
|
241
|
+
position: 'absolute',
|
|
242
|
+
backgroundColor: 'rgba(30, 30, 30, 0.95)',
|
|
243
|
+
borderRadius: 12,
|
|
244
|
+
paddingVertical: 4,
|
|
245
|
+
width: 200,
|
|
246
|
+
zIndex: 100,
|
|
247
|
+
},
|
|
248
|
+
menuItem: {
|
|
249
|
+
flexDirection: 'row',
|
|
250
|
+
alignItems: 'center',
|
|
251
|
+
justifyContent: 'space-between',
|
|
252
|
+
paddingVertical: 12,
|
|
253
|
+
paddingHorizontal: 16,
|
|
254
|
+
borderBottomWidth: react_native_1.StyleSheet.hairlineWidth,
|
|
255
|
+
borderBottomColor: 'rgba(255, 255, 255, 0.1)',
|
|
256
|
+
},
|
|
257
|
+
menuText: {
|
|
258
|
+
color: '#fff',
|
|
259
|
+
fontSize: 16,
|
|
260
|
+
fontWeight: '400',
|
|
261
|
+
},
|
|
262
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const theme_1 = require("../utils/theme");
|
|
7
|
+
const Icons_1 = require("./Icons");
|
|
8
|
+
const ReplyPreview = ({ replyTo }) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const theme = (0, theme_1.useTheme)();
|
|
11
|
+
if (!replyTo)
|
|
12
|
+
return null;
|
|
13
|
+
const senderName = ((_a = replyTo.user) === null || _a === void 0 ? void 0 : _a.name) || 'Unknown';
|
|
14
|
+
const fileType = (_b = replyTo.fileType) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
15
|
+
const caption = replyTo.caption || '';
|
|
16
|
+
const text = replyTo.text || '';
|
|
17
|
+
const getFileNameFromUrl = (url) => {
|
|
18
|
+
console.log('url', url);
|
|
19
|
+
if (!url)
|
|
20
|
+
return undefined;
|
|
21
|
+
try {
|
|
22
|
+
const clean = url.split('?')[0];
|
|
23
|
+
const parts = clean.split('/');
|
|
24
|
+
const last = parts[parts.length - 1];
|
|
25
|
+
return last || undefined;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const getExtension = (name) => {
|
|
32
|
+
if (!name)
|
|
33
|
+
return undefined;
|
|
34
|
+
const ext = name.split('.').pop();
|
|
35
|
+
return ext ? ext.toLowerCase() : undefined;
|
|
36
|
+
};
|
|
37
|
+
const computedFileName = replyTo.fileName || getFileNameFromUrl(replyTo.fileUrl);
|
|
38
|
+
const extension = getExtension(computedFileName);
|
|
39
|
+
const isMedia = fileType === 'image' || fileType === 'video' || !!replyTo.image || !!replyTo.video;
|
|
40
|
+
const isFile = !!computedFileName || fileType === 'audio' || fileType === 'file' || !!replyTo.audio;
|
|
41
|
+
const renderMedia = () => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.mediaRow, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.textWrapper, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.senderName, { color: theme.colors.darkPrimary }], children: senderName }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: !caption && fileType ? { minWidth: '100%' } : null, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.captionText, { color: theme.colors.gray }], children: caption || (fileType === 'image' || replyTo.image ? 'Photo' : 'Video') }) })] }), fileType === 'image' || replyTo.image ? ((0, jsx_runtime_1.jsx)(react_native_1.Image, { source: { uri: replyTo.image || replyTo.fileUrl }, style: styles.mediaThumb, resizeMode: "cover" })) : ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.mediaThumb, children: (0, jsx_runtime_1.jsx)(Icons_1.VideoIcon, { size: 30, color: theme.colors.white }) }))] }));
|
|
42
|
+
const renderFileRow = () => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.fileRow, children: [fileType === 'audio' ||
|
|
43
|
+
replyTo.audio ||
|
|
44
|
+
(extension && ['mp3', 'wav', 'm4a', 'aac', 'ogg'].includes(extension)) ? ((0, jsx_runtime_1.jsx)(Icons_1.AudioIcon, { size: 18, color: theme.colors.gray })) : ((0, jsx_runtime_1.jsx)(Icons_1.FileIcon, { size: 18, color: theme.colors.gray })), (0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.fileName, { color: theme.colors.gray }], children: computedFileName || (extension ? extension.toUpperCase() : fileType || 'File') })] }));
|
|
45
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [styles.container, { backgroundColor: theme.colors.softRed }], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.borderIndicator, { backgroundColor: theme.colors.primary }] }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.textWrapper, children: isMedia ? (renderMedia()) : isFile ? (renderFileRow()) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.senderName, { color: theme.colors.darkPrimary }], children: senderName }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.textSnippet, { color: theme.colors.darkBrown }], children: text })] })) })] }));
|
|
46
|
+
};
|
|
47
|
+
const styles = react_native_1.StyleSheet.create({
|
|
48
|
+
container: {
|
|
49
|
+
flexDirection: 'row',
|
|
50
|
+
backgroundColor: theme_1.defaultTheme.colors.softRed,
|
|
51
|
+
padding: utils_1.appSize.width(1.5),
|
|
52
|
+
borderRadius: utils_1.appSize.width(2),
|
|
53
|
+
width: 'auto',
|
|
54
|
+
maxWidth: '100%',
|
|
55
|
+
marginVertical: utils_1.appSize.height(0.5),
|
|
56
|
+
},
|
|
57
|
+
borderIndicator: {
|
|
58
|
+
width: 3,
|
|
59
|
+
backgroundColor: theme_1.defaultTheme.colors.primary,
|
|
60
|
+
borderRadius: 3,
|
|
61
|
+
marginRight: 8,
|
|
62
|
+
},
|
|
63
|
+
textWrapper: {
|
|
64
|
+
flexShrink: 1,
|
|
65
|
+
},
|
|
66
|
+
senderName: {
|
|
67
|
+
fontSize: utils_1.appSize.font(11),
|
|
68
|
+
fontWeight: '600',
|
|
69
|
+
color: theme_1.defaultTheme.colors.darkPrimary,
|
|
70
|
+
},
|
|
71
|
+
textSnippet: {
|
|
72
|
+
fontSize: utils_1.appSize.font(13),
|
|
73
|
+
color: theme_1.defaultTheme.colors.darkBrown,
|
|
74
|
+
},
|
|
75
|
+
mediaRow: {
|
|
76
|
+
flexDirection: 'row',
|
|
77
|
+
alignItems: 'center',
|
|
78
|
+
},
|
|
79
|
+
captionText: {
|
|
80
|
+
fontSize: utils_1.appSize.font(12),
|
|
81
|
+
color: theme_1.defaultTheme.colors.gray,
|
|
82
|
+
},
|
|
83
|
+
mediaThumb: {
|
|
84
|
+
width: utils_1.appSize.width(10),
|
|
85
|
+
height: utils_1.appSize.width(10),
|
|
86
|
+
borderRadius: 6,
|
|
87
|
+
marginLeft: 10,
|
|
88
|
+
overflow: 'hidden',
|
|
89
|
+
backgroundColor: '#ccc',
|
|
90
|
+
justifyContent: 'center',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
},
|
|
93
|
+
fileRow: {
|
|
94
|
+
flexDirection: 'row',
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
},
|
|
97
|
+
fileName: {
|
|
98
|
+
marginLeft: 6,
|
|
99
|
+
color: theme_1.defaultTheme.colors.gray,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
exports.default = ReplyPreview;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const react_native_safe_area_context_1 = require("react-native-safe-area-context");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const theme_1 = require("../utils/theme");
|
|
8
|
+
const Icons_1 = require("./Icons");
|
|
9
|
+
const uploadOptions = [
|
|
10
|
+
{ id: '1', label: 'Image', icon: Icons_1.ImageIcon },
|
|
11
|
+
{ id: '2', label: 'Video', icon: Icons_1.VideoIcon },
|
|
12
|
+
{ id: '3', label: 'Document', icon: Icons_1.FileIcon },
|
|
13
|
+
];
|
|
14
|
+
const UploadFooter = ({ onActionPress, }) => {
|
|
15
|
+
const inset = (0, react_native_safe_area_context_1.useSafeAreaInsets)();
|
|
16
|
+
const theme = (0, theme_1.useTheme)();
|
|
17
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.container, { backgroundColor: theme.colors.verySoftGray }, { paddingBottom: inset.bottom + 20 }], children: uploadOptions.map(item => {
|
|
18
|
+
const Icon = item.icon;
|
|
19
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: styles.iconBox, onPress: () => onActionPress(item.label), children: (0, jsx_runtime_1.jsx)(Icon, { size: 22, color: theme.colors.darkRed }) }, item.id));
|
|
20
|
+
}) }));
|
|
21
|
+
};
|
|
22
|
+
const styles = react_native_1.StyleSheet.create({
|
|
23
|
+
container: {
|
|
24
|
+
flexDirection: 'row',
|
|
25
|
+
padding: utils_1.appSize.width(3),
|
|
26
|
+
backgroundColor: theme_1.defaultTheme.colors.verySoftGray,
|
|
27
|
+
justifyContent: 'space-between',
|
|
28
|
+
},
|
|
29
|
+
iconBox: {
|
|
30
|
+
padding: 10,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
exports.default = UploadFooter;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/adapters/UniversalAudio.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.AudioEngine = void 0;
|
|
5
|
+
let ExpoAudio = null;
|
|
6
|
+
let RNSound = null;
|
|
7
|
+
// Try expo-audio first
|
|
8
|
+
try {
|
|
9
|
+
ExpoAudio = require('expo-audio');
|
|
10
|
+
}
|
|
11
|
+
catch { }
|
|
12
|
+
// Fallback to react-native-sound
|
|
13
|
+
if (!ExpoAudio) {
|
|
14
|
+
try {
|
|
15
|
+
RNSound = require('react-native-sound');
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
}
|
|
19
|
+
exports.AudioEngine = {
|
|
20
|
+
type: ExpoAudio ? 'expo-audio' : RNSound ? 'rnsound' : 'none',
|
|
21
|
+
ExpoAudio,
|
|
22
|
+
RNSound,
|
|
23
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UniversalBlurView = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_native_1 = require("react-native");
|
|
6
|
+
let NativeBlurView = null;
|
|
7
|
+
// Try Expo Blur first (Expo Go / Expo Dev Client)
|
|
8
|
+
try {
|
|
9
|
+
NativeBlurView = require('expo-blur').BlurView;
|
|
10
|
+
}
|
|
11
|
+
catch { }
|
|
12
|
+
// Fallback to community blur (Bare RN)
|
|
13
|
+
if (!NativeBlurView) {
|
|
14
|
+
try {
|
|
15
|
+
NativeBlurView = require('@react-native-community/blur').BlurView;
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
}
|
|
19
|
+
const UniversalBlurView = (props) => {
|
|
20
|
+
if (NativeBlurView) {
|
|
21
|
+
return (0, jsx_runtime_1.jsx)(NativeBlurView, { ...props });
|
|
22
|
+
}
|
|
23
|
+
// Final fallback (no blur installed)
|
|
24
|
+
return (0, jsx_runtime_1.jsx)(react_native_1.View, { ...props });
|
|
25
|
+
};
|
|
26
|
+
exports.UniversalBlurView = UniversalBlurView;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VideoEngine = void 0;
|
|
4
|
+
let ExpoVideo = null;
|
|
5
|
+
let RNVideo = null;
|
|
6
|
+
try {
|
|
7
|
+
ExpoVideo = require('expo-video');
|
|
8
|
+
}
|
|
9
|
+
catch { }
|
|
10
|
+
if (!ExpoVideo) {
|
|
11
|
+
try {
|
|
12
|
+
RNVideo = require('react-native-video').default;
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
15
|
+
}
|
|
16
|
+
exports.VideoEngine = {
|
|
17
|
+
type: ExpoVideo ? 'expo-video' : RNVideo ? 'rn-video' : 'none',
|
|
18
|
+
ExpoVideo,
|
|
19
|
+
RNVideo,
|
|
20
|
+
};
|