Composer - Self label dialog ALF rewrite (#4354)
This commit is contained in:
@@ -499,10 +499,6 @@ export const ComposePost = ({
|
||||
openEmojiPicker?.(textInput.current?.getCursorPosition())
|
||||
}, [openEmojiPicker])
|
||||
|
||||
const focusTextInput = useCallback(() => {
|
||||
textInput.current?.focus()
|
||||
}, [])
|
||||
|
||||
const onSelectGif = useCallback((gif: Gif) => {
|
||||
dispatch({type: 'embed_add_gif', gif})
|
||||
}, [])
|
||||
@@ -808,11 +804,7 @@ export const ComposePost = ({
|
||||
disabled={!canSelectImages}
|
||||
onAdd={onImageAdd}
|
||||
/>
|
||||
<SelectGifBtn
|
||||
onClose={focusTextInput}
|
||||
onSelectGif={onSelectGif}
|
||||
disabled={hasMedia}
|
||||
/>
|
||||
<SelectGifBtn onSelectGif={onSelectGif} disabled={hasMedia} />
|
||||
{!isMobile ? (
|
||||
<Button
|
||||
onPress={onEmojiButtonPress}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import React from 'react'
|
||||
import {Keyboard, StyleSheet} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {Keyboard, LayoutAnimation, View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {ShieldExclamation} from 'lib/icons'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {Button} from 'view/com/util/forms/Button'
|
||||
import {ShieldExclamation} from '#/lib/icons'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import * as ToggleButton from '#/components/forms/ToggleButton'
|
||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn']
|
||||
|
||||
export function LabelsBtn({
|
||||
labels,
|
||||
@@ -20,48 +22,177 @@ export function LabelsBtn({
|
||||
hasMedia: boolean
|
||||
onChange: (v: string[]) => void
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const control = Dialog.useDialogControl()
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {openModal} = useModalControls()
|
||||
|
||||
const removeAdultLabel = () => {
|
||||
const final = labels.filter(l => !ADULT_CONTENT_LABELS.includes(l))
|
||||
onChange(final)
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||
}
|
||||
|
||||
const hasAdultSelection =
|
||||
labels.includes('sexual') ||
|
||||
labels.includes('nudity') ||
|
||||
labels.includes('porn')
|
||||
|
||||
if (!hasMedia && hasAdultSelection) {
|
||||
removeAdultLabel()
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="default-light"
|
||||
testID="labelsBtn"
|
||||
style={[styles.button, !hasMedia && styles.dimmed]}
|
||||
accessibilityLabel={_(msg`Content warnings`)}
|
||||
accessibilityHint=""
|
||||
onPress={() => {
|
||||
if (isNative) {
|
||||
if (Keyboard.isVisible()) {
|
||||
Keyboard.dismiss()
|
||||
}
|
||||
}
|
||||
openModal({name: 'self-label', labels, hasMedia, onChange})
|
||||
}}>
|
||||
<ShieldExclamation style={pal.link} size={24} />
|
||||
{labels.length > 0 ? (
|
||||
<FontAwesomeIcon
|
||||
icon="check"
|
||||
size={16}
|
||||
style={pal.link as FontAwesomeIconStyle}
|
||||
<>
|
||||
<Button
|
||||
testID="labelsBtn"
|
||||
style={!hasMedia && {opacity: 0.4}}
|
||||
label={_(msg`Content warnings`)}
|
||||
accessibilityHint={_(
|
||||
msg`Opens a dialog to add a content warning to your post`,
|
||||
)}
|
||||
onPress={() => {
|
||||
Keyboard.dismiss()
|
||||
control.open()
|
||||
}}>
|
||||
<ShieldExclamation style={{color: t.palette.primary_500}} size={24} />
|
||||
{labels.length > 0 ? (
|
||||
<Check size="sm" fill={t.palette.primary_500} />
|
||||
) : null}
|
||||
</Button>
|
||||
|
||||
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
||||
<Dialog.Handle />
|
||||
<DialogInner
|
||||
labels={labels}
|
||||
onChange={onChange}
|
||||
hasAdultSelection={hasAdultSelection}
|
||||
hasMedia={hasMedia}
|
||||
removeAdultLabel={removeAdultLabel}
|
||||
/>
|
||||
) : null}
|
||||
</Button>
|
||||
</Dialog.Outer>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 2,
|
||||
paddingHorizontal: 6,
|
||||
},
|
||||
dimmed: {
|
||||
opacity: 0.4,
|
||||
},
|
||||
label: {
|
||||
maxWidth: 100,
|
||||
},
|
||||
})
|
||||
function DialogInner({
|
||||
labels,
|
||||
onChange,
|
||||
hasAdultSelection,
|
||||
hasMedia,
|
||||
removeAdultLabel,
|
||||
}: {
|
||||
labels: string[]
|
||||
onChange: (v: string[]) => void
|
||||
hasAdultSelection: boolean
|
||||
hasMedia: boolean
|
||||
removeAdultLabel: () => void
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const control = Dialog.useDialogContext()
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<Dialog.ScrollableInner
|
||||
label={_(msg`Add a content warning`)}
|
||||
style={[{maxWidth: 500}, a.w_full]}>
|
||||
<View style={[a.flex_1, a.gap_md]}>
|
||||
<Text style={[a.text_2xl, a.font_bold]}>
|
||||
<Trans>Add a content warning</Trans>
|
||||
</Text>
|
||||
|
||||
<View
|
||||
style={[
|
||||
a.border,
|
||||
a.p_md,
|
||||
t.atoms.border_contrast_high,
|
||||
a.rounded_md,
|
||||
]}>
|
||||
<View
|
||||
style={[a.flex_row, a.align_center, a.justify_between, a.pb_sm]}>
|
||||
<Text style={[a.font_bold, a.text_lg]}>
|
||||
<Trans>Adult Content</Trans>
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
label={_(msg`Remove`)}
|
||||
variant="ghost"
|
||||
color="primary"
|
||||
size="tiny"
|
||||
onPress={removeAdultLabel}
|
||||
disabled={!hasAdultSelection}
|
||||
style={{opacity: hasAdultSelection ? 1 : 0}}
|
||||
aria-hidden={!hasAdultSelection}>
|
||||
<ButtonText>
|
||||
<Trans>Remove</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
{hasMedia ? (
|
||||
<>
|
||||
<ToggleButton.Group
|
||||
label={_(msg`Adult Content labels`)}
|
||||
values={labels}
|
||||
onChange={values => {
|
||||
onChange(values)
|
||||
LayoutAnimation.configureNext(
|
||||
LayoutAnimation.Presets.easeInEaseOut,
|
||||
)
|
||||
}}>
|
||||
<ToggleButton.Button name="sexual" label={_(msg`Suggestive`)}>
|
||||
<ToggleButton.ButtonText>
|
||||
<Trans>Suggestive</Trans>
|
||||
</ToggleButton.ButtonText>
|
||||
</ToggleButton.Button>
|
||||
<ToggleButton.Button name="nudity" label={_(msg`Nudity`)}>
|
||||
<ToggleButton.ButtonText>
|
||||
<Trans>Nudity</Trans>
|
||||
</ToggleButton.ButtonText>
|
||||
</ToggleButton.Button>
|
||||
<ToggleButton.Button name="porn" label={_(msg`Porn`)}>
|
||||
<ToggleButton.ButtonText>
|
||||
<Trans>Porn</Trans>
|
||||
</ToggleButton.ButtonText>
|
||||
</ToggleButton.Button>
|
||||
</ToggleButton.Group>
|
||||
|
||||
<Text style={[a.mt_sm, t.atoms.text_contrast_medium]}>
|
||||
{labels.includes('sexual') ? (
|
||||
<Trans>Pictures meant for adults.</Trans>
|
||||
) : labels.includes('nudity') ? (
|
||||
<Trans>Artistic or non-erotic nudity.</Trans>
|
||||
) : labels.includes('porn') ? (
|
||||
<Trans>Sexual activity or erotic nudity.</Trans>
|
||||
) : (
|
||||
<Trans>If none are selected, suitable for all ages.</Trans>
|
||||
)}
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<View>
|
||||
<Text style={t.atoms.text_contrast_medium}>
|
||||
<Trans>
|
||||
<Text style={[a.font_bold, t.atoms.text_contrast_medium]}>
|
||||
Not Applicable.
|
||||
</Text>{' '}
|
||||
This warning is only available for posts with media attached.
|
||||
</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Button
|
||||
label={_(msg`Done`)}
|
||||
onPress={() => control.close()}
|
||||
color="primary"
|
||||
size="large"
|
||||
variant="solid"
|
||||
style={a.mt_xl}>
|
||||
<ButtonText>
|
||||
<Trans>Done</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</Dialog.ScrollableInner>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {GifSelectDialog} from '#/components/dialogs/GifSelect'
|
||||
import {GifSquare_Stroke2_Corner0_Rounded as GifIcon} from '#/components/icons/Gif'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
onClose?: () => void
|
||||
onSelectGif: (gif: Gif) => void
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user