forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {Keyboard, View} from 'react-native'
2import {msg, Trans} from '@lingui/macro'
3import {useLingui} from '@lingui/react'
4
5import {
6 ADULT_CONTENT_LABELS,
7 type AdultSelfLabel,
8 OTHER_SELF_LABELS,
9 type OtherSelfLabel,
10 type SelfLabel,
11} from '#/lib/moderation'
12import {isWeb} from '#/platform/detection'
13import {atoms as a, useTheme, web} from '#/alf'
14import {Button, ButtonIcon, ButtonText} from '#/components/Button'
15import * as Dialog from '#/components/Dialog'
16import * as Toggle from '#/components/forms/Toggle'
17import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
18import {TinyChevronBottom_Stroke2_Corner0_Rounded as TinyChevronIcon} from '#/components/icons/Chevron'
19import {Shield_Stroke2_Corner0_Rounded} from '#/components/icons/Shield'
20import {Text} from '#/components/Typography'
21
22export function LabelsBtn({
23 labels,
24 onChange,
25}: {
26 labels: SelfLabel[]
27 onChange: (v: SelfLabel[]) => void
28}) {
29 const control = Dialog.useDialogControl()
30 const {_} = useLingui()
31
32 const hasLabel = labels.length > 0
33
34 const updateAdultLabels = (newLabels: AdultSelfLabel[]) => {
35 const newLabel = newLabels[newLabels.length - 1]
36 const filtered = labels.filter(l => !ADULT_CONTENT_LABELS.includes(l))
37 onChange([
38 ...new Set([...filtered, newLabel].filter(Boolean) as SelfLabel[]),
39 ])
40 }
41
42 const updateOtherLabels = (newLabels: OtherSelfLabel[]) => {
43 const newLabel = newLabels[newLabels.length - 1]
44 const filtered = labels.filter(l => !OTHER_SELF_LABELS.includes(l))
45 onChange([
46 ...new Set([...filtered, newLabel].filter(Boolean) as SelfLabel[]),
47 ])
48 }
49
50 return (
51 <>
52 <Button
53 color="secondary"
54 size="small"
55 testID="labelsBtn"
56 onPress={() => {
57 Keyboard.dismiss()
58 control.open()
59 }}
60 label={_(msg`Content warnings`)}
61 accessibilityHint={_(
62 msg`Opens a dialog to add a content warning to your post`,
63 )}>
64 <ButtonIcon icon={hasLabel ? Check : Shield_Stroke2_Corner0_Rounded} />
65 <ButtonText numberOfLines={1}>
66 {labels.length > 0 ? (
67 <Trans>Labels added</Trans>
68 ) : (
69 <Trans>Labels</Trans>
70 )}
71 </ButtonText>
72 <ButtonIcon icon={TinyChevronIcon} size="2xs" />
73 </Button>
74
75 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
76 <Dialog.Handle />
77 <DialogInner
78 labels={labels}
79 updateAdultLabels={updateAdultLabels}
80 updateOtherLabels={updateOtherLabels}
81 />
82 </Dialog.Outer>
83 </>
84 )
85}
86
87function DialogInner({
88 labels,
89 updateAdultLabels,
90 updateOtherLabels,
91}: {
92 labels: string[]
93 updateAdultLabels: (labels: AdultSelfLabel[]) => void
94 updateOtherLabels: (labels: OtherSelfLabel[]) => void
95}) {
96 const {_} = useLingui()
97 const control = Dialog.useDialogContext()
98 const t = useTheme()
99
100 return (
101 <Dialog.ScrollableInner
102 label={_(msg`Add a content warning`)}
103 style={[{maxWidth: 500}, a.w_full]}>
104 <View style={[a.flex_1]}>
105 <View style={[a.gap_sm]}>
106 <Text style={[a.text_2xl, a.font_semi_bold]}>
107 <Trans>Add a content warning</Trans>
108 </Text>
109 <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
110 <Trans>
111 Please add any content warning labels that are applicable for the
112 media you are skeeting.
113 </Trans>
114 </Text>
115 </View>
116
117 <View style={[a.my_md, a.gap_lg]}>
118 <View>
119 <View
120 style={[a.flex_row, a.align_center, a.justify_between, a.pb_sm]}>
121 <Text style={[a.font_semi_bold, a.text_lg]}>
122 <Trans>Adult Content</Trans>
123 </Text>
124 </View>
125 <View
126 style={[
127 a.p_md,
128 a.rounded_sm,
129 a.border,
130 t.atoms.border_contrast_medium,
131 ]}>
132 <Toggle.Group
133 label={_(msg`Adult Content labels`)}
134 values={labels}
135 onChange={values => {
136 updateAdultLabels(values as AdultSelfLabel[])
137 }}>
138 <View style={[a.gap_sm]}>
139 <Toggle.Item name="sexual" label={_(msg`Suggestive`)}>
140 <Toggle.Checkbox />
141 <Toggle.LabelText>
142 <Trans>Suggestive</Trans>
143 </Toggle.LabelText>
144 </Toggle.Item>
145 <Toggle.Item name="nudity" label={_(msg`Nudity`)}>
146 <Toggle.Checkbox />
147 <Toggle.LabelText>
148 <Trans>Nudity</Trans>
149 </Toggle.LabelText>
150 </Toggle.Item>
151 <Toggle.Item name="porn" label={_(msg`Porn`)}>
152 <Toggle.Checkbox />
153 <Toggle.LabelText>
154 <Trans>Adult</Trans>
155 </Toggle.LabelText>
156 </Toggle.Item>
157 </View>
158 </Toggle.Group>
159 {labels.includes('sexual') ||
160 labels.includes('nudity') ||
161 labels.includes('porn') ? (
162 <Text style={[a.mt_sm, t.atoms.text_contrast_medium]}>
163 {labels.includes('sexual') ? (
164 <Trans>Pictures meant for adults.</Trans>
165 ) : labels.includes('nudity') ? (
166 <Trans>Artistic or non-erotic nudity.</Trans>
167 ) : labels.includes('porn') ? (
168 <Trans>Sexual activity or erotic nudity.</Trans>
169 ) : (
170 ''
171 )}
172 </Text>
173 ) : null}
174 </View>
175 </View>
176 <View>
177 <View
178 style={[a.flex_row, a.align_center, a.justify_between, a.pb_sm]}>
179 <Text style={[a.font_semi_bold, a.text_lg]}>
180 <Trans>Other</Trans>
181 </Text>
182 </View>
183 <View
184 style={[
185 a.p_md,
186 a.rounded_sm,
187 a.border,
188 t.atoms.border_contrast_medium,
189 ]}>
190 <Toggle.Group
191 label={_(msg`Adult Content labels`)}
192 values={labels}
193 onChange={values => {
194 updateOtherLabels(values as OtherSelfLabel[])
195 }}>
196 <Toggle.Item name="graphic-media" label={_(msg`Graphic Media`)}>
197 <Toggle.Checkbox />
198 <Toggle.LabelText>
199 <Trans>Graphic Media</Trans>
200 </Toggle.LabelText>
201 </Toggle.Item>
202 </Toggle.Group>
203 {labels.includes('graphic-media') ? (
204 <Text style={[a.mt_sm, t.atoms.text_contrast_medium]}>
205 <Trans>
206 Media that may be disturbing or inappropriate for some
207 audiences.
208 </Trans>
209 </Text>
210 ) : null}
211 </View>
212 </View>
213 </View>
214 </View>
215
216 <View style={[a.mt_sm, web([a.flex_row, a.ml_auto])]}>
217 <Button
218 label={_(msg`Done`)}
219 onPress={() => control.close()}
220 color="primary"
221 size={isWeb ? 'small' : 'large'}
222 variant="solid"
223 testID="confirmBtn">
224 <ButtonText>
225 <Trans>Done</Trans>
226 </ButtonText>
227 </Button>
228 </View>
229 </Dialog.ScrollableInner>
230 )
231}