@adminide-stack/yantra-mobile 12.0.105 → 12.0.106

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 (33) hide show
  1. package/lib/features/messaging/BlockedContactsScreen.js +127 -0
  2. package/lib/features/messaging/BlockedContactsScreen.js.map +1 -0
  3. package/lib/features/messaging/ChatAttachments.js +4 -2
  4. package/lib/features/messaging/ChatAttachments.js.map +1 -1
  5. package/lib/features/messaging/ChatComponents.js +194 -10
  6. package/lib/features/messaging/ChatComponents.js.map +1 -1
  7. package/lib/features/messaging/ChatInfoScreen.js +173 -17
  8. package/lib/features/messaging/ChatInfoScreen.js.map +1 -1
  9. package/lib/features/messaging/ConversationListScreen.js +17 -1
  10. package/lib/features/messaging/ConversationListScreen.js.map +1 -1
  11. package/lib/features/messaging/MediaGalleryScreen.js +264 -0
  12. package/lib/features/messaging/MediaGalleryScreen.js.map +1 -0
  13. package/lib/features/messaging/NativeChatExperience.js +137 -18
  14. package/lib/features/messaging/NativeChatExperience.js.map +1 -1
  15. package/lib/features/messaging/NewGroupScreen.js +191 -0
  16. package/lib/features/messaging/NewGroupScreen.js.map +1 -0
  17. package/lib/features/messaging/PollComposer.js +137 -0
  18. package/lib/features/messaging/PollComposer.js.map +1 -0
  19. package/lib/features/messaging/PollVotesScreen.js +122 -0
  20. package/lib/features/messaging/PollVotesScreen.js.map +1 -0
  21. package/lib/features/messaging/ThreadScreen.js +180 -13
  22. package/lib/features/messaging/ThreadScreen.js.map +1 -1
  23. package/lib/features/messaging/chatLinks.js +39 -2
  24. package/lib/features/messaging/chatLinks.js.map +1 -1
  25. package/lib/features/messaging/chatModel.js +186 -19
  26. package/lib/features/messaging/chatModel.js.map +1 -1
  27. package/lib/features/messaging/chatOperations.js +111 -2
  28. package/lib/features/messaging/chatOperations.js.map +1 -1
  29. package/lib/features/messaging/nativeChatChannelQuery.js +7 -2
  30. package/lib/features/messaging/nativeChatChannelQuery.js.map +1 -1
  31. package/lib/features/messaging/useChatData.js +248 -10
  32. package/lib/features/messaging/useChatData.js.map +1 -1
  33. 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,ScrollView,View,Pressable,Text,Modal,ActivityIndicator}from'react-native';import {Image}from'expo-image';import {MaterialCommunityIcons}from'@expo/vector-icons';import {SafeAreaView,SafeAreaProvider}from'react-native-safe-area-context';import {TapRow}from'./TapRow.js';import {attachmentUrl}from'./chatModel.js';const IMAGE_MAX = 240;
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 {splitLinks,firstLink,isOnlyALink}from'./chatLinks.js';import {useLinkPreview,LinkPreviewCard}from'./LinkPreviewCard.js';import {usePressed}from'./usePressed.js';var __defProp = Object.defineProperty;
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 parts = React.useMemo(() => splitLinks(body), [body]);
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((_b = message.authorId) != null ? _b : message.authorName, theme)
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
- body && !onlyLink ? /* @__PURE__ */ jsxs(Text, { style: [styles.bubbleText, {
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) => part.kind === "link" ? /* @__PURE__ */ jsx(Text, { style: [styles.linkText, {
406
- color: theme.isDark ? "#53bdeb" : "#027eb5"
407
- }], onPress: onOpenLink ? () => onOpenLink(part.url) : void 0, accessibilityRole: "link", children: part.text }, i) : part.text),
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