From 29aaf09a8b8b199b249cef9123673022fde11c4f Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Mon, 24 Jun 2024 23:15:11 +0100 Subject: Composer - replace threadgate modal with alf dialog (#4329) * replace threadgate modal with alf dialog * add accessibility to selectable * add aria * hide spinner once fetched * add `hasOpenDialogs` value to context * remove state * Rm loading state * Update the threadgate dialog button theming * Factor out the threadgate editor and add editing to post views * Mark messages for localization * Use colors from mute dialog * Remove unnecessary effect * Reset state on dialog dismiss * Clearer CTA * Fix bugs * Scope keyboard fix * Rm getAreDialogsActive (no longer needed) --------- Co-authored-by: Dan Abramov Co-authored-by: Paul Frazee --- src/components/dialogs/ThreadgateEditor.tsx | 218 ++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 src/components/dialogs/ThreadgateEditor.tsx (limited to 'src/components/dialogs/ThreadgateEditor.tsx') diff --git a/src/components/dialogs/ThreadgateEditor.tsx b/src/components/dialogs/ThreadgateEditor.tsx new file mode 100644 index 000000000..75383764f --- /dev/null +++ b/src/components/dialogs/ThreadgateEditor.tsx @@ -0,0 +1,218 @@ +import React from 'react' +import {StyleProp, View, ViewStyle} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import isEqual from 'lodash.isequal' + +import {useMyListsQuery} from '#/state/queries/my-lists' +import {ThreadgateSetting} from '#/state/queries/threadgate' +import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import * as Dialog from '#/components/Dialog' +import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' +import {Text} from '#/components/Typography' + +interface ThreadgateEditorDialogProps { + control: Dialog.DialogControlProps + threadgate: ThreadgateSetting[] + onChange?: (v: ThreadgateSetting[]) => void + onConfirm?: (v: ThreadgateSetting[]) => void +} + +export function ThreadgateEditorDialog({ + control, + threadgate, + onChange, + onConfirm, +}: ThreadgateEditorDialogProps) { + return ( + + + + + ) +} + +function DialogContent({ + seedThreadgate, + onChange, + onConfirm, +}: { + seedThreadgate: ThreadgateSetting[] + onChange?: (v: ThreadgateSetting[]) => void + onConfirm?: (v: ThreadgateSetting[]) => void +}) { + const {_} = useLingui() + const control = Dialog.useDialogContext() + const {data: lists} = useMyListsQuery('curate') + const [draft, setDraft] = React.useState(seedThreadgate) + + const [prevSeedThreadgate, setPrevSeedThreadgate] = + React.useState(seedThreadgate) + if (seedThreadgate !== prevSeedThreadgate) { + // New data flowed from above (e.g. due to update coming through). + setPrevSeedThreadgate(seedThreadgate) + setDraft(seedThreadgate) // Reset draft. + } + + function updateThreadgate(nextThreadgate: ThreadgateSetting[]) { + setDraft(nextThreadgate) + onChange?.(nextThreadgate) + } + + const onPressEverybody = () => { + updateThreadgate([]) + } + + const onPressNobody = () => { + updateThreadgate([{type: 'nobody'}]) + } + + const onPressAudience = (setting: ThreadgateSetting) => { + // remove nobody + let newSelected = draft.filter(v => v.type !== 'nobody') + // toggle + const i = newSelected.findIndex(v => isEqual(v, setting)) + if (i === -1) { + newSelected.push(setting) + } else { + newSelected.splice(i, 1) + } + updateThreadgate(newSelected) + } + + const doneLabel = onConfirm ? _(msg`Save`) : _(msg`Done`) + return ( + + + + Chose who can reply + + + Either choose "Everybody" or "Nobody" + + + + v.type === 'nobody')} + onPress={onPressNobody} + style={{flex: 1}} + /> + + + Or combine these options: + + + v.type === 'mention')} + onPress={() => onPressAudience({type: 'mention'})} + /> + v.type === 'following')} + onPress={() => onPressAudience({type: 'following'})} + /> + {lists && lists.length > 0 + ? lists.map(list => ( + v.type === 'list' && v.list === list.uri) + } + onPress={() => + onPressAudience({type: 'list', list: list.uri}) + } + /> + )) + : // No loading states to avoid jumps for the common case (no lists) + null} + + + + + + ) +} + +function Selectable({ + label, + isSelected, + onPress, + style, +}: { + label: string + isSelected: boolean + onPress: () => void + style?: StyleProp +}) { + const t = useTheme() + return ( + + ) +} -- cgit 1.4.1