Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at post-text-option 231 lines 7.6 kB view raw
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}