diff --git a/src/state/drafts/__tests__/serialization.test.ts b/src/state/drafts/__tests__/serialization.test.ts
index 206ca340de..c80c387c9c 100644
--- a/src/state/drafts/__tests__/serialization.test.ts
+++ b/src/state/drafts/__tests__/serialization.test.ts
@@ -416,7 +416,7 @@ describe('Draft serialization', () => {
labels: [],
},
],
- threadgate: ['nobody'],
+ threadgate: [{type: 'nobody'}],
syncStatus: 'local',
}
@@ -428,7 +428,7 @@ describe('Draft serialization', () => {
loadedMedia,
})
- expect(newState.thread.threadgate).toEqual(['nobody'])
+ expect(newState.thread.threadgate).toEqual([{type: 'nobody'}])
})
it('restores reply information', () => {
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 6772cdbe56..0e0c773e75 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -360,6 +360,32 @@ export const ComposePost = ({
}
}, [saveDraft, composerState, replyTo, onClose, _])
+ // Save without closing - for use by DraftsButton
+ const saveCurrentDraft = React.useCallback(async () => {
+ await saveDraft({
+ composerState,
+ replyTo,
+ })
+ }, [saveDraft, composerState, replyTo])
+
+ // Check if composer is empty (no content to save)
+ const isComposerEmpty = React.useMemo(() => {
+ // Has multiple posts means it's not empty
+ if (thread.posts.length > 1) return false
+
+ const firstPost = thread.posts[0]
+ // Has text
+ if (firstPost.richtext.text.trim().length > 0) return false
+ // Has media
+ if (firstPost.embed.media) return false
+ // Has quote
+ if (firstPost.embed.quote) return false
+ // Has link
+ if (firstPost.embed.link) return false
+
+ return true
+ }, [thread.posts])
+
const insets = useSafeAreaInsets()
const viewStyles = useMemo(
() => ({
@@ -784,7 +810,9 @@ export const ComposePost = ({
topBarAnimatedStyle={topBarAnimatedStyle}
onCancel={onPressCancel}
onPublish={onPressPublish}
- onSelectDraft={handleSelectDraft}>
+ onSelectDraft={handleSelectDraft}
+ onSaveDraft={saveCurrentDraft}
+ isEmpty={isComposerEmpty}>
{missingAltError && }
void
onPublish: () => void
onSelectDraft: (draft: StoredDraft) => void
+ onSaveDraft: () => Promise
+ isEmpty: boolean
topBarAnimatedStyle: StyleProp
children?: React.ReactNode
}) {
@@ -1110,8 +1142,12 @@ function ComposerTopBar({
Cancel
-
+
{isPublishing ? (
<>
{publishingStage}
diff --git a/src/view/com/composer/drafts/DraftsButton.tsx b/src/view/com/composer/drafts/DraftsButton.tsx
index b7fab0a4ae..b27b225103 100644
--- a/src/view/com/composer/drafts/DraftsButton.tsx
+++ b/src/view/com/composer/drafts/DraftsButton.tsx
@@ -2,57 +2,116 @@ import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
-import {type StoredDraft, useDrafts} from '#/state/drafts'
+import {type StoredDraft, useDrafts, useSaveDraft} from '#/state/drafts'
import {atoms as a, useTheme} from '#/alf'
-import {Button, ButtonText} from '#/components/Button'
+import {Button, ButtonIcon} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {PageText_Stroke2_Corner0_Rounded as DraftIcon} from '#/components/icons/PageText'
+import * as Prompt from '#/components/Prompt'
import {Text} from '#/components/Typography'
import {DraftsListDialog} from './DraftsListDialog'
export function DraftsButton({
onSelectDraft,
+ onSaveDraft,
+ isEmpty,
}: {
onSelectDraft: (draft: StoredDraft) => void
+ onSaveDraft: () => Promise
+ isEmpty: boolean
}) {
const {_} = useLingui()
const t = useTheme()
- const control = Dialog.useDialogControl()
- const {data: drafts, isLoading} = useDrafts()
+ const draftsDialogControl = Dialog.useDialogControl()
+ const savePromptControl = Prompt.usePromptControl()
+ const {data: drafts} = useDrafts()
+ const {isPending: isSaving} = useSaveDraft()
- const hasDrafts = drafts && drafts.length > 0
+ const draftCount = drafts?.length ?? 0
- if (isLoading || !hasDrafts) {
- return null
+ const handlePress = () => {
+ if (isEmpty) {
+ // Composer is empty, go directly to drafts list
+ draftsDialogControl.open()
+ } else {
+ // Composer has content, ask what to do
+ savePromptControl.open()
+ }
+ }
+
+ const handleSaveAndOpen = async () => {
+ await onSaveDraft()
+ draftsDialogControl.open()
+ }
+
+ const handleDiscardAndOpen = () => {
+ draftsDialogControl.open()
}
return (
<>
-
+
+
+
+
+
+ Save current draft?
+
+
+
+ You have unsaved changes. Would you like to save them before viewing
+ your drafts?
+
+
+
+
+
+
+
+
>
)
}