'Teilen -> ARIA' aus WhatsApp, Galerie, Browser & Co. Ablauf wie gewuenscht: sehen WAS geteilt wurde -> WOHIN (Projekt oder Hauptchat) -> optional Text dazu. Ohne Text geht genauso. - Manifest: intent-filter fuer ACTION_SEND (text/image/video/audio/application) und ACTION_SEND_MULTIPLE. launchMode=singleTask war bereits gesetzt. - ShareIntentModule (Kotlin): liest den Intent und kopiert die Inhalte SOFORT in den App-Cache — die Leseerlaubnis fuer content://-URIs gilt nur fuer diesen Intent und waere nach der Projektauswahl womoeglich erloschen. Liefert echte Dateipfade, dadurch laeuft Teilen durch exakt dieselbe Upload-Strecke wie die Bueroklammer (RNFS -> Base64 -> Anhang im Chat). - MainActivity.onNewIntent: setIntent + Event an JS (best effort). Zweitweg in JS ueber AppState 'active' -> getSharedData(), falls das Event je nach RN-Architektur nicht durchkommt; getSharedData markiert den Intent als verbraucht, also kein doppeltes Aufpoppen. - ShareModal: Vorschau der geteilten Inhalte, Projektliste (inkl. Hauptchat), optionales Textfeld. Senden erst nach Zielwahl moeglich. - sendPendingAttachments nimmt die Anhaenge jetzt optional als Parameter — beim Teilen waere der State zum Aufrufzeitpunkt noch leer. tsc --noEmit: 0 Fehler. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
/**
|
|
* Teilen-Ziel — Bruecke zum nativen ShareIntent-Modul.
|
|
*
|
|
* Zwei Faelle:
|
|
* App war ZU → der Inhalt liegt beim Start am Intent → getShared()
|
|
* App LAEUFT → onNewIntent feuert das Event 'ShareReceived' → onShare()
|
|
*
|
|
* Die Dateien hat die native Seite schon in den App-Cache kopiert und liefert
|
|
* echte Pfade; content://-URIs waeren nach dem Dialog womoeglich nicht mehr
|
|
* lesbar (die Leseerlaubnis gilt nur fuer den Intent).
|
|
*/
|
|
import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
import RNFS from 'react-native-fs';
|
|
import type { FileData } from '../components/FileUpload';
|
|
import type { SharedItem } from '../components/ShareModal';
|
|
|
|
const { ShareIntent } = NativeModules;
|
|
|
|
export interface SharedPayload {
|
|
text: string;
|
|
items: SharedItem[];
|
|
}
|
|
|
|
const EMPTY: SharedPayload = { text: '', items: [] };
|
|
|
|
/** Inhalt, mit dem die App gestartet wurde (leer, wenn normal geoeffnet). */
|
|
export async function getShared(): Promise<SharedPayload> {
|
|
if (!ShareIntent?.getSharedData) return EMPTY;
|
|
try {
|
|
const r = await ShareIntent.getSharedData();
|
|
return { text: r?.text || '', items: Array.isArray(r?.items) ? r.items : [] };
|
|
} catch (e) {
|
|
console.warn('[Share] getSharedData fehlgeschlagen:', e);
|
|
return EMPTY;
|
|
}
|
|
}
|
|
|
|
/** Abonniert Shares in die bereits laufende App. Gibt Unsubscribe zurueck. */
|
|
export function onShare(cb: (p: SharedPayload) => void): () => void {
|
|
if (!ShareIntent) return () => {};
|
|
const emitter = new NativeEventEmitter(ShareIntent);
|
|
const sub = emitter.addListener('ShareReceived', (r: any) => {
|
|
cb({ text: r?.text || '', items: Array.isArray(r?.items) ? r.items : [] });
|
|
});
|
|
return () => { try { sub.remove(); } catch (_) {} };
|
|
}
|
|
|
|
/** Zwischenkopien loeschen (nach erfolgreichem Senden). */
|
|
export async function clearShareCache(): Promise<void> {
|
|
try { await ShareIntent?.clearCache?.(); } catch (_) {}
|
|
}
|
|
|
|
/**
|
|
* Macht aus geteilten Dateien das Format, das der bestehende Upload-Weg
|
|
* erwartet (Base64) — so laeuft Teilen durch exakt dieselbe Strecke wie die
|
|
* Bueroklammer, inklusive Anhang-Darstellung im Chat.
|
|
*/
|
|
export async function toFileData(items: SharedItem[]): Promise<FileData[]> {
|
|
const out: FileData[] = [];
|
|
for (const it of items) {
|
|
try {
|
|
const base64 = await RNFS.readFile(it.path, 'base64');
|
|
out.push({
|
|
name: it.name || 'geteilt',
|
|
type: it.type || 'application/octet-stream',
|
|
size: it.size || 0,
|
|
base64,
|
|
uri: 'file://' + it.path,
|
|
});
|
|
} catch (e) {
|
|
console.warn('[Share] Datei nicht lesbar (%s): %s', it.name, e);
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export default { getShared, onShare, clearShareCache, toFileData };
|