@adminide-stack/yantra-mobile 12.0.105 → 12.0.106-alpha.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/lib/features/messaging/BlockedContactsScreen.js +127 -0
- package/lib/features/messaging/BlockedContactsScreen.js.map +1 -0
- package/lib/features/messaging/ChatAttachments.js +4 -2
- package/lib/features/messaging/ChatAttachments.js.map +1 -1
- package/lib/features/messaging/ChatComponents.js +194 -10
- package/lib/features/messaging/ChatComponents.js.map +1 -1
- package/lib/features/messaging/ChatInfoScreen.js +173 -17
- package/lib/features/messaging/ChatInfoScreen.js.map +1 -1
- package/lib/features/messaging/ConversationListScreen.js +17 -1
- package/lib/features/messaging/ConversationListScreen.js.map +1 -1
- package/lib/features/messaging/MediaGalleryScreen.js +264 -0
- package/lib/features/messaging/MediaGalleryScreen.js.map +1 -0
- package/lib/features/messaging/NativeChatExperience.js +137 -18
- package/lib/features/messaging/NativeChatExperience.js.map +1 -1
- package/lib/features/messaging/NewGroupScreen.js +191 -0
- package/lib/features/messaging/NewGroupScreen.js.map +1 -0
- package/lib/features/messaging/PollComposer.js +137 -0
- package/lib/features/messaging/PollComposer.js.map +1 -0
- package/lib/features/messaging/PollVotesScreen.js +122 -0
- package/lib/features/messaging/PollVotesScreen.js.map +1 -0
- package/lib/features/messaging/ThreadScreen.js +180 -13
- package/lib/features/messaging/ThreadScreen.js.map +1 -1
- package/lib/features/messaging/chatLinks.js +39 -2
- package/lib/features/messaging/chatLinks.js.map +1 -1
- package/lib/features/messaging/chatModel.js +186 -19
- package/lib/features/messaging/chatModel.js.map +1 -1
- package/lib/features/messaging/chatOperations.js +111 -2
- package/lib/features/messaging/chatOperations.js.map +1 -1
- package/lib/features/messaging/nativeChatChannelQuery.js +7 -2
- package/lib/features/messaging/nativeChatChannelQuery.js.map +1 -1
- package/lib/features/messaging/useChatData.js +248 -10
- package/lib/features/messaging/useChatData.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {jsxs,jsx}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,View,Pressable,Text,ActivityIndicator,FlatList}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {MaterialCommunityIcons}from'@expo/vector-icons';import {InlineBanner,Avatar,EmptyState}from'./ChatComponents.js';import {BLOCKED_CONTACTS_QUERY}from'./chatOperations.js';function BlockedContactsScreen({
|
|
2
|
+
gql,
|
|
3
|
+
theme,
|
|
4
|
+
onBack,
|
|
5
|
+
onUnblock
|
|
6
|
+
}) {
|
|
7
|
+
const [rows, setRows] = React.useState(null);
|
|
8
|
+
const [error, setError] = React.useState(null);
|
|
9
|
+
React.useEffect(() => {
|
|
10
|
+
let alive = true;
|
|
11
|
+
void (async () => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
const res = await gql.query(BLOCKED_CONTACTS_QUERY, {}, {
|
|
14
|
+
fetchPolicy: "network-only"
|
|
15
|
+
}).catch(() => null);
|
|
16
|
+
if (!alive) return;
|
|
17
|
+
if ((_a = res == null ? void 0 : res.errors) == null ? void 0 : _a.length) setError("Couldn\u2019t load your blocked contacts.");
|
|
18
|
+
const raw = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b.blockedContacts;
|
|
19
|
+
const list = Array.isArray(raw) ? raw : [];
|
|
20
|
+
setRows(list.map((r) => {
|
|
21
|
+
var _a2, _b2, _c, _d;
|
|
22
|
+
return {
|
|
23
|
+
userId: String((_a2 = r == null ? void 0 : r.userId) != null ? _a2 : ""),
|
|
24
|
+
name: String((_c = (_b2 = r == null ? void 0 : r.displayName) != null ? _b2 : r == null ? void 0 : r.username) != null ? _c : "Unknown"),
|
|
25
|
+
picture: (_d = r == null ? void 0 : r.picture) != null ? _d : null
|
|
26
|
+
};
|
|
27
|
+
}).filter((r) => r.userId));
|
|
28
|
+
})();
|
|
29
|
+
return () => {
|
|
30
|
+
alive = false;
|
|
31
|
+
};
|
|
32
|
+
}, [gql]);
|
|
33
|
+
const unblock = (userId) => {
|
|
34
|
+
const before = rows;
|
|
35
|
+
setRows((prev) => prev ? prev.filter((r) => r.userId !== userId) : prev);
|
|
36
|
+
void (async () => {
|
|
37
|
+
const ok = await onUnblock(userId);
|
|
38
|
+
if (!ok) {
|
|
39
|
+
setRows(before);
|
|
40
|
+
setError("Couldn\u2019t unblock this contact.");
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
};
|
|
44
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles.fill, {
|
|
45
|
+
backgroundColor: theme.bg
|
|
46
|
+
}], testID: "chat-blocked", children: [
|
|
47
|
+
/* @__PURE__ */ jsx(SafeAreaView, { edges: ["top"], style: {
|
|
48
|
+
backgroundColor: theme.headerBg
|
|
49
|
+
}, children: /* @__PURE__ */ jsxs(View, { style: [styles.header, {
|
|
50
|
+
borderBottomColor: theme.border,
|
|
51
|
+
flexDirection: "row"
|
|
52
|
+
}], children: [
|
|
53
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onBack, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Back", style: styles.headerIcon, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "chevron-left", size: 32, color: theme.accent }) }),
|
|
54
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.title, {
|
|
55
|
+
color: theme.text
|
|
56
|
+
}], children: "Blocked contacts" }),
|
|
57
|
+
/* @__PURE__ */ jsx(View, { style: styles.headerIcon })
|
|
58
|
+
] }) }),
|
|
59
|
+
/* @__PURE__ */ jsx(InlineBanner, { message: error, theme, onDismiss: () => setError(null) }),
|
|
60
|
+
rows === null ? /* @__PURE__ */ jsx(View, { style: styles.center, children: /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.accent }) }) : /* @__PURE__ */ jsx(FlatList, { data: rows, keyExtractor: (r) => r.userId, contentContainerStyle: rows.length ? void 0 : styles.fill, ListEmptyComponent: /* @__PURE__ */ jsx(EmptyState, { icon: "account-cancel-outline", title: "No blocked contacts", detail: "Blocked contacts can no longer send you messages. Block someone from their chat info.", theme }), renderItem: ({
|
|
61
|
+
item
|
|
62
|
+
}) => /* @__PURE__ */ jsxs(View, { style: [styles.row, {
|
|
63
|
+
borderBottomColor: theme.border,
|
|
64
|
+
flexDirection: "row"
|
|
65
|
+
}], children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Avatar, { name: item.name, uri: item.picture, theme, size: 40, variant: "initials" }),
|
|
67
|
+
/* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.name, {
|
|
68
|
+
color: theme.text
|
|
69
|
+
}], children: item.name }),
|
|
70
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: () => unblock(item.userId), hitSlop: 8, accessibilityRole: "button", accessibilityLabel: `Unblock ${item.name}`, style: [styles.unblock, {
|
|
71
|
+
borderColor: theme.accent
|
|
72
|
+
}], children: /* @__PURE__ */ jsx(Text, { style: [styles.unblockText, {
|
|
73
|
+
color: theme.accent
|
|
74
|
+
}], children: "Unblock" }) })
|
|
75
|
+
] }) })
|
|
76
|
+
] });
|
|
77
|
+
}
|
|
78
|
+
const styles = StyleSheet.create({
|
|
79
|
+
fill: {
|
|
80
|
+
flex: 1
|
|
81
|
+
},
|
|
82
|
+
center: {
|
|
83
|
+
flex: 1,
|
|
84
|
+
alignItems: "center",
|
|
85
|
+
justifyContent: "center"
|
|
86
|
+
},
|
|
87
|
+
header: {
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
justifyContent: "space-between",
|
|
90
|
+
paddingHorizontal: 4,
|
|
91
|
+
minHeight: 52,
|
|
92
|
+
borderBottomWidth: StyleSheet.hairlineWidth
|
|
93
|
+
},
|
|
94
|
+
headerIcon: {
|
|
95
|
+
width: 44,
|
|
96
|
+
height: 44,
|
|
97
|
+
alignItems: "center",
|
|
98
|
+
justifyContent: "center"
|
|
99
|
+
},
|
|
100
|
+
title: {
|
|
101
|
+
fontSize: 17,
|
|
102
|
+
fontWeight: "600"
|
|
103
|
+
},
|
|
104
|
+
row: {
|
|
105
|
+
alignItems: "center",
|
|
106
|
+
paddingHorizontal: 16,
|
|
107
|
+
paddingVertical: 10,
|
|
108
|
+
borderBottomWidth: StyleSheet.hairlineWidth
|
|
109
|
+
},
|
|
110
|
+
name: {
|
|
111
|
+
flex: 1,
|
|
112
|
+
fontSize: 16,
|
|
113
|
+
fontWeight: "500",
|
|
114
|
+
marginLeft: 12,
|
|
115
|
+
marginRight: 8
|
|
116
|
+
},
|
|
117
|
+
unblock: {
|
|
118
|
+
borderWidth: 1,
|
|
119
|
+
borderRadius: 16,
|
|
120
|
+
paddingHorizontal: 14,
|
|
121
|
+
paddingVertical: 6
|
|
122
|
+
},
|
|
123
|
+
unblockText: {
|
|
124
|
+
fontSize: 14,
|
|
125
|
+
fontWeight: "600"
|
|
126
|
+
}
|
|
127
|
+
});export{BlockedContactsScreen};//# sourceMappingURL=BlockedContactsScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockedContactsScreen.js","sources":["../../../src/features/messaging/BlockedContactsScreen.tsx"],"sourcesContent":["/**\n * Blocked contacts, WhatsApp-style: everyone the viewer has blocked, each with an Unblock\n * button. Blocking is one-directional and silent; this screen is the one place to reverse it.\n */\nimport * as React from 'react';\nimport { ActivityIndicator, FlatList, Pressable, StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { Avatar, EmptyState, InlineBanner, type ChatTheme } from './ChatComponents';\nimport type { ChatGraphQLSeam } from './chatHost';\nimport { BLOCKED_CONTACTS_QUERY } from './chatOperations';\n\ninterface BlockedRow {\n userId: string;\n name: string;\n picture: string | null;\n}\n\nexport function BlockedContactsScreen({\n gql,\n theme,\n onBack,\n onUnblock,\n}: {\n gql: ChatGraphQLSeam;\n theme: ChatTheme;\n onBack: () => void;\n /** Unblock a contact; resolves true on success so the row can leave the list. */\n onUnblock: (userId: string) => Promise<boolean>;\n}) {\n const [rows, setRows] = React.useState<BlockedRow[] | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n\n React.useEffect(() => {\n let alive = true;\n void (async () => {\n const res = await gql\n .query<{ blockedContacts?: unknown }>(BLOCKED_CONTACTS_QUERY, {}, { fetchPolicy: 'network-only' })\n .catch(() => null);\n if (!alive) return;\n if (res?.errors?.length) setError('Couldn’t load your blocked contacts.');\n const raw = res?.data?.blockedContacts;\n const list: Array<Record<string, unknown>> = Array.isArray(raw)\n ? (raw as Array<Record<string, unknown>>)\n : [];\n setRows(\n list\n .map((r) => ({\n userId: String(r?.userId ?? ''),\n name: String(r?.displayName ?? r?.username ?? 'Unknown'),\n picture: (r?.picture as string | null) ?? null,\n }))\n .filter((r) => r.userId),\n );\n })();\n return () => {\n alive = false;\n };\n }, [gql]);\n\n const unblock = (userId: string) => {\n // Optimistic: drop the row; restore it if the server rejects.\n const before = rows;\n setRows((prev) => (prev ? prev.filter((r) => r.userId !== userId) : prev));\n void (async () => {\n const ok = await onUnblock(userId);\n if (!ok) {\n setRows(before);\n setError('Couldn’t unblock this contact.');\n }\n })();\n };\n\n return (\n <View style={[styles.fill, { backgroundColor: theme.bg }]} testID=\"chat-blocked\">\n <SafeAreaView edges={['top']} style={{ backgroundColor: theme.headerBg }}>\n <View style={[styles.header, { borderBottomColor: theme.border, flexDirection: 'row' }]}>\n <Pressable\n onPress={onBack}\n hitSlop={10}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Back\"\n style={styles.headerIcon}\n >\n <MaterialCommunityIcons name=\"chevron-left\" size={32} color={theme.accent} />\n </Pressable>\n <Text style={[styles.title, { color: theme.text }]}>Blocked contacts</Text>\n <View style={styles.headerIcon} />\n </View>\n </SafeAreaView>\n <InlineBanner message={error} theme={theme} onDismiss={() => setError(null)} />\n {rows === null ? (\n <View style={styles.center}>\n <ActivityIndicator color={theme.accent} />\n </View>\n ) : (\n <FlatList\n data={rows}\n keyExtractor={(r) => r.userId}\n contentContainerStyle={rows.length ? undefined : styles.fill}\n ListEmptyComponent={\n <EmptyState\n icon=\"account-cancel-outline\"\n title=\"No blocked contacts\"\n detail=\"Blocked contacts can no longer send you messages. Block someone from their chat info.\"\n theme={theme}\n />\n }\n renderItem={({ item }) => (\n <View style={[styles.row, { borderBottomColor: theme.border, flexDirection: 'row' }]}>\n <Avatar name={item.name} uri={item.picture} theme={theme} size={40} variant=\"initials\" />\n <Text numberOfLines={1} style={[styles.name, { color: theme.text }]}>\n {item.name}\n </Text>\n <Pressable\n onPress={() => unblock(item.userId)}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel={`Unblock ${item.name}`}\n style={[styles.unblock, { borderColor: theme.accent }]}\n >\n <Text style={[styles.unblockText, { color: theme.accent }]}>Unblock</Text>\n </Pressable>\n </View>\n )}\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center' },\n header: {\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 4,\n minHeight: 52,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n headerIcon: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center' },\n title: { fontSize: 17, fontWeight: '600' },\n row: {\n alignItems: 'center',\n paddingHorizontal: 16,\n paddingVertical: 10,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n name: { flex: 1, fontSize: 16, fontWeight: '500', marginLeft: 12, marginRight: 8 },\n unblock: { borderWidth: 1, borderRadius: 16, paddingHorizontal: 14, paddingVertical: 6 },\n unblockText: { fontSize: 14, fontWeight: '600' },\n});\n"],"names":["_a","_b"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {jsx,jsxs}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,
|
|
1
|
+
import {jsx,jsxs}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,Modal,View,Pressable,ScrollView,Text,ActivityIndicator}from'react-native';import {Image}from'expo-image';import {MaterialCommunityIcons}from'@expo/vector-icons';import {SafeAreaProvider,SafeAreaView}from'react-native-safe-area-context';import {TapRow}from'./TapRow.js';import {attachmentUrl}from'./chatModel.js';const IMAGE_MAX = 240;
|
|
2
2
|
function durationLabel(ms) {
|
|
3
3
|
const total = Math.max(0, Math.round((ms != null ? ms : 0) / 1e3));
|
|
4
4
|
return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, "0")}`;
|
|
@@ -126,6 +126,7 @@ function AttachSheet({
|
|
|
126
126
|
onClose,
|
|
127
127
|
onPhotos,
|
|
128
128
|
onCamera,
|
|
129
|
+
onPoll,
|
|
129
130
|
onDismissed
|
|
130
131
|
}) {
|
|
131
132
|
const row = (icon, label, run) => /* @__PURE__ */ jsx(TapRow, { onPress: run, accessibilityRole: "button", accessibilityLabel: label, pressedColor: theme.surface, children: /* @__PURE__ */ jsxs(View, { style: [styles.sheetRow, {
|
|
@@ -147,7 +148,8 @@ function AttachSheet({
|
|
|
147
148
|
backgroundColor: theme.border
|
|
148
149
|
}] }),
|
|
149
150
|
row("image-multiple-outline", "Photos", onPhotos),
|
|
150
|
-
row("camera-outline", "Camera", onCamera)
|
|
151
|
+
row("camera-outline", "Camera", onCamera),
|
|
152
|
+
onPoll ? row("poll", "Poll", onPoll) : null
|
|
151
153
|
] })
|
|
152
154
|
] });
|
|
153
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatAttachments.js","sources":["../../../src/features/messaging/ChatAttachments.tsx"],"sourcesContent":["/**\n * Attachments in the chat: photos and voice notes inside bubbles, the full-screen photo viewer,\n * and the composer pieces (the \"+\" menu, picked photos, the recording bar).\n *\n * Plain react-native + expo-image only (host-shared); picking, uploading, recording and playback\n * all go through the host seams (`ChatMediaSeam`, `ChatAudioSeam`).\n */\nimport * as React from 'react';\nimport { ActivityIndicator, Modal, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { Image } from 'expo-image';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';\nimport type { ChatTheme } from './ChatComponents';\nimport { TapRow } from './TapRow';\nimport type { ChatAudioSeam, ChatPickedImage } from './chatHost';\nimport { attachmentUrl, type ChatAttachment } from './chatModel';\n\nconst IMAGE_MAX = 240;\n\nexport function durationLabel(ms: number | null | undefined): string {\n const total = Math.max(0, Math.round((ms ?? 0) / 1000));\n return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, '0')}`;\n}\n\nfunction imageSize(a: ChatAttachment): { width: number; height: number } {\n const w = a.width ?? 0;\n const h = a.height ?? 0;\n if (!w || !h) return { width: IMAGE_MAX, height: IMAGE_MAX * 0.75 };\n const scale = Math.min(IMAGE_MAX / w, IMAGE_MAX / h);\n return { width: Math.max(120, Math.round(w * scale)), height: Math.max(90, Math.round(h * scale)) };\n}\n\n/** Photos and voice notes of one message. */\nexport function MessageAttachments({\n attachments,\n mine,\n theme,\n fileBaseUrl,\n audio,\n uploading,\n onOpenImage,\n}: {\n attachments: ChatAttachment[];\n mine: boolean;\n theme: ChatTheme;\n fileBaseUrl?: string | null;\n audio?: ChatAudioSeam;\n /** Still sending: shows a spinner over photos. */\n uploading?: boolean;\n onOpenImage?: (url: string) => void;\n}) {\n const images = attachments.filter((a) => a.kind === 'image');\n const voices = attachments.filter((a) => a.kind === 'audio');\n const others = attachments.filter((a) => a.kind === 'file');\n const textColor = mine ? theme.bubbleMineText : theme.bubbleTheirsText;\n\n return (\n <View>\n {images.length ? (\n <View style={[styles.imageGrid, { flexDirection: 'row' }]}>\n {images.map((a) => {\n const url = attachmentUrl(a, fileBaseUrl);\n const size = images.length === 1 ? imageSize(a) : { width: 116, height: 116 };\n return (\n <Pressable\n key={a.id}\n onPress={onOpenImage ? () => onOpenImage(url) : undefined}\n accessibilityRole=\"imagebutton\"\n accessibilityLabel=\"Photo\"\n >\n <Image\n source={{ uri: url }}\n style={[styles.image, size, { backgroundColor: theme.surface }]}\n contentFit=\"cover\"\n transition={120}\n />\n {uploading ? (\n <View style={[StyleSheet.absoluteFill, styles.imageOverlay]}>\n <ActivityIndicator color=\"#ffffff\" />\n </View>\n ) : null}\n </Pressable>\n );\n })}\n </View>\n ) : null}\n {voices.map((a) => (\n <VoiceNote\n key={a.id}\n url={attachmentUrl(a, fileBaseUrl)}\n durationMs={a.durationMs}\n audio={audio}\n color={textColor}\n accent={mine ? textColor : theme.accent}\n disabled={uploading}\n />\n ))}\n {others.map((a) => (\n <View key={a.id} style={[styles.fileRow, { flexDirection: 'row' }]}>\n <MaterialCommunityIcons name=\"file-outline\" size={20} color={textColor} />\n <Text numberOfLines={1} style={[styles.fileName, { color: textColor }]}>\n {a.name}\n </Text>\n </View>\n ))}\n </View>\n );\n}\n\nfunction VoiceNote({\n url,\n durationMs,\n audio,\n color,\n accent,\n disabled,\n}: {\n url: string;\n durationMs?: number | null;\n audio?: ChatAudioSeam;\n color: string;\n accent: string;\n disabled?: boolean;\n}) {\n const [playing, setPlaying] = React.useState(false);\n const stopRef = React.useRef<(() => void) | null>(null);\n\n React.useEffect(() => () => stopRef.current?.(), []);\n\n const toggle = React.useCallback(async () => {\n if (!audio) return;\n if (playing) {\n stopRef.current?.();\n stopRef.current = null;\n setPlaying(false);\n return;\n }\n setPlaying(true);\n try {\n stopRef.current = await audio.play(url, () => {\n stopRef.current = null;\n setPlaying(false);\n });\n } catch {\n setPlaying(false);\n }\n }, [audio, playing, url]);\n\n return (\n <View style={[styles.voice, { flexDirection: 'row' }]}>\n <Pressable\n onPress={() => void toggle()}\n disabled={!audio || disabled}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel={playing ? 'Pause voice message' : 'Play voice message'}\n >\n <MaterialCommunityIcons name={playing ? 'pause-circle' : 'play-circle'} size={34} color={accent} />\n </Pressable>\n <View style={[styles.voiceWave, { flexDirection: 'row' }]}>\n {WAVE.map((h, i) => (\n <View key={i} style={[styles.voiceBar, { height: h, backgroundColor: color, opacity: 0.55 }]} />\n ))}\n </View>\n <Text style={[styles.voiceTime, { color }]}>{durationLabel(durationMs)}</Text>\n </View>\n );\n}\n\nconst WAVE = [6, 12, 18, 10, 22, 14, 8, 16, 24, 12, 6, 14, 20, 10, 16, 8, 12, 18];\n\n/** Full-screen photo, tap anywhere or ✕ to close. */\nexport function ImageViewer({ url, onClose }: { url: string | null; onClose: () => void }) {\n return (\n <Modal visible={Boolean(url)} transparent animationType=\"fade\" statusBarTranslucent onRequestClose={onClose}>\n {/* A Modal is a new native root: without its own provider the safe-area insets read 0\n (first open), and the ✕ lands under the status bar where it cannot be tapped. */}\n <SafeAreaProvider>\n <View style={styles.viewer}>\n {url ? (\n <Pressable style={StyleSheet.absoluteFill} onPress={onClose} accessibilityLabel=\"Close photo\">\n <Image source={{ uri: url }} style={StyleSheet.absoluteFill} contentFit=\"contain\" />\n </Pressable>\n ) : null}\n <SafeAreaView edges={['top']} style={styles.viewerTop} pointerEvents=\"box-none\">\n <Pressable\n onPress={onClose}\n hitSlop={16}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Close\"\n style={styles.viewerClose}\n testID=\"chat-image-viewer-close\"\n >\n <MaterialCommunityIcons name=\"close\" size={24} color=\"#ffffff\" />\n </Pressable>\n </SafeAreaView>\n </View>\n </SafeAreaProvider>\n </Modal>\n );\n}\n\n/** The \"+\" menu: Photos and Camera, like iMessage's app drawer rows. */\nexport function AttachSheet({\n visible,\n theme,\n onClose,\n onPhotos,\n onCamera,\n onDismissed,\n}: {\n visible: boolean;\n theme: ChatTheme;\n onClose: () => void;\n onPhotos: () => void;\n onCamera: () => void;\n /** iOS: the sheet is fully gone - only now can the photo picker be presented. */\n onDismissed?: () => void;\n}) {\n const row = (icon: React.ComponentProps<typeof MaterialCommunityIcons>['name'], label: string, run: () => void) => (\n <TapRow onPress={run} accessibilityRole=\"button\" accessibilityLabel={label} pressedColor={theme.surface}>\n <View style={[styles.sheetRow, { flexDirection: 'row' }]}>\n <View style={[styles.sheetIcon, { backgroundColor: theme.surface }]}>\n <MaterialCommunityIcons name={icon} size={22} color={theme.accent} />\n </View>\n <Text style={[styles.sheetLabel, { color: theme.text }]}>{label}</Text>\n </View>\n </TapRow>\n );\n return (\n <Modal visible={visible} transparent animationType=\"slide\" onRequestClose={onClose} onDismiss={onDismissed}>\n <Pressable style={styles.sheetBackdrop} onPress={onClose} accessibilityLabel=\"Close\" />\n <SafeAreaView edges={['bottom']} style={[styles.sheet, { backgroundColor: theme.bg }]}>\n <View style={[styles.sheetHandle, { backgroundColor: theme.border }]} />\n {row('image-multiple-outline', 'Photos', onPhotos)}\n {row('camera-outline', 'Camera', onCamera)}\n </SafeAreaView>\n </Modal>\n );\n}\n\n/** Photos picked for the next message, each removable. */\nexport function StagedAttachments({\n files,\n theme,\n onRemove,\n}: {\n files: ChatPickedImage[];\n theme: ChatTheme;\n onRemove: (index: number) => void;\n}) {\n if (!files.length) return null;\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n // ScrollView grows by default (flexGrow: 1) and would push the transcript up.\n style={[styles.stagedBar, { backgroundColor: theme.composerBar }]}\n contentContainerStyle={styles.staged}\n >\n {files.map((f, i) => (\n <View key={`${f.uri}-${i}`} style={styles.stagedItem}>\n <Image source={{ uri: f.uri }} style={styles.stagedImage} contentFit=\"cover\" />\n <Pressable\n onPress={() => onRemove(i)}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Remove photo\"\n style={styles.stagedRemove}\n >\n <MaterialCommunityIcons name=\"close-circle\" size={20} color=\"#ffffff\" />\n </Pressable>\n </View>\n ))}\n </ScrollView>\n );\n}\n\n/** Replaces the text field while recording: cancel, a live timer, send. */\nexport function RecordingBar({\n theme,\n startedAt,\n onCancel,\n onSend,\n}: {\n theme: ChatTheme;\n startedAt: number;\n onCancel: () => void;\n onSend: () => void;\n}) {\n const [now, setNow] = React.useState(Date.now());\n React.useEffect(() => {\n const t = setInterval(() => setNow(Date.now()), 250);\n return () => clearInterval(t);\n }, []);\n return (\n <View style={[styles.recording, { flexDirection: 'row', backgroundColor: theme.composerBar }]}>\n <Pressable\n onPress={onCancel}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Cancel recording\"\n style={styles.recordingButton}\n >\n <MaterialCommunityIcons name=\"close\" size={26} color={theme.textMuted} />\n </Pressable>\n <View\n style={[\n styles.recordingPill,\n { flexDirection: 'row', backgroundColor: theme.bg, borderColor: theme.border },\n ]}\n >\n <View style={[styles.recordingDot, { backgroundColor: theme.danger }]} />\n <Text style={[styles.recordingTime, { color: theme.text }]}>{durationLabel(now - startedAt)}</Text>\n <Text style={[styles.recordingHint, { color: theme.textMuted }]}>Recording…</Text>\n </View>\n <Pressable\n onPress={onSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send voice message\"\n style={[styles.recordingSend, { backgroundColor: theme.accent }]}\n testID=\"chat-voice-send\"\n >\n <MaterialCommunityIcons name=\"arrow-up\" size={22} color={theme.onAccent} />\n </Pressable>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n imageGrid: { flexWrap: 'wrap', gap: 4, marginVertical: 2 },\n image: { borderRadius: 12 },\n imageOverlay: {\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0,0,0,0.25)',\n borderRadius: 12,\n },\n fileRow: { alignItems: 'center', paddingVertical: 4, maxWidth: 220 },\n fileName: { marginLeft: 6, fontSize: 15, flexShrink: 1 },\n voice: { alignItems: 'center', paddingVertical: 2, paddingHorizontal: 6, minWidth: 200 },\n voiceWave: { alignItems: 'center', flex: 1, marginHorizontal: 8, gap: 2 },\n voiceBar: { width: 3, borderRadius: 2 },\n voiceTime: { fontSize: 13, fontVariant: ['tabular-nums'] },\n viewer: { flex: 1, backgroundColor: '#000000' },\n viewerTop: { position: 'absolute', top: 0, left: 0, right: 0, paddingHorizontal: 16, paddingTop: 8, zIndex: 2 },\n viewerClose: {\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(255,255,255,0.18)',\n },\n sheetBackdrop: { flex: 1, backgroundColor: 'rgba(15, 23, 42, 0.35)' },\n sheet: { borderTopLeftRadius: 16, borderTopRightRadius: 16, paddingTop: 8, paddingBottom: 8 },\n sheetHandle: { alignSelf: 'center', width: 36, height: 5, borderRadius: 3, marginBottom: 8 },\n sheetRow: { alignItems: 'center', paddingHorizontal: 20, paddingVertical: 12 },\n sheetIcon: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center' },\n sheetLabel: { fontSize: 17, marginLeft: 14 },\n stagedBar: { flexGrow: 0, flexShrink: 0 },\n staged: { paddingHorizontal: 12, paddingTop: 8, gap: 8 },\n stagedItem: { width: 72, height: 72 },\n stagedImage: { width: 72, height: 72, borderRadius: 10 },\n stagedRemove: { position: 'absolute', top: 2, right: 2, backgroundColor: 'rgba(0,0,0,0.45)', borderRadius: 10 },\n recording: { alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 },\n recordingButton: { width: 36, height: 36, alignItems: 'center', justifyContent: 'center' },\n recordingPill: {\n flex: 1,\n alignItems: 'center',\n minHeight: 38,\n borderRadius: 20,\n borderWidth: StyleSheet.hairlineWidth,\n paddingHorizontal: 12,\n marginHorizontal: 6,\n },\n recordingDot: { width: 10, height: 10, borderRadius: 5 },\n recordingTime: { fontSize: 16, marginLeft: 8, fontVariant: ['tabular-nums'] },\n recordingHint: { fontSize: 15, marginLeft: 10 },\n recordingSend: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center' },\n});\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatAttachments.js","sources":["../../../src/features/messaging/ChatAttachments.tsx"],"sourcesContent":["/**\n * Attachments in the chat: photos and voice notes inside bubbles, the full-screen photo viewer,\n * and the composer pieces (the \"+\" menu, picked photos, the recording bar).\n *\n * Plain react-native + expo-image only (host-shared); picking, uploading, recording and playback\n * all go through the host seams (`ChatMediaSeam`, `ChatAudioSeam`).\n */\nimport * as React from 'react';\nimport { ActivityIndicator, Modal, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { Image } from 'expo-image';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';\nimport type { ChatTheme } from './ChatComponents';\nimport { TapRow } from './TapRow';\nimport type { ChatAudioSeam, ChatPickedImage } from './chatHost';\nimport { attachmentUrl, type ChatAttachment } from './chatModel';\n\nconst IMAGE_MAX = 240;\n\nexport function durationLabel(ms: number | null | undefined): string {\n const total = Math.max(0, Math.round((ms ?? 0) / 1000));\n return `${Math.floor(total / 60)}:${String(total % 60).padStart(2, '0')}`;\n}\n\nfunction imageSize(a: ChatAttachment): { width: number; height: number } {\n const w = a.width ?? 0;\n const h = a.height ?? 0;\n if (!w || !h) return { width: IMAGE_MAX, height: IMAGE_MAX * 0.75 };\n const scale = Math.min(IMAGE_MAX / w, IMAGE_MAX / h);\n return { width: Math.max(120, Math.round(w * scale)), height: Math.max(90, Math.round(h * scale)) };\n}\n\n/** Photos and voice notes of one message. */\nexport function MessageAttachments({\n attachments,\n mine,\n theme,\n fileBaseUrl,\n audio,\n uploading,\n onOpenImage,\n}: {\n attachments: ChatAttachment[];\n mine: boolean;\n theme: ChatTheme;\n fileBaseUrl?: string | null;\n audio?: ChatAudioSeam;\n /** Still sending: shows a spinner over photos. */\n uploading?: boolean;\n onOpenImage?: (url: string) => void;\n}) {\n const images = attachments.filter((a) => a.kind === 'image');\n const voices = attachments.filter((a) => a.kind === 'audio');\n const others = attachments.filter((a) => a.kind === 'file');\n const textColor = mine ? theme.bubbleMineText : theme.bubbleTheirsText;\n\n return (\n <View>\n {images.length ? (\n <View style={[styles.imageGrid, { flexDirection: 'row' }]}>\n {images.map((a) => {\n const url = attachmentUrl(a, fileBaseUrl);\n const size = images.length === 1 ? imageSize(a) : { width: 116, height: 116 };\n return (\n <Pressable\n key={a.id}\n onPress={onOpenImage ? () => onOpenImage(url) : undefined}\n accessibilityRole=\"imagebutton\"\n accessibilityLabel=\"Photo\"\n >\n <Image\n source={{ uri: url }}\n style={[styles.image, size, { backgroundColor: theme.surface }]}\n contentFit=\"cover\"\n transition={120}\n />\n {uploading ? (\n <View style={[StyleSheet.absoluteFill, styles.imageOverlay]}>\n <ActivityIndicator color=\"#ffffff\" />\n </View>\n ) : null}\n </Pressable>\n );\n })}\n </View>\n ) : null}\n {voices.map((a) => (\n <VoiceNote\n key={a.id}\n url={attachmentUrl(a, fileBaseUrl)}\n durationMs={a.durationMs}\n audio={audio}\n color={textColor}\n accent={mine ? textColor : theme.accent}\n disabled={uploading}\n />\n ))}\n {others.map((a) => (\n <View key={a.id} style={[styles.fileRow, { flexDirection: 'row' }]}>\n <MaterialCommunityIcons name=\"file-outline\" size={20} color={textColor} />\n <Text numberOfLines={1} style={[styles.fileName, { color: textColor }]}>\n {a.name}\n </Text>\n </View>\n ))}\n </View>\n );\n}\n\nfunction VoiceNote({\n url,\n durationMs,\n audio,\n color,\n accent,\n disabled,\n}: {\n url: string;\n durationMs?: number | null;\n audio?: ChatAudioSeam;\n color: string;\n accent: string;\n disabled?: boolean;\n}) {\n const [playing, setPlaying] = React.useState(false);\n const stopRef = React.useRef<(() => void) | null>(null);\n\n React.useEffect(() => () => stopRef.current?.(), []);\n\n const toggle = React.useCallback(async () => {\n if (!audio) return;\n if (playing) {\n stopRef.current?.();\n stopRef.current = null;\n setPlaying(false);\n return;\n }\n setPlaying(true);\n try {\n stopRef.current = await audio.play(url, () => {\n stopRef.current = null;\n setPlaying(false);\n });\n } catch {\n setPlaying(false);\n }\n }, [audio, playing, url]);\n\n return (\n <View style={[styles.voice, { flexDirection: 'row' }]}>\n <Pressable\n onPress={() => void toggle()}\n disabled={!audio || disabled}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel={playing ? 'Pause voice message' : 'Play voice message'}\n >\n <MaterialCommunityIcons name={playing ? 'pause-circle' : 'play-circle'} size={34} color={accent} />\n </Pressable>\n <View style={[styles.voiceWave, { flexDirection: 'row' }]}>\n {WAVE.map((h, i) => (\n <View key={i} style={[styles.voiceBar, { height: h, backgroundColor: color, opacity: 0.55 }]} />\n ))}\n </View>\n <Text style={[styles.voiceTime, { color }]}>{durationLabel(durationMs)}</Text>\n </View>\n );\n}\n\nconst WAVE = [6, 12, 18, 10, 22, 14, 8, 16, 24, 12, 6, 14, 20, 10, 16, 8, 12, 18];\n\n/** Full-screen photo, tap anywhere or ✕ to close. */\nexport function ImageViewer({ url, onClose }: { url: string | null; onClose: () => void }) {\n return (\n <Modal visible={Boolean(url)} transparent animationType=\"fade\" statusBarTranslucent onRequestClose={onClose}>\n {/* A Modal is a new native root: without its own provider the safe-area insets read 0\n (first open), and the ✕ lands under the status bar where it cannot be tapped. */}\n <SafeAreaProvider>\n <View style={styles.viewer}>\n {url ? (\n <Pressable style={StyleSheet.absoluteFill} onPress={onClose} accessibilityLabel=\"Close photo\">\n <Image source={{ uri: url }} style={StyleSheet.absoluteFill} contentFit=\"contain\" />\n </Pressable>\n ) : null}\n <SafeAreaView edges={['top']} style={styles.viewerTop} pointerEvents=\"box-none\">\n <Pressable\n onPress={onClose}\n hitSlop={16}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Close\"\n style={styles.viewerClose}\n testID=\"chat-image-viewer-close\"\n >\n <MaterialCommunityIcons name=\"close\" size={24} color=\"#ffffff\" />\n </Pressable>\n </SafeAreaView>\n </View>\n </SafeAreaProvider>\n </Modal>\n );\n}\n\n/** The \"+\" menu: Photos and Camera, like iMessage's app drawer rows. */\nexport function AttachSheet({\n visible,\n theme,\n onClose,\n onPhotos,\n onCamera,\n onPoll,\n onDismissed,\n}: {\n visible: boolean;\n theme: ChatTheme;\n onClose: () => void;\n onPhotos: () => void;\n onCamera: () => void;\n /** Opens the poll composer. Omitted where polls are unavailable. */\n onPoll?: () => void;\n /** iOS: the sheet is fully gone - only now can the photo picker be presented. */\n onDismissed?: () => void;\n}) {\n const row = (icon: React.ComponentProps<typeof MaterialCommunityIcons>['name'], label: string, run: () => void) => (\n <TapRow onPress={run} accessibilityRole=\"button\" accessibilityLabel={label} pressedColor={theme.surface}>\n <View style={[styles.sheetRow, { flexDirection: 'row' }]}>\n <View style={[styles.sheetIcon, { backgroundColor: theme.surface }]}>\n <MaterialCommunityIcons name={icon} size={22} color={theme.accent} />\n </View>\n <Text style={[styles.sheetLabel, { color: theme.text }]}>{label}</Text>\n </View>\n </TapRow>\n );\n return (\n <Modal visible={visible} transparent animationType=\"slide\" onRequestClose={onClose} onDismiss={onDismissed}>\n <Pressable style={styles.sheetBackdrop} onPress={onClose} accessibilityLabel=\"Close\" />\n <SafeAreaView edges={['bottom']} style={[styles.sheet, { backgroundColor: theme.bg }]}>\n <View style={[styles.sheetHandle, { backgroundColor: theme.border }]} />\n {row('image-multiple-outline', 'Photos', onPhotos)}\n {row('camera-outline', 'Camera', onCamera)}\n {onPoll ? row('poll', 'Poll', onPoll) : null}\n </SafeAreaView>\n </Modal>\n );\n}\n\n/** Photos picked for the next message, each removable. */\nexport function StagedAttachments({\n files,\n theme,\n onRemove,\n}: {\n files: ChatPickedImage[];\n theme: ChatTheme;\n onRemove: (index: number) => void;\n}) {\n if (!files.length) return null;\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n // ScrollView grows by default (flexGrow: 1) and would push the transcript up.\n style={[styles.stagedBar, { backgroundColor: theme.composerBar }]}\n contentContainerStyle={styles.staged}\n >\n {files.map((f, i) => (\n <View key={`${f.uri}-${i}`} style={styles.stagedItem}>\n <Image source={{ uri: f.uri }} style={styles.stagedImage} contentFit=\"cover\" />\n <Pressable\n onPress={() => onRemove(i)}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Remove photo\"\n style={styles.stagedRemove}\n >\n <MaterialCommunityIcons name=\"close-circle\" size={20} color=\"#ffffff\" />\n </Pressable>\n </View>\n ))}\n </ScrollView>\n );\n}\n\n/** Replaces the text field while recording: cancel, a live timer, send. */\nexport function RecordingBar({\n theme,\n startedAt,\n onCancel,\n onSend,\n}: {\n theme: ChatTheme;\n startedAt: number;\n onCancel: () => void;\n onSend: () => void;\n}) {\n const [now, setNow] = React.useState(Date.now());\n React.useEffect(() => {\n const t = setInterval(() => setNow(Date.now()), 250);\n return () => clearInterval(t);\n }, []);\n return (\n <View style={[styles.recording, { flexDirection: 'row', backgroundColor: theme.composerBar }]}>\n <Pressable\n onPress={onCancel}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Cancel recording\"\n style={styles.recordingButton}\n >\n <MaterialCommunityIcons name=\"close\" size={26} color={theme.textMuted} />\n </Pressable>\n <View\n style={[\n styles.recordingPill,\n { flexDirection: 'row', backgroundColor: theme.bg, borderColor: theme.border },\n ]}\n >\n <View style={[styles.recordingDot, { backgroundColor: theme.danger }]} />\n <Text style={[styles.recordingTime, { color: theme.text }]}>{durationLabel(now - startedAt)}</Text>\n <Text style={[styles.recordingHint, { color: theme.textMuted }]}>Recording…</Text>\n </View>\n <Pressable\n onPress={onSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send voice message\"\n style={[styles.recordingSend, { backgroundColor: theme.accent }]}\n testID=\"chat-voice-send\"\n >\n <MaterialCommunityIcons name=\"arrow-up\" size={22} color={theme.onAccent} />\n </Pressable>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n imageGrid: { flexWrap: 'wrap', gap: 4, marginVertical: 2 },\n image: { borderRadius: 12 },\n imageOverlay: {\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0,0,0,0.25)',\n borderRadius: 12,\n },\n fileRow: { alignItems: 'center', paddingVertical: 4, maxWidth: 220 },\n fileName: { marginLeft: 6, fontSize: 15, flexShrink: 1 },\n voice: { alignItems: 'center', paddingVertical: 2, paddingHorizontal: 6, minWidth: 200 },\n voiceWave: { alignItems: 'center', flex: 1, marginHorizontal: 8, gap: 2 },\n voiceBar: { width: 3, borderRadius: 2 },\n voiceTime: { fontSize: 13, fontVariant: ['tabular-nums'] },\n viewer: { flex: 1, backgroundColor: '#000000' },\n viewerTop: { position: 'absolute', top: 0, left: 0, right: 0, paddingHorizontal: 16, paddingTop: 8, zIndex: 2 },\n viewerClose: {\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(255,255,255,0.18)',\n },\n sheetBackdrop: { flex: 1, backgroundColor: 'rgba(15, 23, 42, 0.35)' },\n sheet: { borderTopLeftRadius: 16, borderTopRightRadius: 16, paddingTop: 8, paddingBottom: 8 },\n sheetHandle: { alignSelf: 'center', width: 36, height: 5, borderRadius: 3, marginBottom: 8 },\n sheetRow: { alignItems: 'center', paddingHorizontal: 20, paddingVertical: 12 },\n sheetIcon: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center' },\n sheetLabel: { fontSize: 17, marginLeft: 14 },\n stagedBar: { flexGrow: 0, flexShrink: 0 },\n staged: { paddingHorizontal: 12, paddingTop: 8, gap: 8 },\n stagedItem: { width: 72, height: 72 },\n stagedImage: { width: 72, height: 72, borderRadius: 10 },\n stagedRemove: { position: 'absolute', top: 2, right: 2, backgroundColor: 'rgba(0,0,0,0.45)', borderRadius: 10 },\n recording: { alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 },\n recordingButton: { width: 36, height: 36, alignItems: 'center', justifyContent: 'center' },\n recordingPill: {\n flex: 1,\n alignItems: 'center',\n minHeight: 38,\n borderRadius: 20,\n borderWidth: StyleSheet.hairlineWidth,\n paddingHorizontal: 12,\n marginHorizontal: 6,\n },\n recordingDot: { width: 10, height: 10, borderRadius: 5 },\n recordingTime: { fontSize: 16, marginLeft: 8, fontVariant: ['tabular-nums'] },\n recordingHint: { fontSize: 15, marginLeft: 10 },\n recordingSend: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center' },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {jsxs,jsx}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,View,Text,Pressable,ActivityIndicator}from'react-native';import {Image}from'expo-image';import {MaterialCommunityIcons}from'@expo/vector-icons';import {initialsOf,timeLabel,isMuted,relativeLabel}from'./chatModel.js';import {MessageAttachments}from'./ChatAttachments.js';import {
|
|
1
|
+
import {jsxs,jsx}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,View,Text,Pressable,ActivityIndicator}from'react-native';import {Image}from'expo-image';import {MaterialCommunityIcons}from'@expo/vector-icons';import {initialsOf,timeLabel,isMuted,relativeLabel}from'./chatModel.js';import {MessageAttachments}from'./ChatAttachments.js';import {splitChatParts,firstLink,isOnlyALink}from'./chatLinks.js';import {useLinkPreview,LinkPreviewCard}from'./LinkPreviewCard.js';import {usePressed}from'./usePressed.js';var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -275,6 +275,9 @@ function ConversationRow({
|
|
|
275
275
|
marginLeft: 4
|
|
276
276
|
} }) : null,
|
|
277
277
|
conversation.pinnedAt > 0 ? /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "pin", size: 16, color: theme.textMuted, accessibilityLabel: "Pinned", style: styles.pinIcon }) : null,
|
|
278
|
+
conversation.unreadMentions > 0 ? /* @__PURE__ */ jsx(View, { style: styles.mentionBadge, accessibilityLabel: "mention badge", children: /* @__PURE__ */ jsx(Text, { style: [styles.mentionBadgeText, {
|
|
279
|
+
color: theme.accent
|
|
280
|
+
}], children: "@" }) }) : null,
|
|
278
281
|
/* @__PURE__ */ jsx(UnreadBadge, { count: conversation.unreadCount, theme, muted })
|
|
279
282
|
] })
|
|
280
283
|
] })
|
|
@@ -318,6 +321,67 @@ function BubbleTail({
|
|
|
318
321
|
borderTopColor: color
|
|
319
322
|
}] });
|
|
320
323
|
}
|
|
324
|
+
function PollView({
|
|
325
|
+
poll,
|
|
326
|
+
mine,
|
|
327
|
+
theme,
|
|
328
|
+
onVote,
|
|
329
|
+
onViewVotes
|
|
330
|
+
}) {
|
|
331
|
+
const total = poll.options.reduce((n, o) => n + o.count, 0);
|
|
332
|
+
const textColor = mine ? theme.bubbleMineText : theme.bubbleTheirsText;
|
|
333
|
+
const metaColor = mine ? theme.metaMine : theme.metaTheirs;
|
|
334
|
+
const trackBg = theme.isDark ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.06)";
|
|
335
|
+
return /* @__PURE__ */ jsxs(View, { style: styles.poll, children: [
|
|
336
|
+
/* @__PURE__ */ jsxs(View, { style: {
|
|
337
|
+
flexDirection: "row",
|
|
338
|
+
alignItems: "center"
|
|
339
|
+
}, children: [
|
|
340
|
+
/* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "poll", size: 13, color: metaColor }),
|
|
341
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.pollKicker, {
|
|
342
|
+
color: metaColor
|
|
343
|
+
}], children: poll.multiple ? "Select one or more" : "Select one" })
|
|
344
|
+
] }),
|
|
345
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.pollQuestion, {
|
|
346
|
+
color: textColor
|
|
347
|
+
}], children: poll.question }),
|
|
348
|
+
poll.options.map((o) => {
|
|
349
|
+
const pct = total > 0 ? Math.round(o.count / total * 100) : 0;
|
|
350
|
+
return /* @__PURE__ */ jsxs(Pressable, { onPress: onVote ? () => onVote(o.id) : void 0, disabled: !onVote, accessibilityRole: "button", accessibilityState: {
|
|
351
|
+
selected: o.mine
|
|
352
|
+
}, accessibilityLabel: `${o.text}, ${o.count} ${o.count === 1 ? "vote" : "votes"}${o.mine ? ", selected" : ""}`, style: [styles.pollOption, {
|
|
353
|
+
flexDirection: "row"
|
|
354
|
+
}], children: [
|
|
355
|
+
/* @__PURE__ */ jsx(View, { style: [styles.pollCheck, {
|
|
356
|
+
borderColor: o.mine ? theme.accent : metaColor,
|
|
357
|
+
backgroundColor: o.mine ? theme.accent : "transparent"
|
|
358
|
+
}], children: o.mine ? /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "check", size: 12, color: "#ffffff" }) : null }),
|
|
359
|
+
/* @__PURE__ */ jsxs(View, { style: styles.pollOptionBody, children: [
|
|
360
|
+
/* @__PURE__ */ jsxs(View, { style: {
|
|
361
|
+
flexDirection: "row",
|
|
362
|
+
justifyContent: "space-between"
|
|
363
|
+
}, children: [
|
|
364
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.pollOptionText, {
|
|
365
|
+
color: textColor
|
|
366
|
+
}], numberOfLines: 4, children: o.text }),
|
|
367
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.pollCount, {
|
|
368
|
+
color: metaColor
|
|
369
|
+
}], children: o.count })
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ jsx(View, { style: [styles.pollBarTrack, {
|
|
372
|
+
backgroundColor: trackBg
|
|
373
|
+
}], children: /* @__PURE__ */ jsx(View, { style: [styles.pollBarFill, {
|
|
374
|
+
backgroundColor: theme.accent,
|
|
375
|
+
width: `${pct}%`
|
|
376
|
+
}] }) })
|
|
377
|
+
] })
|
|
378
|
+
] }, o.id);
|
|
379
|
+
}),
|
|
380
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onViewVotes, disabled: !onViewVotes, accessibilityRole: "button", hitSlop: 6, children: /* @__PURE__ */ jsx(Text, { style: [styles.pollFooter, {
|
|
381
|
+
color: theme.accent
|
|
382
|
+
}], children: `${total} ${total === 1 ? "vote" : "votes"}${onViewVotes ? " \xB7 View votes" : ""}` }) })
|
|
383
|
+
] });
|
|
384
|
+
}
|
|
321
385
|
function MessageBubble({
|
|
322
386
|
message,
|
|
323
387
|
theme,
|
|
@@ -333,15 +397,18 @@ function MessageBubble({
|
|
|
333
397
|
audio,
|
|
334
398
|
onOpenImage,
|
|
335
399
|
linkPreviews,
|
|
336
|
-
onOpenLink
|
|
400
|
+
onOpenLink,
|
|
401
|
+
onVote,
|
|
402
|
+
onViewVotes
|
|
337
403
|
}) {
|
|
338
|
-
var _a, _b;
|
|
404
|
+
var _a, _b, _c;
|
|
339
405
|
const bubbleRef = React.useRef(null);
|
|
340
406
|
const reactions = (_a = message.reactions) != null ? _a : [];
|
|
341
407
|
const mine = message.isMine;
|
|
342
408
|
const failed = message.sendState === "failed";
|
|
343
409
|
const body = message.body.trim();
|
|
344
|
-
const
|
|
410
|
+
const hasMentions = Boolean((_b = message.mentions) == null ? void 0 : _b.length);
|
|
411
|
+
const parts = React.useMemo(() => splitChatParts(body, hasMentions), [body, hasMentions]);
|
|
345
412
|
const cardUrl = React.useMemo(() => message.isDeleted ? null : firstLink(body), [body, message.isDeleted]);
|
|
346
413
|
const preview = useLinkPreview(cardUrl, linkPreviews);
|
|
347
414
|
const onlyLink = Boolean(preview) && !message.attachments.length && isOnlyALink(body);
|
|
@@ -395,16 +462,27 @@ function MessageBubble({
|
|
|
395
462
|
}], children: "Forwarded" })
|
|
396
463
|
] }) : null,
|
|
397
464
|
showAuthor && !mine ? /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.author, message.attachments.length || onlyLink ? styles.authorOverMedia : null, {
|
|
398
|
-
color: personColor((
|
|
465
|
+
color: personColor((_c = message.authorId) != null ? _c : message.authorName, theme)
|
|
399
466
|
}], children: message.authorName }) : null,
|
|
400
467
|
message.replyTo ? /* @__PURE__ */ jsx(ReplyQuote, { reply: message.replyTo, theme, viewerId, onPress: onPressQuote ? () => onPressQuote(message.replyTo.id) : void 0 }) : null,
|
|
401
468
|
message.attachments.length ? /* @__PURE__ */ jsx(MessageAttachments, { attachments: message.attachments, mine, theme, fileBaseUrl, audio, uploading: message.sendState === "sending", onOpenImage }) : null,
|
|
402
|
-
|
|
469
|
+
message.poll ? /* @__PURE__ */ jsx(PollView, { poll: message.poll, mine, theme, onVote, onViewVotes }) : null,
|
|
470
|
+
body && !onlyLink && !message.poll ? /* @__PURE__ */ jsxs(Text, { style: [styles.bubbleText, {
|
|
403
471
|
color: textColor
|
|
404
472
|
}, message.attachments.length ? styles.bubbleCaption : null], children: [
|
|
405
|
-
parts.map((part, i) =>
|
|
406
|
-
|
|
407
|
-
|
|
473
|
+
parts.map((part, i) => {
|
|
474
|
+
if (part.kind === "link") {
|
|
475
|
+
return /* @__PURE__ */ jsx(Text, { style: [styles.linkText, {
|
|
476
|
+
color: theme.isDark ? "#53bdeb" : "#027eb5"
|
|
477
|
+
}], onPress: onOpenLink ? () => onOpenLink(part.url) : void 0, accessibilityRole: "link", children: part.text }, i);
|
|
478
|
+
}
|
|
479
|
+
if (part.kind === "mention") {
|
|
480
|
+
return /* @__PURE__ */ jsx(Text, { style: [styles.mentionText, {
|
|
481
|
+
color: theme.accent
|
|
482
|
+
}], children: part.text }, i);
|
|
483
|
+
}
|
|
484
|
+
return part.text;
|
|
485
|
+
}),
|
|
408
486
|
/* @__PURE__ */ jsx(Text, { style: styles.metaSpacer, children: `\u2002\u2002${message.starred ? "\u2003" : ""}${meta}${showTicks ? "\u2003\u2002" : ""}` })
|
|
409
487
|
] }) : null,
|
|
410
488
|
preview ? /* @__PURE__ */ jsx(View, { style: onlyLink ? null : styles.cardBelowText, children: /* @__PURE__ */ jsx(LinkPreviewCard, { preview, theme, onOpen: onOpenLink }) }) : null,
|
|
@@ -413,6 +491,7 @@ function MessageBubble({
|
|
|
413
491
|
flexDirection: "row",
|
|
414
492
|
alignItems: "center"
|
|
415
493
|
}], pointerEvents: "none", children: [
|
|
494
|
+
message.kept ? /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "bookmark", size: 11, color: metaOnMedia ? "#ffffff" : metaColor, accessibilityLabel: "Kept", style: styles.metaStar }) : null,
|
|
416
495
|
message.starred ? /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "star", size: 11, color: metaOnMedia ? "#ffffff" : metaColor, accessibilityLabel: "Starred", style: styles.metaStar }) : null,
|
|
417
496
|
/* @__PURE__ */ jsx(Text, { style: [styles.metaText, {
|
|
418
497
|
color: metaOnMedia ? "#ffffff" : metaColor
|
|
@@ -458,6 +537,20 @@ function DaySeparator({
|
|
|
458
537
|
color: theme.chipText
|
|
459
538
|
}], children: label }) }) });
|
|
460
539
|
}
|
|
540
|
+
function SystemRow({
|
|
541
|
+
text,
|
|
542
|
+
theme
|
|
543
|
+
}) {
|
|
544
|
+
if (!text) return null;
|
|
545
|
+
return /* @__PURE__ */ jsx(View, { style: [styles.daySep, {
|
|
546
|
+
flexDirection: "row",
|
|
547
|
+
justifyContent: "center"
|
|
548
|
+
}], children: /* @__PURE__ */ jsx(View, { style: [styles.systemChip, {
|
|
549
|
+
backgroundColor: theme.chipBg
|
|
550
|
+
}], children: /* @__PURE__ */ jsx(Text, { style: [styles.systemText, {
|
|
551
|
+
color: theme.chipText
|
|
552
|
+
}], children: text }) }) });
|
|
553
|
+
}
|
|
461
554
|
function UnreadDivider({
|
|
462
555
|
count,
|
|
463
556
|
theme
|
|
@@ -549,6 +642,14 @@ const styles = StyleSheet.create({
|
|
|
549
642
|
rotate: "45deg"
|
|
550
643
|
}]
|
|
551
644
|
},
|
|
645
|
+
mentionBadge: {
|
|
646
|
+
marginLeft: 6,
|
|
647
|
+
marginTop: 2
|
|
648
|
+
},
|
|
649
|
+
mentionBadgeText: {
|
|
650
|
+
fontSize: 15,
|
|
651
|
+
fontWeight: "700"
|
|
652
|
+
},
|
|
552
653
|
forwarded: {
|
|
553
654
|
marginBottom: 2
|
|
554
655
|
},
|
|
@@ -648,6 +749,67 @@ const styles = StyleSheet.create({
|
|
|
648
749
|
marginLeft: 3,
|
|
649
750
|
marginRight: 1
|
|
650
751
|
},
|
|
752
|
+
poll: {
|
|
753
|
+
paddingHorizontal: 6,
|
|
754
|
+
paddingTop: 4,
|
|
755
|
+
paddingBottom: 2,
|
|
756
|
+
minWidth: 220
|
|
757
|
+
},
|
|
758
|
+
pollKicker: {
|
|
759
|
+
fontSize: 12,
|
|
760
|
+
marginLeft: 4,
|
|
761
|
+
fontWeight: "500"
|
|
762
|
+
},
|
|
763
|
+
pollQuestion: {
|
|
764
|
+
fontSize: 16,
|
|
765
|
+
fontWeight: "600",
|
|
766
|
+
lineHeight: 21,
|
|
767
|
+
marginTop: 4,
|
|
768
|
+
marginBottom: 8
|
|
769
|
+
},
|
|
770
|
+
pollOption: {
|
|
771
|
+
alignItems: "flex-start",
|
|
772
|
+
marginBottom: 10
|
|
773
|
+
},
|
|
774
|
+
pollCheck: {
|
|
775
|
+
width: 20,
|
|
776
|
+
height: 20,
|
|
777
|
+
borderRadius: 10,
|
|
778
|
+
borderWidth: 1.5,
|
|
779
|
+
alignItems: "center",
|
|
780
|
+
justifyContent: "center",
|
|
781
|
+
marginRight: 10,
|
|
782
|
+
marginTop: 1
|
|
783
|
+
},
|
|
784
|
+
pollOptionBody: {
|
|
785
|
+
flex: 1
|
|
786
|
+
},
|
|
787
|
+
pollOptionText: {
|
|
788
|
+
fontSize: 15,
|
|
789
|
+
lineHeight: 20,
|
|
790
|
+
flex: 1,
|
|
791
|
+
marginRight: 8
|
|
792
|
+
},
|
|
793
|
+
pollCount: {
|
|
794
|
+
fontSize: 13,
|
|
795
|
+
fontWeight: "600"
|
|
796
|
+
},
|
|
797
|
+
pollBarTrack: {
|
|
798
|
+
height: 4,
|
|
799
|
+
borderRadius: 2,
|
|
800
|
+
marginTop: 5,
|
|
801
|
+
overflow: "hidden"
|
|
802
|
+
},
|
|
803
|
+
pollBarFill: {
|
|
804
|
+
height: 4,
|
|
805
|
+
borderRadius: 2
|
|
806
|
+
},
|
|
807
|
+
pollFooter: {
|
|
808
|
+
fontSize: 13,
|
|
809
|
+
fontWeight: "600",
|
|
810
|
+
marginTop: 2,
|
|
811
|
+
marginBottom: 2
|
|
812
|
+
},
|
|
651
813
|
deletedText: {
|
|
652
814
|
fontSize: 15,
|
|
653
815
|
fontStyle: "italic",
|
|
@@ -670,6 +832,9 @@ const styles = StyleSheet.create({
|
|
|
670
832
|
linkText: {
|
|
671
833
|
textDecorationLine: "underline"
|
|
672
834
|
},
|
|
835
|
+
mentionText: {
|
|
836
|
+
fontWeight: "600"
|
|
837
|
+
},
|
|
673
838
|
/** Invisible copy of the meta, sized like it, so text never runs under the time. */
|
|
674
839
|
metaSpacer: {
|
|
675
840
|
fontSize: 11,
|
|
@@ -763,6 +928,25 @@ const styles = StyleSheet.create({
|
|
|
763
928
|
fontSize: 12.5,
|
|
764
929
|
fontWeight: "500"
|
|
765
930
|
},
|
|
931
|
+
systemChip: {
|
|
932
|
+
maxWidth: "84%",
|
|
933
|
+
paddingHorizontal: 12,
|
|
934
|
+
paddingVertical: 6,
|
|
935
|
+
borderRadius: 8,
|
|
936
|
+
shadowColor: "#0b141a",
|
|
937
|
+
shadowOpacity: 0.1,
|
|
938
|
+
shadowRadius: 0.5,
|
|
939
|
+
shadowOffset: {
|
|
940
|
+
width: 0,
|
|
941
|
+
height: 1
|
|
942
|
+
},
|
|
943
|
+
elevation: 1
|
|
944
|
+
},
|
|
945
|
+
systemText: {
|
|
946
|
+
fontSize: 13,
|
|
947
|
+
lineHeight: 18,
|
|
948
|
+
textAlign: "center"
|
|
949
|
+
},
|
|
766
950
|
unreadBand: {
|
|
767
951
|
marginVertical: 10,
|
|
768
952
|
paddingVertical: 6,
|
|
@@ -829,4 +1013,4 @@ const styles = StyleSheet.create({
|
|
|
829
1013
|
fontSize: 15,
|
|
830
1014
|
fontWeight: "700"
|
|
831
1015
|
}
|
|
832
|
-
});export{Avatar,ConnectionBanner,ConversationRow,DaySeparator,EmptyState,InlineBanner,MessageBubble,MessageTicks,ReplyQuote,UnreadBadge,UnreadDivider,chatThemes,personColor};//# sourceMappingURL=ChatComponents.js.map
|
|
1016
|
+
});export{Avatar,ConnectionBanner,ConversationRow,DaySeparator,EmptyState,InlineBanner,MessageBubble,MessageTicks,ReplyQuote,SystemRow,UnreadBadge,UnreadDivider,chatThemes,personColor};//# sourceMappingURL=ChatComponents.js.map
|