Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
120
fork

Configure Feed

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

at a876aae44ea07494ebea9727350aa060b81f317b 307 lines 8.8 kB view raw
1import {View} from 'react-native' 2import { 3 type InterpretedLabelValueDefinition, 4 type LabelPreference, 5} from '@atproto/api' 6import {msg} from '@lingui/core/macro' 7import {useLingui} from '@lingui/react' 8import {Trans} from '@lingui/react/macro' 9 10import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' 11import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription' 12import {getLabelStrings} from '#/lib/moderation/useLabelInfo' 13import { 14 usePreferencesQuery, 15 usePreferencesSetContentLabelMutation, 16} from '#/state/queries/preferences' 17import {atoms as a, useBreakpoints, useTheme} from '#/alf' 18import * as ToggleButton from '#/components/forms/ToggleButton' 19import {InlineLinkText} from '#/components/Link' 20import {Text} from '#/components/Typography' 21import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '../icons/CircleInfo' 22 23export function Outer({children}: React.PropsWithChildren<{}>) { 24 return ( 25 <View 26 style={[ 27 a.flex_row, 28 a.gap_sm, 29 a.px_lg, 30 a.py_lg, 31 a.justify_between, 32 a.flex_wrap, 33 ]}> 34 {children} 35 </View> 36 ) 37} 38 39export function Content({ 40 children, 41 name, 42 description, 43}: React.PropsWithChildren<{ 44 name: string 45 description: string 46}>) { 47 const t = useTheme() 48 const {gtPhone} = useBreakpoints() 49 50 return ( 51 <View style={[a.gap_xs, a.flex_1]}> 52 <Text emoji style={[a.font_semi_bold, gtPhone ? a.text_sm : a.text_md]}> 53 {name} 54 </Text> 55 <Text emoji style={[t.atoms.text_contrast_medium, a.leading_snug]}> 56 {description} 57 </Text> 58 59 {children} 60 </View> 61 ) 62} 63 64export function Buttons({ 65 name, 66 values, 67 onChange, 68 ignoreLabel, 69 warnLabel, 70 hideLabel, 71 disabled, 72}: { 73 name: string 74 values: ToggleButton.GroupProps['values'] 75 onChange: ToggleButton.GroupProps['onChange'] 76 ignoreLabel?: string 77 warnLabel?: string 78 hideLabel?: string 79 disabled?: boolean 80}) { 81 const {_} = useLingui() 82 83 return ( 84 <View style={[{minHeight: 35}, a.w_full]}> 85 <ToggleButton.Group 86 disabled={disabled} 87 label={_( 88 msg`Configure content filtering setting for category: ${name}`, 89 )} 90 values={values} 91 onChange={onChange}> 92 {ignoreLabel && ( 93 <ToggleButton.Button name="ignore" label={ignoreLabel}> 94 <ToggleButton.ButtonText>{ignoreLabel}</ToggleButton.ButtonText> 95 </ToggleButton.Button> 96 )} 97 {warnLabel && ( 98 <ToggleButton.Button name="warn" label={warnLabel}> 99 <ToggleButton.ButtonText>{warnLabel}</ToggleButton.ButtonText> 100 </ToggleButton.Button> 101 )} 102 {hideLabel && ( 103 <ToggleButton.Button name="hide" label={hideLabel}> 104 <ToggleButton.ButtonText>{hideLabel}</ToggleButton.ButtonText> 105 </ToggleButton.Button> 106 )} 107 </ToggleButton.Group> 108 </View> 109 ) 110} 111 112/** 113 * For use on the global Moderation screen to set prefs for a "global" label, 114 * not scoped to a single labeler. 115 */ 116export function GlobalLabelPreference({ 117 labelDefinition, 118 disabled, 119}: { 120 labelDefinition: InterpretedLabelValueDefinition 121 disabled?: boolean 122}) { 123 const {_} = useLingui() 124 125 const {identifier} = labelDefinition 126 const {data: preferences} = usePreferencesQuery() 127 const {mutate, variables} = usePreferencesSetContentLabelMutation() 128 const savedPref = preferences?.moderationPrefs.labels[identifier] 129 const pref = variables?.visibility ?? savedPref ?? 'warn' 130 131 const allLabelStrings = useGlobalLabelStrings() 132 const labelStrings = 133 labelDefinition.identifier in allLabelStrings 134 ? allLabelStrings[labelDefinition.identifier] 135 : { 136 name: labelDefinition.identifier, 137 description: `Labeled "${labelDefinition.identifier}"`, 138 } 139 140 const labelOptions = { 141 hide: _(msg`Hide`), 142 warn: _(msg`Warn`), 143 ignore: _(msg`Show`), 144 } 145 146 return ( 147 <Outer> 148 <Content 149 name={labelStrings.name} 150 description={labelStrings.description} 151 /> 152 <Buttons 153 name={labelStrings.name.toLowerCase()} 154 values={[pref]} 155 onChange={values => { 156 mutate({ 157 label: identifier, 158 visibility: values[0] as LabelPreference, 159 labelerDid: undefined, 160 }) 161 }} 162 ignoreLabel={labelOptions.ignore} 163 warnLabel={labelOptions.warn} 164 hideLabel={labelOptions.hide} 165 disabled={disabled} 166 /> 167 </Outer> 168 ) 169} 170 171/** 172 * For use on individual labeler pages 173 */ 174export function LabelerLabelPreference({ 175 labelDefinition, 176 disabled, 177 labelerDid, 178}: { 179 labelDefinition: InterpretedLabelValueDefinition 180 disabled?: boolean 181 labelerDid?: string 182}) { 183 const {_, i18n} = useLingui() 184 const t = useTheme() 185 const {gtPhone} = useBreakpoints() 186 187 const isGlobalLabel = !labelDefinition.definedBy 188 const {identifier} = labelDefinition 189 const {data: preferences} = usePreferencesQuery() 190 const {mutate, variables} = usePreferencesSetContentLabelMutation() 191 const savedPref = 192 labelerDid && !isGlobalLabel 193 ? preferences?.moderationPrefs.labelers.find(l => l.did === labelerDid) 194 ?.labels[identifier] 195 : preferences?.moderationPrefs.labels[identifier] 196 const pref = 197 variables?.visibility ?? 198 savedPref ?? 199 labelDefinition.defaultSetting ?? 200 'warn' 201 202 // does the 'warn' setting make sense for this label? 203 const canWarn = !( 204 labelDefinition.blurs === 'none' && labelDefinition.severity === 'none' 205 ) 206 // is this label adult only? 207 const adultOnly = labelDefinition.flags.includes('adult') 208 // is this label disabled because it's adult only? 209 const adultDisabled = 210 adultOnly && !preferences?.moderationPrefs.adultContentEnabled 211 // are there any reasons we cant configure this label here? 212 const cantConfigure = isGlobalLabel || adultDisabled 213 const showConfig = !disabled && (gtPhone || !cantConfigure) 214 215 // adjust the pref based on whether warn is available 216 let prefAdjusted = pref 217 if (adultDisabled) { 218 prefAdjusted = 'hide' 219 } else if (!canWarn && pref === 'warn') { 220 prefAdjusted = 'ignore' 221 } 222 223 // grab localized descriptions of the label and its settings 224 const currentPrefLabel = useLabelBehaviorDescription( 225 labelDefinition, 226 prefAdjusted, 227 ) 228 const hideLabel = useLabelBehaviorDescription(labelDefinition, 'hide') 229 const warnLabel = useLabelBehaviorDescription(labelDefinition, 'warn') 230 const ignoreLabel = useLabelBehaviorDescription(labelDefinition, 'ignore') 231 const globalLabelStrings = useGlobalLabelStrings() 232 const labelStrings = getLabelStrings( 233 i18n.locale, 234 globalLabelStrings, 235 labelDefinition, 236 ) 237 238 return ( 239 <Outer> 240 <Content name={labelStrings.name} description={labelStrings.description}> 241 {cantConfigure && ( 242 <View style={[a.flex_row, a.gap_xs, a.align_center, a.mt_xs]}> 243 <CircleInfo size="sm" fill={t.atoms.text_contrast_high.color} /> 244 245 <Text 246 style={[ 247 t.atoms.text_contrast_medium, 248 a.font_semi_bold, 249 a.italic, 250 ]}> 251 {adultDisabled ? ( 252 <Trans>Adult content is disabled.</Trans> 253 ) : isGlobalLabel ? ( 254 <Trans> 255 Configured in{' '} 256 <InlineLinkText 257 label={_(msg`moderation settings`)} 258 to="/moderation" 259 style={a.text_sm}> 260 moderation settings 261 </InlineLinkText> 262 . 263 </Trans> 264 ) : null} 265 </Text> 266 </View> 267 )} 268 </Content> 269 270 {showConfig && ( 271 <> 272 {cantConfigure ? ( 273 <View 274 style={[ 275 {minHeight: 35}, 276 a.px_md, 277 a.py_md, 278 a.rounded_sm, 279 a.border, 280 t.atoms.border_contrast_low, 281 a.self_start, 282 ]}> 283 <Text emoji style={[a.font_semi_bold, t.atoms.text_contrast_low]}> 284 {currentPrefLabel} 285 </Text> 286 </View> 287 ) : ( 288 <Buttons 289 name={labelStrings.name.toLowerCase()} 290 values={[pref]} 291 onChange={values => { 292 mutate({ 293 label: identifier, 294 visibility: values[0] as LabelPreference, 295 labelerDid, 296 }) 297 }} 298 ignoreLabel={ignoreLabel} 299 warnLabel={canWarn ? warnLabel : undefined} 300 hideLabel={hideLabel} 301 /> 302 )} 303 </> 304 )} 305 </Outer> 306 ) 307}