diff --git a/packages/pl-fe/CHANGELOG.md b/packages/pl-fe/CHANGELOG.md index 01d625c08..a188a8934 100644 --- a/packages/pl-fe/CHANGELOG.md +++ b/packages/pl-fe/CHANGELOG.md @@ -29,6 +29,7 @@ Changes made since the project forked from Soapbox in April 2024. - Language detection is done client-side for composed posts, utilizing `fasttext.wasm.js`. - Draft posts. They are stored locally only and work with any backend. - New visibility scopes are supported – local-only and list-only for Pleroma. Local-only is a separate switch on GoToSocial. +- On backends that support explicit mentioning, you can choose to include mentions in your replies body. **Features:** - The most recent scrobble is displayed on user profile/card. diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index d3cddcb7c..3d8fb8fed 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -20,7 +20,7 @@ import { uploadFile, updateMedia } from './media'; import { createStatus } from './statuses'; import type { EditorState } from 'lexical'; -import type { Account as BaseAccount, BackendVersion, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus } from 'pl-api'; +import type { Account as BaseAccount, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus } from 'pl-api'; import type { AutoSuggestion } from 'pl-fe/components/autosuggest-input'; import type { Emoji } from 'pl-fe/features/emoji'; import type { Account } from 'pl-fe/normalizers/account'; @@ -118,7 +118,6 @@ interface ComposeSetStatusAction { explicitAddressing: boolean; spoilerText?: string; contentType?: string | false; - v: BackendVersion; withRedraft?: boolean; draftId?: string; editorState?: string | null; @@ -135,8 +134,8 @@ const setComposeToStatus = ( editorState?: string | null, ) => (dispatch: AppDispatch, getState: () => RootState) => { - const client = getClient(getState); - const { createStatusExplicitAddressing: explicitAddressing, version: v } = client.features; + const { features } = getClient(getState); + const explicitAddressing = features.createStatusExplicitAddressing && !useSettingsStore.getState().settings.forceImplicitAddressing; dispatch({ type: COMPOSE_SET_STATUS, @@ -147,7 +146,6 @@ const setComposeToStatus = ( explicitAddressing, spoilerText, contentType, - v, withRedraft, draftId, editorState, @@ -178,9 +176,9 @@ const replyCompose = ( ) => (dispatch: AppDispatch, getState: () => RootState) => { const state = getState(); - const client = getClient(state); - const { createStatusExplicitAddressing: explicitAddressing } = client.features; - const preserveSpoilers = useSettingsStore.getState().settings.preserveSpoilers; + const { features } = getClient(getState); + const { forceImplicitAddressing, preserveSpoilers } = useSettingsStore.getState().settings; + const explicitAddressing = features.createStatusExplicitAddressing && !forceImplicitAddressing; const account = selectOwnAccount(state); if (!account) return; @@ -214,7 +212,8 @@ interface ComposeQuoteAction { const quoteCompose = (status: ComposeQuoteAction['status']) => (dispatch: AppDispatch, getState: () => RootState) => { const state = getState(); - const { createStatusExplicitAddressing: explicitAddressing } = state.auth.client.features; + const { forceImplicitAddressing } = useSettingsStore.getState().settings; + const explicitAddressing = state.auth.client.features.createStatusExplicitAddressing && !forceImplicitAddressing; dispatch({ type: COMPOSE_QUOTE, @@ -347,10 +346,13 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => const compose = state.compose[composeId]!; + const status = compose.text; const media = compose.media_attachments; const statusId = compose.id; let to = compose.to; + const { forceImplicitAddressing } = useSettingsStore.getState().settings; + const explicitAddressing = state.auth.client.features.createStatusExplicitAddressing && !forceImplicitAddressing; if (!validateSchedule(state, composeId)) { toast.error(messages.scheduleError); @@ -399,7 +401,7 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => content_type: contentType, scheduled_at: compose.schedule?.toISOString(), language: compose.language || compose.suggested_language || undefined, - to: to.length ? to : undefined, + to: explicitAddressing && to.length ? to : undefined, local_only: !compose.federated, }; @@ -897,7 +899,8 @@ interface ComposeEventReplyAction { const eventDiscussionCompose = (composeId: string, status: ComposeEventReplyAction['status']) => (dispatch: AppDispatch, getState: () => RootState) => { const state = getState(); - const { createStatusExplicitAddressing: explicitAddressing } = state.auth.client.features; + const { forceImplicitAddressing } = useSettingsStore.getState().settings; + const explicitAddressing = state.auth.client.features.createStatusExplicitAddressing && !forceImplicitAddressing; return dispatch({ type: COMPOSE_EVENT_REPLY, diff --git a/packages/pl-fe/src/features/compose/components/reply-mentions.tsx b/packages/pl-fe/src/features/compose/components/reply-mentions.tsx index 9e1918c24..bdf0385e8 100644 --- a/packages/pl-fe/src/features/compose/components/reply-mentions.tsx +++ b/packages/pl-fe/src/features/compose/components/reply-mentions.tsx @@ -4,6 +4,7 @@ import { FormattedList, FormattedMessage } from 'react-intl'; import { useCompose } from 'pl-fe/hooks/use-compose'; import { useFeatures } from 'pl-fe/hooks/use-features'; import { useModalsStore } from 'pl-fe/stores/modals'; +import { useSettingsStore } from 'pl-fe/stores/settings'; interface IReplyMentions { composeId: string; @@ -15,7 +16,10 @@ const ReplyMentions: React.FC = ({ composeId }) => { const compose = useCompose(composeId); const to = compose.to; - if (!features.createStatusExplicitAddressing || !compose.in_reply_to || !to) { + const { forceImplicitAddressing } = useSettingsStore().settings; + const explicitAddressing = features.createStatusExplicitAddressing && !forceImplicitAddressing; + + if (!explicitAddressing || !compose.in_reply_to || !to) { return null; } diff --git a/packages/pl-fe/src/features/preferences/index.tsx b/packages/pl-fe/src/features/preferences/index.tsx index 30c3036bf..306cbcbb1 100644 --- a/packages/pl-fe/src/features/preferences/index.tsx +++ b/packages/pl-fe/src/features/preferences/index.tsx @@ -203,6 +203,12 @@ const Preferences = () => { )} + {features.createStatusExplicitAddressing && ( + }> + + + )} + }> diff --git a/packages/pl-fe/src/locales/en.json b/packages/pl-fe/src/locales/en.json index 477589e3e..f1905da62 100644 --- a/packages/pl-fe/src/locales/en.json +++ b/packages/pl-fe/src/locales/en.json @@ -1253,6 +1253,7 @@ "preferences.fields.display_media.default": "Hide posts marked as sensitive", "preferences.fields.display_media.hide_all": "Always hide media posts", "preferences.fields.display_media.show_all": "Always show posts", + "preferences.fields.implicit_addressing_label": "Include mentions in post content when replying", "preferences.fields.known_languages_label": "Languages you know", "preferences.fields.language_label": "Display language", "preferences.fields.media_display_label": "Sensitive content", diff --git a/packages/pl-fe/src/reducers/compose.ts b/packages/pl-fe/src/reducers/compose.ts index 124c25bbc..c57bb27e3 100644 --- a/packages/pl-fe/src/reducers/compose.ts +++ b/packages/pl-fe/src/reducers/compose.ts @@ -1,10 +1,9 @@ import { create } from 'mutative'; -import { PLEROMA, type CredentialAccount, type Instance, type MediaAttachment, type Tag } from 'pl-api'; +import { type CredentialAccount, type Instance, type MediaAttachment, type Tag } from 'pl-api'; import { INSTANCE_FETCH_SUCCESS, InstanceAction } from 'pl-fe/actions/instance'; import { isNativeEmoji, type Emoji } from 'pl-fe/features/emoji'; import { tagHistory } from 'pl-fe/settings'; -import { hasIntegerMediaIds } from 'pl-fe/utils/status'; import { COMPOSE_CHANGE, @@ -546,11 +545,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In compose.quote = action.status.quote_id; compose.group_id = action.status.group_id; - if (action.v?.software === PLEROMA && action.withRedraft && hasIntegerMediaIds(action.status)) { - compose.media_attachments = []; - } else { - compose.media_attachments = action.status.media_attachments; - } + compose.media_attachments = action.status.media_attachments; if (action.status.spoiler_text.length > 0) { compose.spoiler_text = action.status.spoiler_text; diff --git a/packages/pl-fe/src/schemas/pl-fe/settings.ts b/packages/pl-fe/src/schemas/pl-fe/settings.ts index e7f64d380..424ef3dc3 100644 --- a/packages/pl-fe/src/schemas/pl-fe/settings.ts +++ b/packages/pl-fe/src/schemas/pl-fe/settings.ts @@ -33,6 +33,7 @@ const settingsSchema = v.object({ autoloadTimelines: v.fallback(v.boolean(), true), autoloadMore: v.fallback(v.boolean(), true), preserveSpoilers: v.fallback(v.boolean(), false), + forceImplicitAddressing: v.fallback(v.boolean(), false), autoTranslate: v.fallback(v.boolean(), false), knownLanguages: v.fallback(v.array(v.string()), []), showWrenchButton: v.fallback(v.boolean(), false), diff --git a/packages/pl-fe/src/stores/settings.ts b/packages/pl-fe/src/stores/settings.ts index 036b0734d..885769cee 100644 --- a/packages/pl-fe/src/stores/settings.ts +++ b/packages/pl-fe/src/stores/settings.ts @@ -65,7 +65,6 @@ const useSettingsStore = create()(mutative((set) => ({ changeSetting(state.userSettings, path, value); mergeSettings(state); - console.log(JSON.parse(JSON.stringify(state.userSettings))); }), rememberEmojiUse: (emoji: Emoji) => set((state: State) => {