[Threadgate] Tweak threadgate buttons (#9173)
* tweak in-post threadgate button * tweak composer threadgate button * reduce date length slightly * pressed styles * make date length depend on breakpoint * add chevron to label btn * add tiny chevron, special-case button icon width * [Threadgate] Add hint (#9350) * get tooltip working on web * add compatibility layer for working in iOS sheets * add timeout to profile tooltip now that it appears instantly * rm debug code * Update ThreadgateBtn.tsx Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * remeasure when keyboard changes --------- Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * fix types * [Threadgate] Refresh dialog (#9342) * wip new ui * update threadgate dialog with new designs * restore nobody option * relayout android sheet when ratio changes * fix ratio changing case in bottom sheet * timebox reached, use setTimeout * update panel styles * missing imports * extract out Panel * tweak layout animation * fix icon color * use same color mechamism for icon as text * restore the header * refreshed toggle styles (#9343) * [Threadgate] Persist settings (#9341) * add persist toggle to threadgate dialog * move state back down * sort out spacing * wire up query * @surfdude29 tweaks * use tiny chevron in WhoCanReply * wait for prefetch before opening * move Panel into the Toggle namespace * default -> pref * use medium date length * rm hover state from web selects, fix border radius * fix key issue in Selects --------- Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
This commit is contained in:
@@ -1,17 +1,31 @@
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import {Keyboard, type StyleProp, type ViewStyle} from 'react-native'
|
||||
import {type AnimatedStyle} from 'react-native-reanimated'
|
||||
import {type AppBskyFeedPostgate} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import deepEqual from 'lodash.isequal'
|
||||
|
||||
import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {type ThreadgateAllowUISetting} from '#/state/queries/threadgate'
|
||||
import {native} from '#/alf'
|
||||
import {usePostInteractionSettingsMutation} from '#/state/queries/post-interaction-settings'
|
||||
import {createPostgateRecord} from '#/state/queries/postgate/util'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {
|
||||
type ThreadgateAllowUISetting,
|
||||
threadgateAllowUISettingToAllowRecordValue,
|
||||
threadgateRecordToAllowUISetting,
|
||||
} from '#/state/queries/threadgate'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {PostInteractionSettingsControlledDialog} from '#/components/dialogs/PostInteractionSettingsDialog'
|
||||
import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe'
|
||||
import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group'
|
||||
import {TinyChevronBottom_Stroke2_Corner0_Rounded as TinyChevronIcon} from '#/components/icons/Chevron'
|
||||
import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Globe'
|
||||
import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
|
||||
import * as Tooltip from '#/components/Tooltip'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useThreadgateNudged} from '#/storage/hooks/threadgate-nudged'
|
||||
|
||||
export function ThreadgateBtn({
|
||||
postgate,
|
||||
@@ -29,15 +43,82 @@ export function ThreadgateBtn({
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const control = Dialog.useDialogControl()
|
||||
const [threadgateNudged, setThreadgateNudged] = useThreadgateNudged()
|
||||
const [showTooltip, setShowTooltip] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!threadgateNudged) {
|
||||
const timeout = setTimeout(() => {
|
||||
setShowTooltip(true)
|
||||
}, 1000)
|
||||
return () => clearTimeout(timeout)
|
||||
}
|
||||
}, [threadgateNudged])
|
||||
|
||||
const onDismissTooltip = (visible: boolean) => {
|
||||
if (visible) return
|
||||
setThreadgateNudged(true)
|
||||
setShowTooltip(false)
|
||||
}
|
||||
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const [persist, setPersist] = useState(false)
|
||||
|
||||
const onPress = () => {
|
||||
if (isNative && Keyboard.isVisible()) {
|
||||
Keyboard.dismiss()
|
||||
}
|
||||
|
||||
setShowTooltip(false)
|
||||
setThreadgateNudged(true)
|
||||
|
||||
control.open()
|
||||
}
|
||||
|
||||
const prefThreadgateAllowUISettings = threadgateRecordToAllowUISetting({
|
||||
$type: 'app.bsky.feed.threadgate',
|
||||
post: '',
|
||||
createdAt: new Date().toISOString(),
|
||||
allow: preferences?.postInteractionSettings.threadgateAllowRules,
|
||||
})
|
||||
const prefPostgate = createPostgateRecord({
|
||||
post: '',
|
||||
embeddingRules:
|
||||
preferences?.postInteractionSettings?.postgateEmbeddingRules || [],
|
||||
})
|
||||
|
||||
const isDirty = useMemo(() => {
|
||||
const everybody = [{type: 'everybody'}]
|
||||
return (
|
||||
!deepEqual(
|
||||
threadgateAllowUISettings,
|
||||
prefThreadgateAllowUISettings ?? everybody,
|
||||
) ||
|
||||
!deepEqual(postgate.embeddingRules, prefPostgate?.embeddingRules ?? [])
|
||||
)
|
||||
}, [
|
||||
prefThreadgateAllowUISettings,
|
||||
prefPostgate,
|
||||
threadgateAllowUISettings,
|
||||
postgate,
|
||||
])
|
||||
|
||||
const {mutate: persistChanges, isPending: isSaving} =
|
||||
usePostInteractionSettingsMutation({
|
||||
onError: err => {
|
||||
if (!isNetworkError(err)) {
|
||||
logger.error('Failed to persist threadgate settings', {
|
||||
safeMessage: err,
|
||||
})
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
control.close(() => {
|
||||
setPersist(false)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const anyoneCanReply =
|
||||
threadgateAllowUISettings.length === 1 &&
|
||||
threadgateAllowUISettings[0].type === 'everybody'
|
||||
@@ -50,34 +131,54 @@ export function ThreadgateBtn({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="solid"
|
||||
color="secondary"
|
||||
size="small"
|
||||
testID="openReplyGateButton"
|
||||
onPress={onPress}
|
||||
label={label}
|
||||
accessibilityHint={_(
|
||||
msg`Opens a dialog to choose who can reply to this thread`,
|
||||
)}
|
||||
style={[
|
||||
native({
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 6,
|
||||
}),
|
||||
]}>
|
||||
<ButtonIcon icon={anyoneCanInteract ? Earth : Group} />
|
||||
<ButtonText numberOfLines={1}>{label}</ButtonText>
|
||||
</Button>
|
||||
<Tooltip.Outer
|
||||
visible={showTooltip}
|
||||
onVisibleChange={onDismissTooltip}
|
||||
position="top">
|
||||
<Tooltip.Target>
|
||||
<Button
|
||||
color={showTooltip ? 'primary_subtle' : 'secondary'}
|
||||
size="small"
|
||||
testID="openReplyGateButton"
|
||||
onPress={onPress}
|
||||
label={label}
|
||||
accessibilityHint={_(
|
||||
msg`Opens a dialog to choose who can interact with this post`,
|
||||
)}>
|
||||
<ButtonIcon icon={anyoneCanInteract ? EarthIcon : GroupIcon} />
|
||||
<ButtonText numberOfLines={1}>{label}</ButtonText>
|
||||
<ButtonIcon icon={TinyChevronIcon} size="2xs" />
|
||||
</Button>
|
||||
</Tooltip.Target>
|
||||
<Tooltip.TextBubble>
|
||||
<Text>
|
||||
<Trans>Psst! You can edit who can interact with this post.</Trans>
|
||||
</Text>
|
||||
</Tooltip.TextBubble>
|
||||
</Tooltip.Outer>
|
||||
|
||||
<PostInteractionSettingsControlledDialog
|
||||
control={control}
|
||||
onSave={() => {
|
||||
control.close()
|
||||
if (persist) {
|
||||
persistChanges({
|
||||
threadgateAllowRules: threadgateAllowUISettingToAllowRecordValue(
|
||||
threadgateAllowUISettings,
|
||||
),
|
||||
postgateEmbeddingRules: postgate.embeddingRules ?? [],
|
||||
})
|
||||
} else {
|
||||
control.close()
|
||||
}
|
||||
}}
|
||||
isSaving={isSaving}
|
||||
postgate={postgate}
|
||||
onChangePostgate={onChangePostgate}
|
||||
threadgateAllowUISettings={threadgateAllowUISettings}
|
||||
onChangeThreadgateAllowUISettings={onChangeThreadgateAllowUISettings}
|
||||
isDirty={isDirty}
|
||||
persist={persist}
|
||||
onChangePersist={setPersist}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user