Add "Who can reply" controls [WIP] (#1954)

* Add threadgating

* UI improvements

* More ui work

* Remove comment

* Tweak colors

* Add missing keys

* Tweak sizing

* Only show composer option on non-reply

* Flex wrap fix

* Move the threadgate control to the top of the composer
This commit is contained in:
Paul Frazee 2023-12-10 12:01:34 -08:00 committed by GitHub
parent f5d014d4c7
commit 28fa5e4919
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 883 additions and 148 deletions

View file

@ -35,6 +35,7 @@ import {shortenLinks} from 'lib/strings/rich-text-manip'
import {toShortUrl} from 'lib/strings/url-helpers'
import {SelectPhotoBtn} from './photos/SelectPhotoBtn'
import {OpenCameraBtn} from './photos/OpenCameraBtn'
import {ThreadgateBtn} from './threadgate/ThreadgateBtn'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useExternalLinkFetch} from './useExternalLinkFetch'
@ -61,6 +62,7 @@ import {useProfileQuery} from '#/state/queries/profile'
import {useComposerControls} from '#/state/shell/composer'
import {until} from '#/lib/async/until'
import {emitPostCreated} from '#/state/events'
import {ThreadgateSetting} from '#/state/queries/threadgate'
type Props = ComposerOpts
export const ComposePost = observer(function ComposePost({
@ -105,6 +107,7 @@ export const ComposePost = observer(function ComposePost({
)
const {extLink, setExtLink} = useExternalLinkFetch({setQuote})
const [labels, setLabels] = useState<string[]>([])
const [threadgate, setThreadgate] = useState<ThreadgateSetting[]>([])
const [suggestedLinks, setSuggestedLinks] = useState<Set<string>>(new Set())
const gallery = useMemo(() => new GalleryModel(), [])
const onClose = useCallback(() => {
@ -220,6 +223,7 @@ export const ComposePost = observer(function ComposePost({
quote,
extLink,
labels,
threadgate,
onStateChange: setProcessingState,
langs: toPostLanguages(langPrefs.postLanguage),
})
@ -296,6 +300,12 @@ export const ComposePost = observer(function ComposePost({
onChange={setLabels}
hasMedia={hasMedia}
/>
{replyTo ? null : (
<ThreadgateBtn
threadgate={threadgate}
onChange={setThreadgate}
/>
)}
{canPost ? (
<TouchableOpacity
testID="composerPublishBtn"
@ -458,9 +468,11 @@ const styles = StyleSheet.create({
topbar: {
flexDirection: 'row',
alignItems: 'center',
paddingTop: 6,
paddingBottom: 4,
paddingHorizontal: 20,
height: 55,
gap: 4,
},
topbarDesktop: {
paddingTop: 10,
@ -470,6 +482,7 @@ const styles = StyleSheet.create({
borderRadius: 20,
paddingHorizontal: 20,
paddingVertical: 6,
marginLeft: 12,
},
errorLine: {
flexDirection: 'row',

View file

@ -49,6 +49,6 @@ const styles = StyleSheet.create({
paddingLeft: 12,
},
labelDesktopWeb: {
paddingLeft: 20,
paddingLeft: 12,
},
})

View file

@ -38,7 +38,7 @@ export function LabelsBtn({
}
openModal({name: 'self-label', labels, hasMedia, onChange})
}}>
<ShieldExclamation style={pal.link} size={26} />
<ShieldExclamation style={pal.link} size={24} />
{labels.length > 0 ? (
<FontAwesomeIcon
icon="check"
@ -54,8 +54,7 @@ const styles = StyleSheet.create({
button: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 14,
marginRight: 4,
paddingHorizontal: 6,
},
dimmed: {
opacity: 0.4,

View file

@ -98,7 +98,8 @@ const styles = StyleSheet.create({
backgroundColor: 'transparent',
border: 'none',
paddingTop: 4,
paddingHorizontal: 10,
paddingLeft: 12,
paddingRight: 12,
cursor: 'pointer',
},
picker: {

View file

@ -0,0 +1,68 @@
import React from 'react'
import {TouchableOpacity, StyleSheet} from 'react-native'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {usePalette} from 'lib/hooks/usePalette'
import {useAnalytics} from 'lib/analytics/analytics'
import {HITSLOP_10} from 'lib/constants'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
import {useModalControls} from '#/state/modals'
import {ThreadgateSetting} from '#/state/queries/threadgate'
export function ThreadgateBtn({
threadgate,
onChange,
}: {
threadgate: ThreadgateSetting[]
onChange: (v: ThreadgateSetting[]) => void
}) {
const pal = usePalette('default')
const {track} = useAnalytics()
const {_} = useLingui()
const {openModal} = useModalControls()
const onPress = () => {
track('Composer:ThreadgateOpened')
openModal({
name: 'threadgate',
settings: threadgate,
onChange,
})
}
return (
<TouchableOpacity
testID="openReplyGateButton"
onPress={onPress}
style={styles.button}
hitSlop={HITSLOP_10}
accessibilityRole="button"
accessibilityLabel={_(msg`Who can reply`)}
accessibilityHint="">
<FontAwesomeIcon
icon={['far', 'comments']}
style={pal.link as FontAwesomeIconStyle}
size={24}
/>
{threadgate.length ? (
<FontAwesomeIcon
icon="check"
size={16}
style={pal.link as FontAwesomeIconStyle}
/>
) : null}
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
button: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 6,
gap: 4,
},
})