fix(mobile): send shared content immediately instead of staging in draft
All checks were successful
Build / increment-version (push) Successful in 6s
Build / build-android (push) Successful in 4m51s
Build / create-release (push) Successful in 14s

This commit is contained in:
2026-05-13 09:58:48 +10:00
parent f8e8058de3
commit 0d97676edd

View File

@@ -518,11 +518,7 @@ function TaskbarFlashStopper() {
function AndroidShareIntentHandler() { function AndroidShareIntentHandler() {
const mx = useMatrixClient(); const mx = useMatrixClient();
const navigate = useNavigate(); const navigate = useNavigate();
const [isMarkdown] = useSetting(settingsAtom, 'isMarkdown');
const [pendingShare, setPendingShare] = useState<AndroidSharePayload | null>(null); const [pendingShare, setPendingShare] = useState<AndroidSharePayload | null>(null);
const [pickedRoomId, setPickedRoomId] = useState<string | null>(null);
const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(pickedRoomId ?? '__android_share__'));
const setUploadItems = useSetAtom(roomIdToUploadItemsAtomFamily(pickedRoomId ?? '__android_share__'));
const mDirects = useAtomValue(mDirectAtom); const mDirects = useAtomValue(mDirectAtom);
const roomToParents = useAtomValue(roomToParentsAtom); const roomToParents = useAtomValue(roomToParentsAtom);
@@ -531,60 +527,81 @@ function AndroidShareIntentHandler() {
const room = mx.getRoom(roomId); const room = mx.getRoom(roomId);
if (!room) return false; if (!room) return false;
// Send text message if present
const nextParts = [share.subject?.trim(), share.text?.trim()].filter( const nextParts = [share.subject?.trim(), share.text?.trim()].filter(
(value): value is string => !!value (value): value is string => !!value
); );
if (nextParts.length > 0) { if (nextParts.length > 0) {
const existingText = toPlainText(msgDraft, isMarkdown).trim(); const textContent = {
const nextText = existingText ? `${existingText}\n${nextParts.join('\n')}` : nextParts.join('\n'); msgtype: 'm.text' as const,
setMsgDraft(plainToEditorInput(nextText, isMarkdown)); body: nextParts.join('\n'),
};
await mx.sendMessage(roomId, textContent);
} }
// Upload and send files if present
if (share.files.length > 0) { if (share.files.length > 0) {
const uploadItems: TUploadItem[] = [];
for (const sharedFile of share.files) { for (const sharedFile of share.files) {
const originalFile = await materializeSharedFile(sharedFile, share.receivedAt); const originalFile = await materializeSharedFile(sharedFile, share.receivedAt);
let fileToUpload = originalFile;
let encInfo: any = undefined;
if (room.hasEncryptionStateEvent()) { if (room.hasEncryptionStateEvent()) {
const encrypted = await encryptFile(originalFile); const encrypted = await encryptFile(originalFile);
uploadItems.push({ fileToUpload = encrypted.file;
file: encrypted.file, encInfo = encrypted.encInfo;
originalFile,
metadata: { markedAsSpoiler: false },
encInfo: encrypted.encInfo,
});
continue;
} }
uploadItems.push({ // Upload file
file: originalFile, const uploadResult = await mx.uploadContent(fileToUpload);
originalFile, const mxc = uploadResult?.content_uri;
metadata: { markedAsSpoiler: false }, if (!mxc) continue;
encInfo: undefined,
}); // Determine message type and send
const fileType = originalFile.type;
let msgtype = 'm.file' as const;
if (fileType.startsWith('image/')) msgtype = 'm.image' as const;
else if (fileType.startsWith('video/')) msgtype = 'm.video' as const;
else if (fileType.startsWith('audio/')) msgtype = 'm.audio' as const;
const fileContent: any = {
msgtype,
body: originalFile.name,
filename: originalFile.name,
info: {
mimetype: originalFile.type,
size: originalFile.size,
},
};
if (encInfo) {
fileContent.file = {
...encInfo,
url: mxc,
};
} else {
fileContent.url = mxc;
} }
setUploadItems({ await mx.sendMessage(roomId, fileContent);
type: 'PUT', }
item: uploadItems,
});
} }
await clearPendingAndroidShare(); await clearPendingAndroidShare();
return true; return true;
}, },
[isMarkdown, msgDraft, mx, setMsgDraft, setUploadItems] [mx]
); );
const handlePickRoom = useCallback( const handlePickRoom = useCallback(
(roomId: string) => { (roomId: string) => {
setPickedRoomId(roomId);
if (!pendingShare) return; if (!pendingShare) return;
applyPendingShare(pendingShare, roomId) applyPendingShare(pendingShare, roomId)
.then((applied) => { .then((applied) => {
if (applied) { if (applied) {
setPendingShare(null); setPendingShare(null);
setPickedRoomId(null);
// Navigate to the selected room // Navigate to the selected room
const isDirect = mDirects.has(roomId); const isDirect = mDirects.has(roomId);
@@ -604,7 +621,6 @@ function AndroidShareIntentHandler() {
.catch((err) => { .catch((err) => {
console.error('[AndroidShare] Failed to apply share after pick:', err); console.error('[AndroidShare] Failed to apply share after pick:', err);
setPendingShare(null); setPendingShare(null);
setPickedRoomId(null);
}); });
}, },
[applyPendingShare, pendingShare, navigate, mDirects, roomToParents] [applyPendingShare, pendingShare, navigate, mDirects, roomToParents]
@@ -613,7 +629,6 @@ function AndroidShareIntentHandler() {
const handleDismiss = useCallback(() => { const handleDismiss = useCallback(() => {
clearPendingAndroidShare().catch(() => {}); clearPendingAndroidShare().catch(() => {});
setPendingShare(null); setPendingShare(null);
setPickedRoomId(null);
}, []); }, []);
useEffect(() => { useEffect(() => {