Track dirty state to skip discard prompt for unchanged drafts
When a draft is loaded and the user hasn't made any changes, closing the composer should not show the discard prompt since nothing would be lost. - Add isDirty field to ComposerState - Set isDirty: true on all content-modifying actions - Set isDirty: false on restore_from_draft, clear, and initial state - Update onPressCancel to only show prompt if no draft or isDirty Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -413,21 +413,31 @@ export const ComposePost = ({
|
||||
const onPressCancel = useCallback(() => {
|
||||
if (textInput.current?.maybeClosePopup()) {
|
||||
return
|
||||
} else if (
|
||||
thread.posts.some(
|
||||
post =>
|
||||
post.shortenedGraphemeLength > 0 ||
|
||||
post.embed.media ||
|
||||
post.embed.link,
|
||||
)
|
||||
) {
|
||||
}
|
||||
|
||||
const hasContent = thread.posts.some(
|
||||
post =>
|
||||
post.shortenedGraphemeLength > 0 || post.embed.media || post.embed.link,
|
||||
)
|
||||
|
||||
// Show discard prompt if there's content AND either:
|
||||
// - No draft is loaded (new composition)
|
||||
// - Draft is loaded but has been modified
|
||||
if (hasContent && (!composerState.draftId || composerState.isDirty)) {
|
||||
closeAllDialogs()
|
||||
Keyboard.dismiss()
|
||||
discardPromptControl.open()
|
||||
} else {
|
||||
onClose()
|
||||
}
|
||||
}, [thread, closeAllDialogs, discardPromptControl, onClose])
|
||||
}, [
|
||||
thread,
|
||||
composerState.draftId,
|
||||
composerState.isDirty,
|
||||
closeAllDialogs,
|
||||
discardPromptControl,
|
||||
onClose,
|
||||
])
|
||||
|
||||
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
||||
|
||||
|
||||
@@ -104,6 +104,8 @@ export type ComposerState = {
|
||||
mutableNeedsFocusActive: boolean
|
||||
/** ID of the draft being edited, if any. Used to update existing draft on save. */
|
||||
draftId?: string
|
||||
/** Whether the composer has been modified since loading a draft. */
|
||||
isDirty: boolean
|
||||
}
|
||||
|
||||
export type ComposerAction =
|
||||
@@ -145,6 +147,7 @@ export function composerReducer(
|
||||
case 'update_postgate': {
|
||||
return {
|
||||
...state,
|
||||
isDirty: true,
|
||||
thread: {
|
||||
...state.thread,
|
||||
postgate: action.postgate,
|
||||
@@ -154,6 +157,7 @@ export function composerReducer(
|
||||
case 'update_threadgate': {
|
||||
return {
|
||||
...state,
|
||||
isDirty: true,
|
||||
thread: {
|
||||
...state.thread,
|
||||
threadgate: action.threadgate,
|
||||
@@ -174,6 +178,7 @@ export function composerReducer(
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
isDirty: true,
|
||||
thread: {
|
||||
...state.thread,
|
||||
posts: nextPosts,
|
||||
@@ -196,6 +201,7 @@ export function composerReducer(
|
||||
})
|
||||
return {
|
||||
...state,
|
||||
isDirty: true,
|
||||
thread: {
|
||||
...state.thread,
|
||||
posts: nextPosts,
|
||||
@@ -221,6 +227,7 @@ export function composerReducer(
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
isDirty: true,
|
||||
activePostIndex: nextActivePostIndex,
|
||||
mutableNeedsFocusActive: true,
|
||||
thread: {
|
||||
@@ -305,6 +312,7 @@ export function composerReducer(
|
||||
activePostIndex: 0,
|
||||
mutableNeedsFocusActive: true,
|
||||
draftId: draft.id,
|
||||
isDirty: false,
|
||||
thread: {
|
||||
posts,
|
||||
postgate: draft.postgate || state.thread.postgate,
|
||||
@@ -317,6 +325,7 @@ export function composerReducer(
|
||||
activePostIndex: 0,
|
||||
mutableNeedsFocusActive: true,
|
||||
draftId: undefined,
|
||||
isDirty: false,
|
||||
thread: {
|
||||
posts: [
|
||||
{
|
||||
@@ -699,6 +708,7 @@ export function createComposerState({
|
||||
return {
|
||||
activePostIndex: 0,
|
||||
mutableNeedsFocusActive: false,
|
||||
isDirty: false,
|
||||
thread: {
|
||||
posts: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user