71a7a57adc
When iOS delivers a file via "Open In…", expo-router strips the docuelevate:// scheme and routes to +not-found.tsx. Previously, this screen only redirected to the Upload tab and relied on the Linking handler in _layout.tsx to add the file to ShareContext. This was unreliable because expo-router may consume the URL event before the Linking handler fires. Now +not-found.tsx directly reconstructs the file:// URI from the pathname and adds it to ShareContext before redirecting. ShareContext deduplicates by URI to prevent double uploads if both mechanisms fire. Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
/**
|
||
* ShareContext – propagates files received from the iOS Share Sheet or the
|
||
* Android Share Intent to the UploadScreen so they can be uploaded
|
||
* automatically.
|
||
*
|
||
* The root layout listens for incoming file:// / content:// URLs via
|
||
* expo-linking and calls addPendingFile(). UploadScreen consumes the context,
|
||
* uploads each pending file, then calls clearPendingFiles().
|
||
*/
|
||
|
||
import React, { createContext, useCallback, useContext, useState } from "react";
|
||
|
||
export interface SharedFile {
|
||
uri: string;
|
||
filename: string;
|
||
mimeType?: string;
|
||
}
|
||
|
||
interface ShareContextValue {
|
||
pendingFiles: SharedFile[];
|
||
addPendingFile: (file: SharedFile) => void;
|
||
clearPendingFiles: () => void;
|
||
}
|
||
|
||
const ShareContext = createContext<ShareContextValue>({
|
||
pendingFiles: [],
|
||
addPendingFile: () => {},
|
||
clearPendingFiles: () => {},
|
||
});
|
||
|
||
export function ShareProvider({ children }: { children: React.ReactNode }) {
|
||
const [pendingFiles, setPendingFiles] = useState<SharedFile[]>([]);
|
||
|
||
const addPendingFile = useCallback((file: SharedFile) => {
|
||
setPendingFiles((prev) => {
|
||
// Deduplicate by normalised URI so the same file is not uploaded twice
|
||
// when both the Linking handler (_layout.tsx) and +not-found.tsx fire.
|
||
const normalize = (uri: string) => {
|
||
try { return decodeURIComponent(uri); } catch { return uri; }
|
||
};
|
||
const norm = normalize(file.uri);
|
||
if (prev.some((f) => normalize(f.uri) === norm)) return prev;
|
||
return [...prev, file];
|
||
});
|
||
}, []);
|
||
|
||
const clearPendingFiles = useCallback(() => {
|
||
setPendingFiles([]);
|
||
}, []);
|
||
|
||
return (
|
||
<ShareContext.Provider value={{ pendingFiles, addPendingFile, clearPendingFiles }}>
|
||
{children}
|
||
</ShareContext.Provider>
|
||
);
|
||
}
|
||
|
||
export function useShare(): ShareContextValue {
|
||
return useContext(ShareContext);
|
||
}
|