@adminide-stack/yantra-mobile 12.0.105-alpha.0 → 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 +3 -3
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {jsx,jsxs}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,Modal,View,Pressable,Text,KeyboardAvoidingView,ScrollView,TextInput,Switch,Platform}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {MaterialCommunityIcons}from'@expo/vector-icons';const MAX_OPTIONS = 12;
|
|
2
|
+
const QUESTION_MAX = 255;
|
|
3
|
+
const OPTION_MAX = 100;
|
|
4
|
+
function PollComposer({
|
|
5
|
+
visible,
|
|
6
|
+
theme,
|
|
7
|
+
onCancel,
|
|
8
|
+
onCreate
|
|
9
|
+
}) {
|
|
10
|
+
const [question, setQuestion] = React.useState("");
|
|
11
|
+
const [options, setOptions] = React.useState(["", ""]);
|
|
12
|
+
const [multiple, setMultiple] = React.useState(false);
|
|
13
|
+
const [busy, setBusy] = React.useState(false);
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
if (visible) {
|
|
16
|
+
setQuestion("");
|
|
17
|
+
setOptions(["", ""]);
|
|
18
|
+
setMultiple(false);
|
|
19
|
+
setBusy(false);
|
|
20
|
+
}
|
|
21
|
+
}, [visible]);
|
|
22
|
+
const setOption = (index, value) => {
|
|
23
|
+
setOptions((prev) => {
|
|
24
|
+
const next = prev.slice();
|
|
25
|
+
next[index] = value.slice(0, OPTION_MAX);
|
|
26
|
+
const nonEmpty = next.filter((o) => o.trim());
|
|
27
|
+
if (nonEmpty.length === next.length && next.length < MAX_OPTIONS) next.push("");
|
|
28
|
+
return next;
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const filled = options.map((o) => o.trim()).filter(Boolean);
|
|
32
|
+
const canSend = question.trim().length > 0 && filled.length >= 2 && !busy;
|
|
33
|
+
const submit = async () => {
|
|
34
|
+
if (!canSend) return;
|
|
35
|
+
setBusy(true);
|
|
36
|
+
try {
|
|
37
|
+
await onCreate(question.trim(), filled, multiple);
|
|
38
|
+
} finally {
|
|
39
|
+
setBusy(false);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return /* @__PURE__ */ jsx(Modal, { visible, animationType: "slide", onRequestClose: onCancel, transparent: false, children: /* @__PURE__ */ jsxs(View, { style: [styles.fill, {
|
|
43
|
+
backgroundColor: theme.bg
|
|
44
|
+
}], testID: "chat-poll-composer", children: [
|
|
45
|
+
/* @__PURE__ */ jsx(SafeAreaView, { edges: ["top"], style: {
|
|
46
|
+
backgroundColor: theme.headerBg
|
|
47
|
+
}, children: /* @__PURE__ */ jsxs(View, { style: [styles.header, {
|
|
48
|
+
borderBottomColor: theme.border,
|
|
49
|
+
flexDirection: "row"
|
|
50
|
+
}], children: [
|
|
51
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onCancel, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Cancel", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 26, color: theme.text }) }),
|
|
52
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.title, {
|
|
53
|
+
color: theme.text
|
|
54
|
+
}], children: "Create poll" }),
|
|
55
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: submit, disabled: !canSend, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Create poll", accessibilityState: {
|
|
56
|
+
disabled: !canSend
|
|
57
|
+
}, children: /* @__PURE__ */ jsx(Text, { style: [styles.send, {
|
|
58
|
+
color: canSend ? theme.accent : theme.textMuted
|
|
59
|
+
}], children: "Send" }) })
|
|
60
|
+
] }) }),
|
|
61
|
+
/* @__PURE__ */ jsx(KeyboardAvoidingView, { style: styles.fill, behavior: Platform.OS === "ios" ? "padding" : void 0, keyboardVerticalOffset: 8, children: /* @__PURE__ */ jsxs(ScrollView, { contentContainerStyle: styles.body, keyboardShouldPersistTaps: "handled", children: [
|
|
62
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.section, {
|
|
63
|
+
color: theme.textMuted
|
|
64
|
+
}], children: "QUESTION" }),
|
|
65
|
+
/* @__PURE__ */ jsx(TextInput, { value: question, onChangeText: (t) => setQuestion(t.slice(0, QUESTION_MAX)), placeholder: "Ask a question", placeholderTextColor: theme.textMuted, style: [styles.input, {
|
|
66
|
+
backgroundColor: theme.surface,
|
|
67
|
+
color: theme.text
|
|
68
|
+
}], multiline: true, accessibilityLabel: "Poll question" }),
|
|
69
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.section, {
|
|
70
|
+
color: theme.textMuted
|
|
71
|
+
}], children: "OPTIONS" }),
|
|
72
|
+
options.map((opt, i) => /* @__PURE__ */ jsx(TextInput, { value: opt, onChangeText: (t) => setOption(i, t), placeholder: i < 2 ? `Option ${i + 1}` : "Add", placeholderTextColor: theme.textMuted, style: [styles.input, {
|
|
73
|
+
backgroundColor: theme.surface,
|
|
74
|
+
color: theme.text
|
|
75
|
+
}], accessibilityLabel: `Poll option ${i + 1}` }, i)),
|
|
76
|
+
/* @__PURE__ */ jsxs(View, { style: [styles.switchRow, {
|
|
77
|
+
borderTopColor: theme.border,
|
|
78
|
+
flexDirection: "row"
|
|
79
|
+
}], children: [
|
|
80
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.switchLabel, {
|
|
81
|
+
color: theme.text
|
|
82
|
+
}], children: "Allow multiple answers" }),
|
|
83
|
+
/* @__PURE__ */ jsx(Switch, { value: multiple, onValueChange: setMultiple, trackColor: {
|
|
84
|
+
true: theme.accent
|
|
85
|
+
}, accessibilityLabel: "Allow multiple answers" })
|
|
86
|
+
] })
|
|
87
|
+
] }) })
|
|
88
|
+
] }) });
|
|
89
|
+
}
|
|
90
|
+
const styles = StyleSheet.create({
|
|
91
|
+
fill: {
|
|
92
|
+
flex: 1
|
|
93
|
+
},
|
|
94
|
+
header: {
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "space-between",
|
|
97
|
+
paddingHorizontal: 16,
|
|
98
|
+
minHeight: 52,
|
|
99
|
+
borderBottomWidth: StyleSheet.hairlineWidth
|
|
100
|
+
},
|
|
101
|
+
title: {
|
|
102
|
+
fontSize: 17,
|
|
103
|
+
fontWeight: "600"
|
|
104
|
+
},
|
|
105
|
+
send: {
|
|
106
|
+
fontSize: 16,
|
|
107
|
+
fontWeight: "700"
|
|
108
|
+
},
|
|
109
|
+
body: {
|
|
110
|
+
padding: 16,
|
|
111
|
+
paddingBottom: 48
|
|
112
|
+
},
|
|
113
|
+
section: {
|
|
114
|
+
fontSize: 12,
|
|
115
|
+
fontWeight: "600",
|
|
116
|
+
marginBottom: 8,
|
|
117
|
+
marginTop: 8,
|
|
118
|
+
letterSpacing: 0.5
|
|
119
|
+
},
|
|
120
|
+
input: {
|
|
121
|
+
borderRadius: 10,
|
|
122
|
+
paddingHorizontal: 12,
|
|
123
|
+
paddingVertical: 12,
|
|
124
|
+
fontSize: 16,
|
|
125
|
+
marginBottom: 10
|
|
126
|
+
},
|
|
127
|
+
switchRow: {
|
|
128
|
+
alignItems: "center",
|
|
129
|
+
justifyContent: "space-between",
|
|
130
|
+
marginTop: 16,
|
|
131
|
+
paddingTop: 16,
|
|
132
|
+
borderTopWidth: StyleSheet.hairlineWidth
|
|
133
|
+
},
|
|
134
|
+
switchLabel: {
|
|
135
|
+
fontSize: 16
|
|
136
|
+
}
|
|
137
|
+
});export{PollComposer};//# sourceMappingURL=PollComposer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollComposer.js","sources":["../../../src/features/messaging/PollComposer.tsx"],"sourcesContent":["/**\n * Create-a-poll screen, WhatsApp-style: a question, a growing list of option fields, and an\n * \"Allow multiple answers\" switch. Send is enabled once there is a question and at least two\n * non-empty options. Presented as a full-screen modal from the composer's \"+\" sheet.\n */\nimport * as React from 'react';\nimport {\n KeyboardAvoidingView,\n Modal,\n Platform,\n Pressable,\n ScrollView,\n StyleSheet,\n Switch,\n Text,\n TextInput,\n View,\n} from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport type { ChatTheme } from './ChatComponents';\n\n/** WhatsApp caps a poll at 12 options. */\nconst MAX_OPTIONS = 12;\nconst QUESTION_MAX = 255;\nconst OPTION_MAX = 100;\n\nexport function PollComposer({\n visible,\n theme,\n onCancel,\n onCreate,\n}: {\n visible: boolean;\n theme: ChatTheme;\n onCancel: () => void;\n /** Resolves when the poll has been created so the composer can close. */\n onCreate: (question: string, options: string[], multiple: boolean) => Promise<void> | void;\n}) {\n const [question, setQuestion] = React.useState('');\n // Always keep two empty slots at the end so there is somewhere to type the next option.\n const [options, setOptions] = React.useState<string[]>(['', '']);\n const [multiple, setMultiple] = React.useState(false);\n const [busy, setBusy] = React.useState(false);\n\n // Reset whenever the sheet opens.\n React.useEffect(() => {\n if (visible) {\n setQuestion('');\n setOptions(['', '']);\n setMultiple(false);\n setBusy(false);\n }\n }, [visible]);\n\n const setOption = (index: number, value: string) => {\n setOptions((prev) => {\n const next = prev.slice();\n next[index] = value.slice(0, OPTION_MAX);\n // Keep exactly one trailing empty slot (up to the cap), WhatsApp-style.\n const nonEmpty = next.filter((o) => o.trim());\n if (nonEmpty.length === next.length && next.length < MAX_OPTIONS) next.push('');\n return next;\n });\n };\n\n const filled = options.map((o) => o.trim()).filter(Boolean);\n const canSend = question.trim().length > 0 && filled.length >= 2 && !busy;\n\n const submit = async () => {\n if (!canSend) return;\n setBusy(true);\n try {\n await onCreate(question.trim(), filled, multiple);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Modal visible={visible} animationType=\"slide\" onRequestClose={onCancel} transparent={false}>\n <View style={[styles.fill, { backgroundColor: theme.bg }]} testID=\"chat-poll-composer\">\n <SafeAreaView edges={['top']} style={{ backgroundColor: theme.headerBg }}>\n <View style={[styles.header, { borderBottomColor: theme.border, flexDirection: 'row' }]}>\n <Pressable\n onPress={onCancel}\n hitSlop={10}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Cancel\"\n >\n <MaterialCommunityIcons name=\"close\" size={26} color={theme.text} />\n </Pressable>\n <Text style={[styles.title, { color: theme.text }]}>Create poll</Text>\n <Pressable\n onPress={submit}\n disabled={!canSend}\n hitSlop={10}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Create poll\"\n accessibilityState={{ disabled: !canSend }}\n >\n <Text style={[styles.send, { color: canSend ? theme.accent : theme.textMuted }]}>Send</Text>\n </Pressable>\n </View>\n </SafeAreaView>\n <KeyboardAvoidingView\n style={styles.fill}\n behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n keyboardVerticalOffset={8}\n >\n <ScrollView contentContainerStyle={styles.body} keyboardShouldPersistTaps=\"handled\">\n <Text style={[styles.section, { color: theme.textMuted }]}>QUESTION</Text>\n <TextInput\n value={question}\n onChangeText={(t) => setQuestion(t.slice(0, QUESTION_MAX))}\n placeholder=\"Ask a question\"\n placeholderTextColor={theme.textMuted}\n style={[styles.input, { backgroundColor: theme.surface, color: theme.text }]}\n multiline\n accessibilityLabel=\"Poll question\"\n />\n\n <Text style={[styles.section, { color: theme.textMuted }]}>OPTIONS</Text>\n {options.map((opt, i) => (\n <TextInput\n key={i}\n value={opt}\n onChangeText={(t) => setOption(i, t)}\n placeholder={i < 2 ? `Option ${i + 1}` : 'Add'}\n placeholderTextColor={theme.textMuted}\n style={[styles.input, { backgroundColor: theme.surface, color: theme.text }]}\n accessibilityLabel={`Poll option ${i + 1}`}\n />\n ))}\n\n <View style={[styles.switchRow, { borderTopColor: theme.border, flexDirection: 'row' }]}>\n <Text style={[styles.switchLabel, { color: theme.text }]}>Allow multiple answers</Text>\n <Switch\n value={multiple}\n onValueChange={setMultiple}\n trackColor={{ true: theme.accent }}\n accessibilityLabel=\"Allow multiple answers\"\n />\n </View>\n </ScrollView>\n </KeyboardAvoidingView>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n header: {\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n minHeight: 52,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n title: { fontSize: 17, fontWeight: '600' },\n send: { fontSize: 16, fontWeight: '700' },\n body: { padding: 16, paddingBottom: 48 },\n section: { fontSize: 12, fontWeight: '600', marginBottom: 8, marginTop: 8, letterSpacing: 0.5 },\n input: {\n borderRadius: 10,\n paddingHorizontal: 12,\n paddingVertical: 12,\n fontSize: 16,\n marginBottom: 10,\n },\n switchRow: {\n alignItems: 'center',\n justifyContent: 'space-between',\n marginTop: 16,\n paddingTop: 16,\n borderTopWidth: StyleSheet.hairlineWidth,\n },\n switchLabel: { fontSize: 16 },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {jsxs,jsx}from'react/jsx-runtime';import {StyleSheet,View,Pressable,Text,ScrollView}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {MaterialCommunityIcons}from'@expo/vector-icons';import {EmptyState,Avatar}from'./ChatComponents.js';function PollVotesScreen({
|
|
2
|
+
poll,
|
|
3
|
+
theme,
|
|
4
|
+
viewerId,
|
|
5
|
+
nameOf,
|
|
6
|
+
onBack
|
|
7
|
+
}) {
|
|
8
|
+
const total = poll ? poll.options.reduce((n, o) => n + o.count, 0) : 0;
|
|
9
|
+
const label = (id) => id === viewerId ? "You" : nameOf(id);
|
|
10
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles.fill, {
|
|
11
|
+
backgroundColor: theme.bg
|
|
12
|
+
}], testID: "chat-poll-votes", children: [
|
|
13
|
+
/* @__PURE__ */ jsx(SafeAreaView, { edges: ["top"], style: {
|
|
14
|
+
backgroundColor: theme.headerBg
|
|
15
|
+
}, children: /* @__PURE__ */ jsxs(View, { style: [styles.header, {
|
|
16
|
+
borderBottomColor: theme.border,
|
|
17
|
+
flexDirection: "row"
|
|
18
|
+
}], children: [
|
|
19
|
+
/* @__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 }) }),
|
|
20
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.title, {
|
|
21
|
+
color: theme.text
|
|
22
|
+
}], children: "Poll votes" }),
|
|
23
|
+
/* @__PURE__ */ jsx(View, { style: styles.headerIcon })
|
|
24
|
+
] }) }),
|
|
25
|
+
!poll ? /* @__PURE__ */ jsx(EmptyState, { icon: "poll", title: "Poll votes didn\u2019t load", detail: "Please try again later.", theme }) : /* @__PURE__ */ jsxs(ScrollView, { contentContainerStyle: styles.body, children: [
|
|
26
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.question, {
|
|
27
|
+
color: theme.text
|
|
28
|
+
}], children: poll.question }),
|
|
29
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.total, {
|
|
30
|
+
color: theme.textMuted
|
|
31
|
+
}], children: `${total} ${total === 1 ? "vote" : "votes"}` }),
|
|
32
|
+
poll.options.map((o) => /* @__PURE__ */ jsxs(View, { style: styles.optionBlock, children: [
|
|
33
|
+
/* @__PURE__ */ jsxs(View, { style: [styles.optionHead, {
|
|
34
|
+
borderBottomColor: theme.border,
|
|
35
|
+
flexDirection: "row"
|
|
36
|
+
}], children: [
|
|
37
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.optionText, {
|
|
38
|
+
color: theme.text
|
|
39
|
+
}], numberOfLines: 2, children: o.text }),
|
|
40
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.optionCount, {
|
|
41
|
+
color: theme.textMuted
|
|
42
|
+
}], children: `${o.count} ${o.count === 1 ? "vote" : "votes"}` })
|
|
43
|
+
] }),
|
|
44
|
+
o.voterIds.length === 0 ? /* @__PURE__ */ jsx(Text, { style: [styles.noVotes, {
|
|
45
|
+
color: theme.textMuted
|
|
46
|
+
}], children: "No votes yet" }) : o.voterIds.map((id) => /* @__PURE__ */ jsxs(View, { style: [styles.voter, {
|
|
47
|
+
flexDirection: "row"
|
|
48
|
+
}], children: [
|
|
49
|
+
/* @__PURE__ */ jsx(Avatar, { name: label(id), theme, size: 30, variant: "initials" }),
|
|
50
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.voterName, {
|
|
51
|
+
color: theme.text
|
|
52
|
+
}], children: label(id) })
|
|
53
|
+
] }, id))
|
|
54
|
+
] }, o.id))
|
|
55
|
+
] })
|
|
56
|
+
] });
|
|
57
|
+
}
|
|
58
|
+
const styles = StyleSheet.create({
|
|
59
|
+
fill: {
|
|
60
|
+
flex: 1
|
|
61
|
+
},
|
|
62
|
+
header: {
|
|
63
|
+
alignItems: "center",
|
|
64
|
+
justifyContent: "space-between",
|
|
65
|
+
paddingHorizontal: 4,
|
|
66
|
+
minHeight: 52,
|
|
67
|
+
borderBottomWidth: StyleSheet.hairlineWidth
|
|
68
|
+
},
|
|
69
|
+
headerIcon: {
|
|
70
|
+
width: 44,
|
|
71
|
+
height: 44,
|
|
72
|
+
alignItems: "center",
|
|
73
|
+
justifyContent: "center"
|
|
74
|
+
},
|
|
75
|
+
title: {
|
|
76
|
+
fontSize: 17,
|
|
77
|
+
fontWeight: "600"
|
|
78
|
+
},
|
|
79
|
+
body: {
|
|
80
|
+
padding: 16
|
|
81
|
+
},
|
|
82
|
+
question: {
|
|
83
|
+
fontSize: 18,
|
|
84
|
+
fontWeight: "700"
|
|
85
|
+
},
|
|
86
|
+
total: {
|
|
87
|
+
fontSize: 13,
|
|
88
|
+
marginTop: 2,
|
|
89
|
+
marginBottom: 12
|
|
90
|
+
},
|
|
91
|
+
optionBlock: {
|
|
92
|
+
marginBottom: 18
|
|
93
|
+
},
|
|
94
|
+
optionHead: {
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "space-between",
|
|
97
|
+
paddingBottom: 6,
|
|
98
|
+
marginBottom: 8,
|
|
99
|
+
borderBottomWidth: StyleSheet.hairlineWidth
|
|
100
|
+
},
|
|
101
|
+
optionText: {
|
|
102
|
+
fontSize: 16,
|
|
103
|
+
fontWeight: "600",
|
|
104
|
+
flex: 1,
|
|
105
|
+
marginRight: 8
|
|
106
|
+
},
|
|
107
|
+
optionCount: {
|
|
108
|
+
fontSize: 13
|
|
109
|
+
},
|
|
110
|
+
noVotes: {
|
|
111
|
+
fontSize: 14,
|
|
112
|
+
fontStyle: "italic"
|
|
113
|
+
},
|
|
114
|
+
voter: {
|
|
115
|
+
alignItems: "center",
|
|
116
|
+
marginBottom: 10
|
|
117
|
+
},
|
|
118
|
+
voterName: {
|
|
119
|
+
fontSize: 15,
|
|
120
|
+
marginLeft: 10
|
|
121
|
+
}
|
|
122
|
+
});export{PollVotesScreen};//# sourceMappingURL=PollVotesScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollVotesScreen.js","sources":["../../../src/features/messaging/PollVotesScreen.tsx"],"sourcesContent":["/**\n * \"Poll votes\": who picked what. WhatsApp polls are non-anonymous, so each option lists its\n * voters by name. Grouped by option, in the poll's own option order.\n */\nimport * as React from 'react';\nimport { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { Avatar, EmptyState, type ChatTheme } from './ChatComponents';\nimport type { ChatPoll } from './chatModel';\n\nexport function PollVotesScreen({\n poll,\n theme,\n viewerId,\n nameOf,\n onBack,\n}: {\n poll: ChatPoll | null;\n theme: ChatTheme;\n viewerId: string;\n /** Resolve a voter id to a display name (the group's member list). */\n nameOf: (id: string) => string;\n onBack: () => void;\n}) {\n const total = poll ? poll.options.reduce((n, o) => n + o.count, 0) : 0;\n const label = (id: string) => (id === viewerId ? 'You' : nameOf(id));\n return (\n <View style={[styles.fill, { backgroundColor: theme.bg }]} testID=\"chat-poll-votes\">\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 }]}>Poll votes</Text>\n <View style={styles.headerIcon} />\n </View>\n </SafeAreaView>\n {!poll ? (\n <EmptyState icon=\"poll\" title=\"Poll votes didn’t load\" detail=\"Please try again later.\" theme={theme} />\n ) : (\n <ScrollView contentContainerStyle={styles.body}>\n <Text style={[styles.question, { color: theme.text }]}>{poll.question}</Text>\n <Text style={[styles.total, { color: theme.textMuted }]}>\n {`${total} ${total === 1 ? 'vote' : 'votes'}`}\n </Text>\n {poll.options.map((o) => (\n <View key={o.id} style={styles.optionBlock}>\n <View\n style={[styles.optionHead, { borderBottomColor: theme.border, flexDirection: 'row' }]}\n >\n <Text style={[styles.optionText, { color: theme.text }]} numberOfLines={2}>\n {o.text}\n </Text>\n <Text style={[styles.optionCount, { color: theme.textMuted }]}>\n {`${o.count} ${o.count === 1 ? 'vote' : 'votes'}`}\n </Text>\n </View>\n {o.voterIds.length === 0 ? (\n <Text style={[styles.noVotes, { color: theme.textMuted }]}>No votes yet</Text>\n ) : (\n o.voterIds.map((id) => (\n <View key={id} style={[styles.voter, { flexDirection: 'row' }]}>\n <Avatar name={label(id)} theme={theme} size={30} variant=\"initials\" />\n <Text style={[styles.voterName, { color: theme.text }]}>{label(id)}</Text>\n </View>\n ))\n )}\n </View>\n ))}\n </ScrollView>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\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 body: { padding: 16 },\n question: { fontSize: 18, fontWeight: '700' },\n total: { fontSize: 13, marginTop: 2, marginBottom: 12 },\n optionBlock: { marginBottom: 18 },\n optionHead: {\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingBottom: 6,\n marginBottom: 8,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n optionText: { fontSize: 16, fontWeight: '600', flex: 1, marginRight: 8 },\n optionCount: { fontSize: 13 },\n noVotes: { fontSize: 14, fontStyle: 'italic' },\n voter: { alignItems: 'center', marginBottom: 10 },\n voterName: { fontSize: 15, marginLeft: 10 },\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,Platform,View,Pressable,Text,TextInput,ActivityIndicator,FlatList,Animated,PanResponder}from'react-native';import {SafeAreaView}from'react-native-safe-area-context';import {MaterialCommunityIcons}from'@expo/vector-icons';import {AppKeyboardAvoidingView}from'../../components/AppKeyboardAvoidingView.js';import {Avatar,ConnectionBanner,InlineBanner,DaySeparator,UnreadDivider,MessageBubble,ReplyQuote}from'./ChatComponents.js';import {ActionSheet}from'./ActionSheet.js';import {replyRefOf,canEditMessage,canDeleteForEveryone,firstUnreadId,dayLabel,messageStatus,timeLabel}from'./chatModel.js';import {MessageActionsOverlay}from'./MessageActions.js';import {StagedAttachments,RecordingBar,AttachSheet,ImageViewer}from'./ChatAttachments.js';var __defProp = Object.defineProperty;
|
|
1
|
+
import {jsxs,jsx}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,Platform,View,Pressable,Text,TextInput,ActivityIndicator,FlatList,Animated,PanResponder}from'react-native';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {MaterialCommunityIcons}from'@expo/vector-icons';import {AppKeyboardAvoidingView}from'../../components/AppKeyboardAvoidingView.js';import {Avatar,ConnectionBanner,InlineBanner,DaySeparator,UnreadDivider,SystemRow,MessageBubble,ReplyQuote}from'./ChatComponents.js';import {ActionSheet}from'./ActionSheet.js';import {TapRow}from'./TapRow.js';import {replyRefOf,canEditMessage,canDeleteForEveryone,firstUnreadId,dayLabel,systemText,messageStatus,timeLabel}from'./chatModel.js';import {MessageActionsOverlay}from'./MessageActions.js';import {StagedAttachments,RecordingBar,AttachSheet,ImageViewer}from'./ChatAttachments.js';import {PollComposer}from'./PollComposer.js';var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -116,7 +116,17 @@ function ThreadScreen({
|
|
|
116
116
|
audio,
|
|
117
117
|
onSendAttachments,
|
|
118
118
|
linkPreviews,
|
|
119
|
-
onOpenLink
|
|
119
|
+
onOpenLink,
|
|
120
|
+
memberNameOf,
|
|
121
|
+
mentionCandidates,
|
|
122
|
+
composerLock,
|
|
123
|
+
onVote,
|
|
124
|
+
onViewVotes,
|
|
125
|
+
onCreatePoll,
|
|
126
|
+
onReportMessage,
|
|
127
|
+
onKeep,
|
|
128
|
+
peerBlocked,
|
|
129
|
+
onUnblockPeer
|
|
120
130
|
}) {
|
|
121
131
|
var _a;
|
|
122
132
|
const [draft, setDraft] = React.useState(initialDraft != null ? initialDraft : "");
|
|
@@ -128,6 +138,7 @@ function ThreadScreen({
|
|
|
128
138
|
}, [initialDraft]);
|
|
129
139
|
const [staged, setStaged] = React.useState([]);
|
|
130
140
|
const [attachOpen, setAttachOpen] = React.useState(false);
|
|
141
|
+
const [pollComposerOpen, setPollComposerOpen] = React.useState(false);
|
|
131
142
|
const [recordingSince, setRecordingSince] = React.useState(null);
|
|
132
143
|
const [viewerUrl, setViewerUrl] = React.useState(null);
|
|
133
144
|
const [composerError, setComposerError] = React.useState(null);
|
|
@@ -144,6 +155,27 @@ function ThreadScreen({
|
|
|
144
155
|
const listRef = React.useRef(null);
|
|
145
156
|
const canAttach = Boolean(media && onSendAttachments);
|
|
146
157
|
const canRecord = Boolean(audio && onSendAttachments);
|
|
158
|
+
const insets = useSafeAreaInsets();
|
|
159
|
+
const resolveName = React.useCallback((id) => {
|
|
160
|
+
var _a2;
|
|
161
|
+
return (_a2 = memberNameOf == null ? void 0 : memberNameOf(id)) != null ? _a2 : "Someone";
|
|
162
|
+
}, [memberNameOf]);
|
|
163
|
+
const insertedMentions = React.useRef([]);
|
|
164
|
+
const [mentionQuery, setMentionQuery] = React.useState(null);
|
|
165
|
+
const mentionMatches = React.useMemo(() => {
|
|
166
|
+
if (mentionQuery == null || !(mentionCandidates == null ? void 0 : mentionCandidates.length)) return [];
|
|
167
|
+
const q = mentionQuery.toLowerCase();
|
|
168
|
+
return mentionCandidates.filter((m) => !m.isYou).filter((m) => !q || m.name.toLowerCase().split(/\s+/).some((w) => w.startsWith(q))).slice(0, 8);
|
|
169
|
+
}, [mentionQuery, mentionCandidates]);
|
|
170
|
+
const mentionIdsFor = React.useCallback((text) => {
|
|
171
|
+
const ids = insertedMentions.current.filter((m) => text.includes(m.token)).map((m) => m.id);
|
|
172
|
+
return Array.from(new Set(ids));
|
|
173
|
+
}, []);
|
|
174
|
+
const activeMentionQuery = React.useCallback((text) => {
|
|
175
|
+
if (!(mentionCandidates == null ? void 0 : mentionCandidates.length)) return null;
|
|
176
|
+
const m = /(?:^|\s)@([\p{L}\p{N}._'’-]*)$/u.exec(text);
|
|
177
|
+
return m ? m[1] : null;
|
|
178
|
+
}, [mentionCandidates]);
|
|
147
179
|
const [selected, setSelected] = React.useState(null);
|
|
148
180
|
const selectedMessage = React.useMemo(() => {
|
|
149
181
|
var _a2;
|
|
@@ -237,6 +269,18 @@ function ThreadScreen({
|
|
|
237
269
|
}
|
|
238
270
|
});
|
|
239
271
|
}
|
|
272
|
+
if (selectedMessage && onKeep && !selectedMessage.isDeleted && (!selectedMessage.sendState || selectedMessage.sendState === "sent")) {
|
|
273
|
+
const target = selectedMessage;
|
|
274
|
+
list.push({
|
|
275
|
+
key: "keep",
|
|
276
|
+
label: target.kept ? "Unkeep" : "Keep",
|
|
277
|
+
icon: target.kept ? "bookmark-off-outline" : "bookmark-outline",
|
|
278
|
+
onPress: () => {
|
|
279
|
+
setSelected(null);
|
|
280
|
+
onKeep(target.id, !target.kept);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
240
284
|
if (selectedMessage && onEdit && canEditMessage(selectedMessage, at)) {
|
|
241
285
|
const target = selectedMessage;
|
|
242
286
|
list.push({
|
|
@@ -257,6 +301,18 @@ function ThreadScreen({
|
|
|
257
301
|
}
|
|
258
302
|
});
|
|
259
303
|
}
|
|
304
|
+
if (selectedMessage && onReportMessage && !selectedMessage.isMine && !selectedMessage.isDeleted) {
|
|
305
|
+
const target = selectedMessage;
|
|
306
|
+
list.push({
|
|
307
|
+
key: "report",
|
|
308
|
+
label: "Report",
|
|
309
|
+
icon: "alert-octagon-outline",
|
|
310
|
+
onPress: () => {
|
|
311
|
+
setSelected(null);
|
|
312
|
+
onReportMessage(target);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
260
316
|
if (selectedMessage && (onDeleteForMe || onDeleteForEveryone)) {
|
|
261
317
|
const target = selectedMessage;
|
|
262
318
|
list.push({
|
|
@@ -270,7 +326,7 @@ function ThreadScreen({
|
|
|
270
326
|
});
|
|
271
327
|
}
|
|
272
328
|
return list;
|
|
273
|
-
}, [selectedMessage, onCopyText, onShareText, flushPendingShare, startReply, onForward, onStar, onEdit, onDeleteForMe, onDeleteForEveryone, onShowInfo, draft]);
|
|
329
|
+
}, [selectedMessage, onCopyText, onShareText, flushPendingShare, startReply, onForward, onStar, onEdit, onKeep, onReportMessage, onDeleteForMe, onDeleteForEveryone, onShowInfo, draft]);
|
|
274
330
|
const deleteActions = React.useMemo(() => {
|
|
275
331
|
const target = deleteTarget;
|
|
276
332
|
if (!target) return [];
|
|
@@ -429,13 +485,35 @@ function ThreadScreen({
|
|
|
429
485
|
return;
|
|
430
486
|
}
|
|
431
487
|
if (!text) return;
|
|
488
|
+
const mentions = mentionIdsFor(text);
|
|
432
489
|
setDraft("");
|
|
433
490
|
setReplyTo(null);
|
|
491
|
+
setMentionQuery(null);
|
|
492
|
+
insertedMentions.current = [];
|
|
434
493
|
onDraftChange == null ? void 0 : onDraftChange("");
|
|
435
494
|
haptics == null ? void 0 : haptics.impact("light");
|
|
436
|
-
onSend(text, quote);
|
|
495
|
+
onSend(text, quote, mentions);
|
|
437
496
|
jumpToLatest();
|
|
438
|
-
}, [draft, staged, replyTo, editing, haptics, onSend, onSendAttachments, onEdit, onDraftChange, jumpToLatest]);
|
|
497
|
+
}, [draft, staged, replyTo, editing, haptics, onSend, onSendAttachments, onEdit, onDraftChange, jumpToLatest, mentionIdsFor]);
|
|
498
|
+
const insertMention = React.useCallback((member) => {
|
|
499
|
+
var _a2;
|
|
500
|
+
const handle = member.name.trim().split(/\s+/)[0] || "member";
|
|
501
|
+
const token = `@${handle}`;
|
|
502
|
+
setDraft((prev) => {
|
|
503
|
+
const next = prev.replace(/(?:^|\s)@([\p{L}\p{N}._'’-]*)$/u, (whole) => {
|
|
504
|
+
const lead = whole.startsWith("@") ? "" : whole[0];
|
|
505
|
+
return `${lead}${token} `;
|
|
506
|
+
});
|
|
507
|
+
onDraftChange == null ? void 0 : onDraftChange(next);
|
|
508
|
+
return next;
|
|
509
|
+
});
|
|
510
|
+
insertedMentions.current = [...insertedMentions.current, {
|
|
511
|
+
token,
|
|
512
|
+
id: member.id
|
|
513
|
+
}];
|
|
514
|
+
setMentionQuery(null);
|
|
515
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
516
|
+
}, [onDraftChange]);
|
|
439
517
|
const pendingPick = React.useRef(null);
|
|
440
518
|
const runPendingPick = React.useCallback(() => {
|
|
441
519
|
const source = pendingPick.current;
|
|
@@ -461,6 +539,17 @@ function ThreadScreen({
|
|
|
461
539
|
pendingPick.current = "camera";
|
|
462
540
|
runPendingPick();
|
|
463
541
|
}, [media, runPendingPick]);
|
|
542
|
+
const pendingPoll = React.useRef(false);
|
|
543
|
+
const runPendingPoll = React.useCallback(() => {
|
|
544
|
+
if (!pendingPoll.current) return;
|
|
545
|
+
pendingPoll.current = false;
|
|
546
|
+
setPollComposerOpen(true);
|
|
547
|
+
}, []);
|
|
548
|
+
const openPoll = React.useCallback(() => {
|
|
549
|
+
pendingPoll.current = true;
|
|
550
|
+
setAttachOpen(false);
|
|
551
|
+
if (Platform.OS !== "ios") setTimeout(runPendingPoll, 400);
|
|
552
|
+
}, [runPendingPoll]);
|
|
464
553
|
const startRecording = React.useCallback(async () => {
|
|
465
554
|
if (!audio) return;
|
|
466
555
|
setComposerError(null);
|
|
@@ -501,7 +590,8 @@ function ThreadScreen({
|
|
|
501
590
|
}, [audio]);
|
|
502
591
|
const headerSubtitle = typingText || subtitle || "";
|
|
503
592
|
return /* @__PURE__ */ jsxs(AppKeyboardAvoidingView, { style: [styles.fill, {
|
|
504
|
-
backgroundColor: theme.threadBg
|
|
593
|
+
backgroundColor: theme.threadBg,
|
|
594
|
+
marginBottom: -insets.bottom
|
|
505
595
|
}], behavior: Platform.OS === "ios" ? "padding" : void 0, keyboardVerticalOffset: 0, children: [
|
|
506
596
|
/* @__PURE__ */ jsxs(SafeAreaView, { edges: ["top"], style: {
|
|
507
597
|
backgroundColor: theme.headerBg
|
|
@@ -596,13 +686,13 @@ function ThreadScreen({
|
|
|
596
686
|
const label = dayLabel(item.createdAt, now);
|
|
597
687
|
const olderLabel = older ? dayLabel(older.createdAt, now) : null;
|
|
598
688
|
const newDay = olderLabel !== label;
|
|
599
|
-
const sameRun = (a, b) => Boolean(a && !a.isDeleted && !b.isDeleted && a.authorId && a.authorId === b.authorId);
|
|
689
|
+
const sameRun = (a, b) => Boolean(a && !a.isDeleted && !b.isDeleted && !a.system && !b.system && a.authorId && a.authorId === b.authorId);
|
|
600
690
|
const startsBand = (unreadAnchor == null ? void 0 : unreadAnchor.id) === item.id;
|
|
601
691
|
const groupWithPrevious = sameRun(older, item) && !newDay && !startsBand;
|
|
602
692
|
return /* @__PURE__ */ jsxs(View, { children: [
|
|
603
693
|
newDay ? /* @__PURE__ */ jsx(DaySeparator, { label, theme }) : null,
|
|
604
694
|
startsBand && unreadAnchor ? /* @__PURE__ */ jsx(UnreadDivider, { count: unreadAnchor.count, theme }) : null,
|
|
605
|
-
/* @__PURE__ */ jsx(SwipeToReply, { enabled: !item.isDeleted && (!item.sendState || item.sendState === "sent"), theme, onReply: () => startReply(item), children: /* @__PURE__ */ jsx(MessageBubble, { message: item, theme, status: item.isMine ? messageStatus(item, readWatermark != null ? readWatermark : 0, deliveredWatermark != null ? deliveredWatermark : 0) : void 0, viewerId, fileBaseUrl: media == null ? void 0 : media.fileBaseUrl, audio, onOpenImage: setViewerUrl, linkPreviews, onOpenLink, showAuthor: Boolean(isGroup) && !groupWithPrevious, groupWithPrevious, highlighted: highlightId === item.id, onPressQuote: jumpToMessage, onRetry: () => onRetry(item.id), onLongPress: (
|
|
695
|
+
item.system ? /* @__PURE__ */ jsx(SystemRow, { text: systemText(item.system, viewerId != null ? viewerId : "", resolveName), theme }) : /* @__PURE__ */ jsx(SwipeToReply, { enabled: !item.isDeleted && (!item.sendState || item.sendState === "sent"), theme, onReply: () => startReply(item), children: /* @__PURE__ */ jsx(MessageBubble, { message: item, theme, status: item.isMine ? messageStatus(item, readWatermark != null ? readWatermark : 0, deliveredWatermark != null ? deliveredWatermark : 0) : void 0, viewerId, fileBaseUrl: media == null ? void 0 : media.fileBaseUrl, audio, onOpenImage: setViewerUrl, linkPreviews, onOpenLink, onVote: item.poll && onVote ? (optionId) => onVote(item.id, optionId) : void 0, onViewVotes: item.poll && onViewVotes ? () => onViewVotes(item) : void 0, showAuthor: Boolean(isGroup) && !groupWithPrevious, groupWithPrevious, highlighted: highlightId === item.id, onPressQuote: jumpToMessage, onRetry: () => onRetry(item.id), onLongPress: (
|
|
606
696
|
// Only confirmed messages can be reacted to or acted on.
|
|
607
697
|
!item.isDeleted && (!item.sendState || item.sendState === "sent") ? (frame) => {
|
|
608
698
|
haptics == null ? void 0 : haptics.impact("medium");
|
|
@@ -660,8 +750,45 @@ function ThreadScreen({
|
|
|
660
750
|
}], children: /* @__PURE__ */ jsx(Text, { style: styles.jumpBadgeText, children: missed > 99 ? "99+" : missed }) }) : null
|
|
661
751
|
] }) : null
|
|
662
752
|
] }),
|
|
663
|
-
/* @__PURE__ */ jsx(
|
|
664
|
-
|
|
753
|
+
!composerLock && !peerBlocked && mentionMatches.length ? /* @__PURE__ */ jsx(View, { style: [styles.mentionPanel, {
|
|
754
|
+
backgroundColor: theme.bg,
|
|
755
|
+
borderTopColor: theme.border
|
|
756
|
+
}], testID: "chat-mention-picker", children: mentionMatches.map((m) => /* @__PURE__ */ jsx(TapRow, { onPress: () => insertMention(m), accessibilityRole: "button", accessibilityLabel: `Mention ${m.name}`, pressedColor: theme.surface, children: /* @__PURE__ */ jsxs(View, { style: [styles.mentionRow, {
|
|
757
|
+
borderBottomColor: theme.border,
|
|
758
|
+
flexDirection: "row"
|
|
759
|
+
}], children: [
|
|
760
|
+
/* @__PURE__ */ jsx(Avatar, { name: m.name, uri: m.avatarUrl, size: 34, theme, variant: "initials" }),
|
|
761
|
+
/* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.mentionName, {
|
|
762
|
+
color: theme.text
|
|
763
|
+
}], children: m.name }),
|
|
764
|
+
m.isAdmin ? /* @__PURE__ */ jsx(Text, { style: [styles.mentionAdmin, {
|
|
765
|
+
color: theme.textMuted
|
|
766
|
+
}], children: "Admin" }) : null
|
|
767
|
+
] }) }, m.id)) }) : null,
|
|
768
|
+
composerLock ? /* @__PURE__ */ jsx(SafeAreaView, { edges: ["bottom"], style: {
|
|
769
|
+
backgroundColor: theme.composerBar
|
|
770
|
+
}, children: /* @__PURE__ */ jsxs(View, { style: [styles.composerLock, {
|
|
771
|
+
borderTopColor: theme.border
|
|
772
|
+
}], testID: "chat-composer-lock", children: [
|
|
773
|
+
/* @__PURE__ */ jsx(MaterialCommunityIcons, { name: composerLock === "adminsOnly" ? "shield-account" : "account-off", size: 18, color: theme.textMuted, style: {
|
|
774
|
+
marginRight: 8
|
|
775
|
+
} }),
|
|
776
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.composerLockText, {
|
|
777
|
+
color: theme.textMuted
|
|
778
|
+
}], children: composerLock === "adminsOnly" ? "Only admins can send messages" : "You can't send messages to this group because you're no longer a participant" })
|
|
779
|
+
] }) }) : null,
|
|
780
|
+
!composerLock && peerBlocked ? /* @__PURE__ */ jsx(SafeAreaView, { edges: ["bottom"], style: {
|
|
781
|
+
backgroundColor: theme.composerBar
|
|
782
|
+
}, children: /* @__PURE__ */ jsx(Pressable, { onPress: onUnblockPeer, disabled: !onUnblockPeer, accessibilityRole: "button", accessibilityLabel: "Unblock to send a message", style: [styles.composerLock, {
|
|
783
|
+
borderTopColor: theme.border
|
|
784
|
+
}], testID: "chat-composer-blocked", children: /* @__PURE__ */ jsxs(Text, { style: [styles.composerLockText, {
|
|
785
|
+
color: theme.textMuted
|
|
786
|
+
}], children: [
|
|
787
|
+
"You blocked this contact.",
|
|
788
|
+
onUnblockPeer ? " Tap to unblock." : ""
|
|
789
|
+
] }) }) }) : null,
|
|
790
|
+
!composerLock && !peerBlocked ? /* @__PURE__ */ jsx(StagedAttachments, { files: staged, theme, onRemove: (index) => setStaged((prev) => prev.filter((_, i) => i !== index)) }) : null,
|
|
791
|
+
!composerLock && !peerBlocked && editing && !recordingSince ? /* @__PURE__ */ jsxs(View, { style: [styles.replyBar, {
|
|
665
792
|
backgroundColor: theme.composerBar,
|
|
666
793
|
flexDirection: "row"
|
|
667
794
|
}], testID: "chat-composer-editing", children: [
|
|
@@ -684,7 +811,7 @@ function ThreadScreen({
|
|
|
684
811
|
setEditing(null);
|
|
685
812
|
}, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Cancel edit", style: styles.replyClose, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 20, color: theme.textMuted }) })
|
|
686
813
|
] }) : null,
|
|
687
|
-
replyTo && !recordingSince ? /* @__PURE__ */ jsxs(View, { style: [styles.replyBar, {
|
|
814
|
+
!composerLock && !peerBlocked && replyTo && !recordingSince ? /* @__PURE__ */ jsxs(View, { style: [styles.replyBar, {
|
|
688
815
|
backgroundColor: theme.composerBar,
|
|
689
816
|
flexDirection: "row"
|
|
690
817
|
}], testID: "chat-composer-reply", children: [
|
|
@@ -693,7 +820,7 @@ function ThreadScreen({
|
|
|
693
820
|
}, children: /* @__PURE__ */ jsx(ReplyQuote, { reply: replyTo, theme, viewerId, compact: true }) }),
|
|
694
821
|
/* @__PURE__ */ jsx(Pressable, { onPress: () => setReplyTo(null), hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Cancel reply", style: styles.replyClose, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 20, color: theme.textMuted }) })
|
|
695
822
|
] }) : null,
|
|
696
|
-
recordingSince ? /* @__PURE__ */ jsx(RecordingBar, { theme, startedAt: recordingSince, onCancel: () => void finishRecording(false), onSend: () => void finishRecording(true) }) : /* @__PURE__ */ jsx(SafeAreaView, { edges: ["bottom"], style: {
|
|
823
|
+
composerLock || peerBlocked ? null : recordingSince ? /* @__PURE__ */ jsx(RecordingBar, { theme, startedAt: recordingSince, onCancel: () => void finishRecording(false), onSend: () => void finishRecording(true) }) : /* @__PURE__ */ jsx(SafeAreaView, { edges: ["bottom"], style: {
|
|
697
824
|
backgroundColor: theme.composerBar
|
|
698
825
|
}, children: /* @__PURE__ */ jsxs(View, { style: {
|
|
699
826
|
flexDirection: "row",
|
|
@@ -717,6 +844,7 @@ function ThreadScreen({
|
|
|
717
844
|
}, children: /* @__PURE__ */ jsx(TextInput, { ref: inputRef, value: draft, onChangeText: (text) => {
|
|
718
845
|
setDraft(text);
|
|
719
846
|
if (!editing) onDraftChange == null ? void 0 : onDraftChange(text);
|
|
847
|
+
setMentionQuery(editing ? null : activeMentionQuery(text));
|
|
720
848
|
}, placeholder: "Message", placeholderTextColor: theme.textMuted, style: {
|
|
721
849
|
flex: 1,
|
|
722
850
|
color: theme.text,
|
|
@@ -734,7 +862,14 @@ function ThreadScreen({
|
|
|
734
862
|
/* @__PURE__ */ jsx(Pressable, { onPress: () => void startRecording(), hitSlop: 6, accessibilityRole: "button", accessibilityLabel: "Record voice message", style: styles.composerIcon, testID: "chat-composer-mic", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "microphone-outline", size: 26, color: theme.accent }) })
|
|
735
863
|
] })
|
|
736
864
|
] }) }),
|
|
737
|
-
/* @__PURE__ */ jsx(AttachSheet, { visible: attachOpen, theme, onClose: () => setAttachOpen(false), onPhotos: () => pick("library"), onCamera: () => pick("camera"), onDismissed: Platform.OS === "ios" ?
|
|
865
|
+
/* @__PURE__ */ jsx(AttachSheet, { visible: attachOpen, theme, onClose: () => setAttachOpen(false), onPhotos: () => pick("library"), onCamera: () => pick("camera"), onPoll: onCreatePoll ? openPoll : void 0, onDismissed: Platform.OS === "ios" ? () => {
|
|
866
|
+
runPendingPick();
|
|
867
|
+
runPendingPoll();
|
|
868
|
+
} : void 0 }),
|
|
869
|
+
onCreatePoll ? /* @__PURE__ */ jsx(PollComposer, { visible: pollComposerOpen, theme, onCancel: () => setPollComposerOpen(false), onCreate: async (question, options, multiple) => {
|
|
870
|
+
await onCreatePoll(question, options, multiple);
|
|
871
|
+
setPollComposerOpen(false);
|
|
872
|
+
} }) : null,
|
|
738
873
|
/* @__PURE__ */ jsx(ImageViewer, { url: viewerUrl, onClose: () => setViewerUrl(null) }),
|
|
739
874
|
/* @__PURE__ */ jsx(MessageActionsOverlay, { message: selectedMessage, frame: (_a = selected == null ? void 0 : selected.frame) != null ? _a : null, theme, actions, onReact: (emoji) => {
|
|
740
875
|
if (selectedMessage && onReact) {
|
|
@@ -816,6 +951,38 @@ const styles = StyleSheet.create({
|
|
|
816
951
|
paddingRight: 4,
|
|
817
952
|
paddingTop: 8
|
|
818
953
|
},
|
|
954
|
+
mentionPanel: {
|
|
955
|
+
maxHeight: 220,
|
|
956
|
+
borderTopWidth: StyleSheet.hairlineWidth
|
|
957
|
+
},
|
|
958
|
+
mentionRow: {
|
|
959
|
+
alignItems: "center",
|
|
960
|
+
paddingHorizontal: 14,
|
|
961
|
+
paddingVertical: 8,
|
|
962
|
+
borderBottomWidth: StyleSheet.hairlineWidth
|
|
963
|
+
},
|
|
964
|
+
mentionName: {
|
|
965
|
+
flex: 1,
|
|
966
|
+
fontSize: 16,
|
|
967
|
+
marginLeft: 12
|
|
968
|
+
},
|
|
969
|
+
mentionAdmin: {
|
|
970
|
+
fontSize: 12,
|
|
971
|
+
marginLeft: 8
|
|
972
|
+
},
|
|
973
|
+
composerLock: {
|
|
974
|
+
flexDirection: "row",
|
|
975
|
+
alignItems: "center",
|
|
976
|
+
justifyContent: "center",
|
|
977
|
+
paddingHorizontal: 24,
|
|
978
|
+
paddingVertical: 14,
|
|
979
|
+
borderTopWidth: StyleSheet.hairlineWidth
|
|
980
|
+
},
|
|
981
|
+
composerLockText: {
|
|
982
|
+
fontSize: 13.5,
|
|
983
|
+
textAlign: "center",
|
|
984
|
+
flexShrink: 1
|
|
985
|
+
},
|
|
819
986
|
replyClose: {
|
|
820
987
|
width: 36,
|
|
821
988
|
height: 36,
|