self label enhoggening
This commit is contained in:
@@ -48,13 +48,6 @@ export interface DeleteAccountModal {
|
|||||||
name: 'delete-account'
|
name: 'delete-account'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelfLabelModal {
|
|
||||||
name: 'self-label'
|
|
||||||
labels: string[]
|
|
||||||
hasMedia: boolean
|
|
||||||
onChange: (labels: string[]) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChangeHandleModal {
|
export interface ChangeHandleModal {
|
||||||
name: 'change-handle'
|
name: 'change-handle'
|
||||||
onChanged: () => void
|
onChanged: () => void
|
||||||
@@ -127,7 +120,6 @@ export type Modal =
|
|||||||
|
|
||||||
// Posts
|
// Posts
|
||||||
| CropImageModal
|
| CropImageModal
|
||||||
| SelfLabelModal
|
|
||||||
|
|
||||||
// Bluesky access
|
// Bluesky access
|
||||||
| WaitlistModal
|
| WaitlistModal
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Keyboard, StyleSheet} from 'react-native'
|
import {Keyboard, View} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
|
|
||||||
import {msg} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useModalControls} from '#/state/modals'
|
import {ShieldExclamation} from '#/lib/icons'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {isNative} from '#/platform/detection'
|
||||||
import {ShieldExclamation} from 'lib/icons'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {isNative} from 'platform/detection'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import {Button} from 'view/com/util/forms/Button'
|
import * as Dialog from '#/components/Dialog'
|
||||||
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import {SelectableBtn} from '../../util/forms/SelectableBtn'
|
||||||
|
|
||||||
|
const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn']
|
||||||
|
|
||||||
export function LabelsBtn({
|
export function LabelsBtn({
|
||||||
labels,
|
labels,
|
||||||
@@ -20,48 +23,161 @@ export function LabelsBtn({
|
|||||||
hasMedia: boolean
|
hasMedia: boolean
|
||||||
onChange: (v: string[]) => void
|
onChange: (v: string[]) => void
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const control = Dialog.useDialogControl()
|
||||||
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {openModal} = useModalControls()
|
|
||||||
|
const toggleAdultLabel = (label: string) => {
|
||||||
|
const hadLabel = labels.includes(label)
|
||||||
|
const stripped = labels.filter(l => !ADULT_CONTENT_LABELS.includes(l))
|
||||||
|
const final = !hadLabel ? stripped.concat([label]) : stripped
|
||||||
|
onChange(final)
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeAdultLabel = () => {
|
||||||
|
const final = labels.filter(l => !ADULT_CONTENT_LABELS.includes(l))
|
||||||
|
onChange(final)
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAdultSelection =
|
||||||
|
labels.includes('sexual') ||
|
||||||
|
labels.includes('nudity') ||
|
||||||
|
labels.includes('porn')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<>
|
||||||
type="default-light"
|
<Button
|
||||||
testID="labelsBtn"
|
testID="labelsBtn"
|
||||||
style={[styles.button, !hasMedia && styles.dimmed]}
|
style={!hasMedia && {opacity: 0.4}}
|
||||||
accessibilityLabel={_(msg`Content warnings`)}
|
label={_(msg`Content warnings`)}
|
||||||
accessibilityHint=""
|
accessibilityHint={_(
|
||||||
onPress={() => {
|
msg`Opens a dialog to add a content warning to your post`,
|
||||||
if (isNative) {
|
)}
|
||||||
if (Keyboard.isVisible()) {
|
onPress={() => {
|
||||||
|
if (isNative && Keyboard.isVisible()) {
|
||||||
Keyboard.dismiss()
|
Keyboard.dismiss()
|
||||||
}
|
}
|
||||||
}
|
control.open()
|
||||||
openModal({name: 'self-label', labels, hasMedia, onChange})
|
}}>
|
||||||
}}>
|
<ShieldExclamation style={{color: t.palette.primary_500}} size={24} />
|
||||||
<ShieldExclamation style={pal.link} size={24} />
|
{labels.length > 0 ? (
|
||||||
{labels.length > 0 ? (
|
<Check size="md" fill={t.palette.primary_500} />
|
||||||
<FontAwesomeIcon
|
) : null}
|
||||||
icon="check"
|
</Button>
|
||||||
size={16}
|
|
||||||
style={pal.link as FontAwesomeIconStyle}
|
<Dialog.Outer control={control}>
|
||||||
/>
|
<Dialog.Handle />
|
||||||
) : null}
|
<Dialog.ScrollableInner
|
||||||
</Button>
|
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>
|
||||||
|
{hasAdultSelection ? (
|
||||||
|
<Button
|
||||||
|
label={_(msg`Remove`)}
|
||||||
|
variant="ghost"
|
||||||
|
onPress={removeAdultLabel}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Remove</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
{hasMedia ? (
|
||||||
|
<>
|
||||||
|
<View style={a.flex_row}>
|
||||||
|
<SelectableBtn
|
||||||
|
testID="sexualLabelBtn"
|
||||||
|
selected={labels.includes('sexual')}
|
||||||
|
left
|
||||||
|
label={_(msg`Suggestive`)}
|
||||||
|
onSelect={() => toggleAdultLabel('sexual')}
|
||||||
|
accessibilityHint=""
|
||||||
|
style={a.flex_1}
|
||||||
|
/>
|
||||||
|
<SelectableBtn
|
||||||
|
testID="nudityLabelBtn"
|
||||||
|
selected={labels.includes('nudity')}
|
||||||
|
label={_(msg`Nudity`)}
|
||||||
|
onSelect={() => toggleAdultLabel('nudity')}
|
||||||
|
accessibilityHint=""
|
||||||
|
style={a.flex_1}
|
||||||
|
/>
|
||||||
|
<SelectableBtn
|
||||||
|
testID="pornLabelBtn"
|
||||||
|
selected={labels.includes('porn')}
|
||||||
|
label={_(msg`Porn`)}
|
||||||
|
right
|
||||||
|
onSelect={() => toggleAdultLabel('porn')}
|
||||||
|
accessibilityHint=""
|
||||||
|
style={a.flex_1}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<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()}
|
||||||
|
onAccessibilityEscape={control.close}
|
||||||
|
color="primary"
|
||||||
|
size="medium"
|
||||||
|
variant="solid"
|
||||||
|
style={a.mt_xl}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Done</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</Dialog.ScrollableInner>
|
||||||
|
</Dialog.Outer>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
button: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
paddingVertical: 2,
|
|
||||||
paddingHorizontal: 6,
|
|
||||||
},
|
|
||||||
dimmed: {
|
|
||||||
opacity: 0.4,
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
maxWidth: 100,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguages
|
|||||||
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
||||||
import * as LinkWarningModal from './LinkWarning'
|
import * as LinkWarningModal from './LinkWarning'
|
||||||
import * as ListAddUserModal from './ListAddRemoveUsers'
|
import * as ListAddUserModal from './ListAddRemoveUsers'
|
||||||
import * as SelfLabelModal from './SelfLabel'
|
|
||||||
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
|
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
|
||||||
import * as VerifyEmailModal from './VerifyEmail'
|
import * as VerifyEmailModal from './VerifyEmail'
|
||||||
|
|
||||||
@@ -70,9 +69,6 @@ export function ModalsContainer() {
|
|||||||
} else if (activeModal?.name === 'delete-account') {
|
} else if (activeModal?.name === 'delete-account') {
|
||||||
snapPoints = DeleteAccountModal.snapPoints
|
snapPoints = DeleteAccountModal.snapPoints
|
||||||
element = <DeleteAccountModal.Component />
|
element = <DeleteAccountModal.Component />
|
||||||
} else if (activeModal?.name === 'self-label') {
|
|
||||||
snapPoints = SelfLabelModal.snapPoints
|
|
||||||
element = <SelfLabelModal.Component {...activeModal} />
|
|
||||||
} else if (activeModal?.name === 'change-handle') {
|
} else if (activeModal?.name === 'change-handle') {
|
||||||
snapPoints = ChangeHandleModal.snapPoints
|
snapPoints = ChangeHandleModal.snapPoints
|
||||||
element = <ChangeHandleModal.Component {...activeModal} />
|
element = <ChangeHandleModal.Component {...activeModal} />
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguages
|
|||||||
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
|
||||||
import * as LinkWarningModal from './LinkWarning'
|
import * as LinkWarningModal from './LinkWarning'
|
||||||
import * as ListAddUserModal from './ListAddRemoveUsers'
|
import * as ListAddUserModal from './ListAddRemoveUsers'
|
||||||
import * as SelfLabelModal from './SelfLabel'
|
|
||||||
import * as UserAddRemoveLists from './UserAddRemoveLists'
|
import * as UserAddRemoveLists from './UserAddRemoveLists'
|
||||||
import * as VerifyEmailModal from './VerifyEmail'
|
import * as VerifyEmailModal from './VerifyEmail'
|
||||||
|
|
||||||
@@ -75,8 +74,6 @@ function Modal({modal}: {modal: ModalIface}) {
|
|||||||
element = <CropImageModal.Component {...modal} />
|
element = <CropImageModal.Component {...modal} />
|
||||||
} else if (modal.name === 'delete-account') {
|
} else if (modal.name === 'delete-account') {
|
||||||
element = <DeleteAccountModal.Component />
|
element = <DeleteAccountModal.Component />
|
||||||
} else if (modal.name === 'self-label') {
|
|
||||||
element = <SelfLabelModal.Component {...modal} />
|
|
||||||
} else if (modal.name === 'change-handle') {
|
} else if (modal.name === 'change-handle') {
|
||||||
element = <ChangeHandleModal.Component {...modal} />
|
element = <ChangeHandleModal.Component {...modal} />
|
||||||
} else if (modal.name === 'invite-codes') {
|
} else if (modal.name === 'invite-codes') {
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
import React, {useState} from 'react'
|
|
||||||
import {StyleSheet, TouchableOpacity, 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 {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
|
||||||
import {colors, s} from 'lib/styles'
|
|
||||||
import {isWeb} from 'platform/detection'
|
|
||||||
import {ScrollView} from 'view/com/modals/util'
|
|
||||||
import {Button} from '../util/forms/Button'
|
|
||||||
import {SelectableBtn} from '../util/forms/SelectableBtn'
|
|
||||||
import {Text} from '../util/text/Text'
|
|
||||||
|
|
||||||
const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn']
|
|
||||||
|
|
||||||
export const snapPoints = ['50%']
|
|
||||||
|
|
||||||
export function Component({
|
|
||||||
labels,
|
|
||||||
hasMedia,
|
|
||||||
onChange,
|
|
||||||
}: {
|
|
||||||
labels: string[]
|
|
||||||
hasMedia: boolean
|
|
||||||
onChange: (labels: string[]) => void
|
|
||||||
}) {
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const {closeModal} = useModalControls()
|
|
||||||
const {isMobile} = useWebMediaQueries()
|
|
||||||
const [selected, setSelected] = useState(labels)
|
|
||||||
const {_} = useLingui()
|
|
||||||
|
|
||||||
const toggleAdultLabel = (label: string) => {
|
|
||||||
const hadLabel = selected.includes(label)
|
|
||||||
const stripped = selected.filter(l => !ADULT_CONTENT_LABELS.includes(l))
|
|
||||||
const final = !hadLabel ? stripped.concat([label]) : stripped
|
|
||||||
setSelected(final)
|
|
||||||
onChange(final)
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeAdultLabel = () => {
|
|
||||||
const final = selected.filter(l => !ADULT_CONTENT_LABELS.includes(l))
|
|
||||||
setSelected(final)
|
|
||||||
onChange(final)
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasAdultSelection =
|
|
||||||
selected.includes('sexual') ||
|
|
||||||
selected.includes('nudity') ||
|
|
||||||
selected.includes('porn')
|
|
||||||
return (
|
|
||||||
<View testID="selfLabelModal" style={[pal.view, styles.container]}>
|
|
||||||
<View style={styles.titleSection}>
|
|
||||||
<Text type="title-lg" style={[pal.text, styles.title]}>
|
|
||||||
<Trans>Add a content warning</Trans>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<ScrollView>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.section,
|
|
||||||
pal.border,
|
|
||||||
{borderBottomWidth: 1, paddingHorizontal: isMobile ? 20 : 0},
|
|
||||||
]}>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
paddingBottom: 8,
|
|
||||||
}}>
|
|
||||||
<Text type="title" style={pal.text}>
|
|
||||||
<Trans>Adult Content</Trans>
|
|
||||||
</Text>
|
|
||||||
{hasAdultSelection ? (
|
|
||||||
<Button
|
|
||||||
type="default-light"
|
|
||||||
onPress={removeAdultLabel}
|
|
||||||
style={{paddingTop: 0, paddingBottom: 0, paddingRight: 0}}>
|
|
||||||
<Text type="md" style={pal.link}>
|
|
||||||
<Trans>Remove</Trans>
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
</View>
|
|
||||||
{hasMedia ? (
|
|
||||||
<>
|
|
||||||
<View style={s.flexRow}>
|
|
||||||
<SelectableBtn
|
|
||||||
testID="sexualLabelBtn"
|
|
||||||
selected={selected.includes('sexual')}
|
|
||||||
left
|
|
||||||
label={_(msg`Suggestive`)}
|
|
||||||
onSelect={() => toggleAdultLabel('sexual')}
|
|
||||||
accessibilityHint=""
|
|
||||||
style={s.flex1}
|
|
||||||
/>
|
|
||||||
<SelectableBtn
|
|
||||||
testID="nudityLabelBtn"
|
|
||||||
selected={selected.includes('nudity')}
|
|
||||||
label={_(msg`Nudity`)}
|
|
||||||
onSelect={() => toggleAdultLabel('nudity')}
|
|
||||||
accessibilityHint=""
|
|
||||||
style={s.flex1}
|
|
||||||
/>
|
|
||||||
<SelectableBtn
|
|
||||||
testID="pornLabelBtn"
|
|
||||||
selected={selected.includes('porn')}
|
|
||||||
label={_(msg`Porn`)}
|
|
||||||
right
|
|
||||||
onSelect={() => toggleAdultLabel('porn')}
|
|
||||||
accessibilityHint=""
|
|
||||||
style={s.flex1}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={[pal.text, styles.adultExplainer]}>
|
|
||||||
{selected.includes('sexual') ? (
|
|
||||||
<Trans>Pictures meant for adults.</Trans>
|
|
||||||
) : selected.includes('nudity') ? (
|
|
||||||
<Trans>Artistic or non-erotic nudity.</Trans>
|
|
||||||
) : selected.includes('porn') ? (
|
|
||||||
<Trans>Sexual activity or erotic nudity.</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>If none are selected, suitable for all ages.</Trans>
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<View>
|
|
||||||
<Text style={[pal.textLight]}>
|
|
||||||
<Trans>
|
|
||||||
<Text type="md-bold" style={[pal.textLight]}>
|
|
||||||
Not Applicable.
|
|
||||||
</Text>{' '}
|
|
||||||
This warning is only available for posts with media attached.
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
<View style={[styles.btnContainer, pal.borderDark]}>
|
|
||||||
<TouchableOpacity
|
|
||||||
testID="confirmBtn"
|
|
||||||
onPress={() => {
|
|
||||||
closeModal()
|
|
||||||
}}
|
|
||||||
style={styles.btn}
|
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={_(msg`Confirm`)}
|
|
||||||
accessibilityHint="">
|
|
||||||
<Text style={[s.white, s.bold, s.f18]}>
|
|
||||||
<Trans context="action">Done</Trans>
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
paddingBottom: isWeb ? 0 : 40,
|
|
||||||
},
|
|
||||||
titleSection: {
|
|
||||||
paddingTop: isWeb ? 0 : 4,
|
|
||||||
paddingBottom: isWeb ? 14 : 10,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
textAlign: 'center',
|
|
||||||
fontWeight: '600',
|
|
||||||
marginBottom: 5,
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
textAlign: 'center',
|
|
||||||
paddingHorizontal: 32,
|
|
||||||
},
|
|
||||||
section: {
|
|
||||||
borderTopWidth: 1,
|
|
||||||
paddingVertical: 20,
|
|
||||||
},
|
|
||||||
adultExplainer: {
|
|
||||||
paddingLeft: 5,
|
|
||||||
paddingTop: 10,
|
|
||||||
},
|
|
||||||
btn: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
borderRadius: 32,
|
|
||||||
padding: 14,
|
|
||||||
backgroundColor: colors.blue3,
|
|
||||||
},
|
|
||||||
btnContainer: {
|
|
||||||
paddingTop: 20,
|
|
||||||
paddingHorizontal: 20,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user