forked from akai/readest
62b5ed8138
Users can now tap "Share → Readest" in Safari, Chrome, or any other browser on iOS / Android and the article URL flows through the same clip-and-import pipeline the in-app "From Web URL" entry uses. Android `MainActivity.handleIncomingIntent` already routed file shares via `ACTION_SEND` + `EXTRA_STREAM`. Extend it to also pick up URL shares via `ACTION_SEND` + `EXTRA_TEXT`: parse the first http(s) token out of the text payload and dispatch it on the existing `shared-intent` event channel. No new event channel needed — `useAppUrlIngress` already listens and re-broadcasts as `app-incoming-url`. The existing `<intent-filter>` for `ACTION_SEND` with `*/*` MIME type already accepts `text/plain` from browsers — no manifest change required. iOS `gen/apple/` gains a new ShareExtension target. The extension's `ShareViewController` extracts a URL from `NSExtensionContext.inputItems` (prefers `public.url`, falls back to first http(s) token in `public.plain-text`) and forwards it to the main app as `readest://clip?url=<encoded>` via the responder-chain `openURL:` selector — the standard share-extension trick used by Pocket, Instapaper, Matter, etc. `project.yml` adds the ShareExtension target and switches the main app's Info.plist / entitlements references to `INFOPLIST_FILE` / `CODE_SIGN_ENTITLEMENTS` build settings instead of xcodegen's `info:` / `entitlements:` blocks. That way the hand-tuned `Readest_iOS/Info.plist` (CFBundleDocumentTypes, UTExportedTypeDeclarations, locales, CFBundleURLTypes for readest://, applesignin, associated-domains for Universal Links) is treated as an opaque input — xcodegen won't regenerate it. JS New `useClipUrlIngress` hook subscribes to `app-incoming-url`, unwraps `readest://clip?url=<encoded>` into the inner URL (the iOS forwarding path), filters out file URIs and annotation deep links, and runs each remaining http(s) URL through `clip_url` → `convertToEpubWithWorker` → `ingestFile` — the same path `/send` uses. Mounted alongside `useOpenWithBooks` and `useOpenAnnotationLink` in both `app/library/page.tsx` and `app/reader/page.tsx` so shares arriving while the user is reading still process. Notes - The PR targets `feat/send-clip-mobile` (PR #4252) since the share pipeline depends on `clip_url` being available on mobile. - iOS Share Extension built locally via xcodegen; the regenerated pbxproj is tracked because gen/apple is gitignored. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect } from 'react';
|
|
import { useEnv } from '@/context/EnvContext';
|
|
import { useTranslation } from '@/hooks/useTranslation';
|
|
import { useAppUrlIngress } from '@/hooks/useAppUrlIngress';
|
|
import { useOpenWithBooks } from '@/hooks/useOpenWithBooks';
|
|
import { useOpenAnnotationLink } from '@/hooks/useOpenAnnotationLink';
|
|
import { useOpenShareLink } from '@/hooks/useOpenShareLink';
|
|
import { useClipUrlIngress } from '@/hooks/useClipUrlIngress';
|
|
import { useSettingsStore } from '@/store/settingsStore';
|
|
import { checkForAppUpdates, checkAppReleaseNotes } from '@/helpers/updater';
|
|
import { tauriHandleSetAlwaysOnTop } from '@/utils/window';
|
|
import Reader from './components/Reader';
|
|
|
|
// This is only used for the Tauri app in the app router
|
|
export default function Page() {
|
|
const _ = useTranslation();
|
|
const { appService } = useEnv();
|
|
const { settings } = useSettingsStore();
|
|
|
|
useAppUrlIngress();
|
|
useOpenWithBooks();
|
|
useOpenAnnotationLink();
|
|
useOpenShareLink();
|
|
useClipUrlIngress();
|
|
|
|
useEffect(() => {
|
|
const doCheckAppUpdates = async () => {
|
|
if (appService?.hasUpdater && settings.autoCheckUpdates) {
|
|
await checkForAppUpdates(_);
|
|
} else if (appService?.hasUpdater === false) {
|
|
checkAppReleaseNotes();
|
|
}
|
|
};
|
|
if (appService?.hasWindow && settings.alwaysOnTop) {
|
|
tauriHandleSetAlwaysOnTop(settings.alwaysOnTop);
|
|
}
|
|
doCheckAppUpdates();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [appService?.hasUpdater, settings.autoCheckUpdates]);
|
|
|
|
return <Reader />;
|
|
}
|