Handle edited state
This commit is contained in:
@@ -148,6 +148,7 @@
|
|||||||
"expo-updates": "~0.26.10",
|
"expo-updates": "~0.26.10",
|
||||||
"expo-video": "^2.0.5",
|
"expo-video": "^2.0.5",
|
||||||
"expo-web-browser": "~14.0.1",
|
"expo-web-browser": "~14.0.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-text-encoding": "^1.0.6",
|
"fast-text-encoding": "^1.0.6",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
"hls.js": "^1.5.11",
|
"hls.js": "^1.5.11",
|
||||||
|
|||||||
@@ -30,16 +30,19 @@ import {
|
|||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {Admonition} from '#/components/Admonition'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
import * as Toggle from '#/components/forms/Toggle'
|
import * as Toggle from '#/components/forms/Toggle'
|
||||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||||
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
export type PostInteractionSettingsFormProps = {
|
export type PostInteractionSettingsFormProps = {
|
||||||
|
canSave?: boolean
|
||||||
onSave: () => void
|
onSave: () => void
|
||||||
isSaving?: boolean
|
isSaving?: boolean
|
||||||
|
|
||||||
@@ -59,6 +62,7 @@ export function PostInteractionSettingsControlledDialog({
|
|||||||
control: Dialog.DialogControlProps
|
control: Dialog.DialogControlProps
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer control={control}>
|
<Dialog.Outer control={control}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
@@ -68,6 +72,16 @@ export function PostInteractionSettingsControlledDialog({
|
|||||||
<View style={[a.gap_md]}>
|
<View style={[a.gap_md]}>
|
||||||
<Header />
|
<Header />
|
||||||
<PostInteractionSettingsForm {...rest} />
|
<PostInteractionSettingsForm {...rest} />
|
||||||
|
<Admonition type="tip" style={[a.mt_sm]}>
|
||||||
|
<Trans>
|
||||||
|
You can configure defaults for these settings from within your{' '}
|
||||||
|
<InlineLinkText
|
||||||
|
label={_(msg`Configure default interaction settings`)}
|
||||||
|
to="/moderation/interaction-settings">
|
||||||
|
moderation settings screen.
|
||||||
|
</InlineLinkText>
|
||||||
|
</Trans>
|
||||||
|
</Admonition>
|
||||||
</View>
|
</View>
|
||||||
<Dialog.Close />
|
<Dialog.Close />
|
||||||
</Dialog.ScrollableInner>
|
</Dialog.ScrollableInner>
|
||||||
@@ -244,6 +258,7 @@ export function PostInteractionSettingsDialogControlledInner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function PostInteractionSettingsForm({
|
export function PostInteractionSettingsForm({
|
||||||
|
canSave = true,
|
||||||
onSave,
|
onSave,
|
||||||
isSaving,
|
isSaving,
|
||||||
postgate,
|
postgate,
|
||||||
@@ -446,6 +461,7 @@ export function PostInteractionSettingsForm({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
disabled={!canSave || isSaving}
|
||||||
label={_(msg`Save`)}
|
label={_(msg`Save`)}
|
||||||
onPress={onSave}
|
onPress={onSave}
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react'
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import deepEqual from 'fast-deep-equal'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {usePostInteractionSettingsMutation} from '#/state/queries/post-interaction-settings'
|
import {usePostInteractionSettingsMutation} from '#/state/queries/post-interaction-settings'
|
||||||
@@ -11,7 +12,6 @@ import {
|
|||||||
UsePreferencesQueryResponse,
|
UsePreferencesQueryResponse,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
import {
|
import {
|
||||||
ThreadgateAllowUISetting,
|
|
||||||
threadgateAllowUISettingToAllowRecordValue,
|
threadgateAllowUISettingToAllowRecordValue,
|
||||||
threadgateRecordToAllowUISetting,
|
threadgateRecordToAllowUISetting,
|
||||||
} from '#/state/queries/threadgate'
|
} from '#/state/queries/threadgate'
|
||||||
@@ -40,8 +40,8 @@ export function Screen() {
|
|||||||
<View style={[gutters, a.gap_xl]}>
|
<View style={[gutters, a.gap_xl]}>
|
||||||
<Admonition type="tip">
|
<Admonition type="tip">
|
||||||
<Trans>
|
<Trans>
|
||||||
The following settings will be applied automatically to all new
|
The following settings will be used as your defaults when creating
|
||||||
posts you create.
|
new posts. They can be edited from the composer before you post.
|
||||||
</Trans>
|
</Trans>
|
||||||
</Admonition>
|
</Admonition>
|
||||||
{preferences ? (
|
{preferences ? (
|
||||||
@@ -63,23 +63,31 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
|||||||
usePostInteractionSettingsMutation()
|
usePostInteractionSettingsMutation()
|
||||||
const [error, setError] = React.useState<string | undefined>(undefined)
|
const [error, setError] = React.useState<string | undefined>(undefined)
|
||||||
|
|
||||||
const [postgate, setPostgate] = React.useState(() => {
|
const allowUI = React.useMemo(() => {
|
||||||
return createPostgateRecord({
|
|
||||||
post: '',
|
|
||||||
embeddingRules:
|
|
||||||
preferences.postInteractionSettings.postgateEmbeddingRules,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const [allowUISettings, setAllowUISettings] = React.useState<
|
|
||||||
ThreadgateAllowUISetting[]
|
|
||||||
>(() => {
|
|
||||||
return threadgateRecordToAllowUISetting({
|
return threadgateRecordToAllowUISetting({
|
||||||
$type: 'app.bsky.feed.threadgate',
|
$type: 'app.bsky.feed.threadgate',
|
||||||
post: '',
|
post: '',
|
||||||
createdAt: new Date().toString(),
|
createdAt: new Date().toString(),
|
||||||
allow: preferences.postInteractionSettings.threadgateAllowRules,
|
allow: preferences.postInteractionSettings.threadgateAllowRules,
|
||||||
})
|
})
|
||||||
})
|
}, [preferences.postInteractionSettings.threadgateAllowRules])
|
||||||
|
const postgate = React.useMemo(() => {
|
||||||
|
return createPostgateRecord({
|
||||||
|
post: '',
|
||||||
|
embeddingRules:
|
||||||
|
preferences.postInteractionSettings.postgateEmbeddingRules,
|
||||||
|
})
|
||||||
|
}, [preferences.postInteractionSettings.postgateEmbeddingRules])
|
||||||
|
|
||||||
|
const [maybeEditedAllowUI, setAllowUI] = React.useState(allowUI)
|
||||||
|
const [maybeEditedPostgate, setEditedPostgate] = React.useState(postgate)
|
||||||
|
|
||||||
|
const wasEdited = React.useMemo(() => {
|
||||||
|
return (
|
||||||
|
!deepEqual(allowUI, maybeEditedAllowUI) ||
|
||||||
|
!deepEqual(postgate.embeddingRules, maybeEditedPostgate.embeddingRules)
|
||||||
|
)
|
||||||
|
}, [postgate, allowUI, maybeEditedAllowUI, maybeEditedPostgate])
|
||||||
|
|
||||||
const onSave = React.useCallback(async () => {
|
const onSave = React.useCallback(async () => {
|
||||||
setError('')
|
setError('')
|
||||||
@@ -87,8 +95,8 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
|||||||
try {
|
try {
|
||||||
await setPostInteractionSettings({
|
await setPostInteractionSettings({
|
||||||
threadgateAllowRules:
|
threadgateAllowRules:
|
||||||
threadgateAllowUISettingToAllowRecordValue(allowUISettings),
|
threadgateAllowUISettingToAllowRecordValue(maybeEditedAllowUI),
|
||||||
postgateEmbeddingRules: postgate.embeddingRules ?? [],
|
postgateEmbeddingRules: maybeEditedPostgate.embeddingRules ?? [],
|
||||||
})
|
})
|
||||||
Toast.show(_(msg`Settings saved`))
|
Toast.show(_(msg`Settings saved`))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -98,17 +106,18 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
|||||||
})
|
})
|
||||||
setError(_(msg`Failed to save settings. Please try again.`))
|
setError(_(msg`Failed to save settings. Please try again.`))
|
||||||
}
|
}
|
||||||
}, [_, postgate, allowUISettings, setPostInteractionSettings])
|
}, [_, maybeEditedPostgate, maybeEditedAllowUI, setPostInteractionSettings])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PostInteractionSettingsForm
|
<PostInteractionSettingsForm
|
||||||
|
canSave={wasEdited}
|
||||||
isSaving={isPending}
|
isSaving={isPending}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
postgate={postgate}
|
postgate={maybeEditedPostgate}
|
||||||
onChangePostgate={setPostgate}
|
onChangePostgate={setEditedPostgate}
|
||||||
threadgateAllowUISettings={allowUISettings}
|
threadgateAllowUISettings={maybeEditedAllowUI}
|
||||||
onChangeThreadgateAllowUISettings={setAllowUISettings}
|
onChangeThreadgateAllowUISettings={setAllowUI}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{error && <Admonition type="error">{error}</Admonition>}
|
{error && <Admonition type="error">{error}</Admonition>}
|
||||||
|
|||||||
@@ -83,10 +83,7 @@ import {
|
|||||||
useLanguagePrefs,
|
useLanguagePrefs,
|
||||||
useLanguagePrefsApi,
|
useLanguagePrefsApi,
|
||||||
} from '#/state/preferences/languages'
|
} from '#/state/preferences/languages'
|
||||||
import {
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
preferencesQueryKey,
|
|
||||||
UsePreferencesQueryResponse,
|
|
||||||
} from '#/state/queries/preferences'
|
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {Gif} from '#/state/queries/tenor'
|
import {Gif} from '#/state/queries/tenor'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
@@ -173,11 +170,7 @@ export const ComposePost = ({
|
|||||||
const discardPromptControl = Prompt.usePromptControl()
|
const discardPromptControl = Prompt.usePromptControl()
|
||||||
const {closeAllDialogs} = useDialogStateControlContext()
|
const {closeAllDialogs} = useDialogStateControlContext()
|
||||||
const {closeAllModals} = useModalControls()
|
const {closeAllModals} = useModalControls()
|
||||||
const initInteractionSettings = useMemo(() => {
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const prefs =
|
|
||||||
queryClient.getQueryData<UsePreferencesQueryResponse>(preferencesQueryKey)
|
|
||||||
return prefs?.postInteractionSettings
|
|
||||||
}, [queryClient])
|
|
||||||
|
|
||||||
const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
|
const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
|
||||||
const [isPublishing, setIsPublishing] = useState(false)
|
const [isPublishing, setIsPublishing] = useState(false)
|
||||||
@@ -191,7 +184,7 @@ export const ComposePost = ({
|
|||||||
initQuoteUri: initQuote?.uri,
|
initQuoteUri: initQuote?.uri,
|
||||||
initText,
|
initText,
|
||||||
initMention,
|
initMention,
|
||||||
initInteractionSettings,
|
initInteractionSettings: preferences?.postInteractionSettings,
|
||||||
},
|
},
|
||||||
createComposerState,
|
createComposerState,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user