feat(images): share target working and receiving images!

This commit is contained in:
2025-04-21 11:44:34 +01:00
parent 9f215bb3d1
commit 6211945e3d
8 changed files with 103 additions and 24 deletions

Binary file not shown.

View File

@ -20,6 +20,7 @@
"@tabler/icons-solidjs": "^3.30.0", "@tabler/icons-solidjs": "^3.30.0",
"@tauri-apps/api": "^2", "@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "~2", "@tauri-apps/plugin-dialog": "~2",
"@tauri-apps/plugin-fs": "~2",
"@tauri-apps/plugin-http": "~2", "@tauri-apps/plugin-http": "~2",
"@tauri-apps/plugin-opener": "^2", "@tauri-apps/plugin-opener": "^2",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -30,6 +31,7 @@
"solid-motionone": "^1.0.3", "solid-motionone": "^1.0.3",
"solidjs-markdown": "^0.2.0", "solidjs-markdown": "^0.2.0",
"tailwind-scrollbar-hide": "^2.0.0", "tailwind-scrollbar-hide": "^2.0.0",
"tauri-plugin-sharetarget-api": "^0.1.6",
"valibot": "^1.0.0-rc.2" "valibot": "^1.0.0-rc.2"
}, },
"devDependencies": { "devDependencies": {

View File

@ -13,9 +13,11 @@ dependencies = [
"serde_json", "serde_json",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-fs",
"tauri-plugin-global-shortcut", "tauri-plugin-global-shortcut",
"tauri-plugin-http", "tauri-plugin-http",
"tauri-plugin-log", "tauri-plugin-log",
"tauri-plugin-sharetarget",
"tauri-plugin-store", "tauri-plugin-store",
"tokio", "tokio",
] ]
@ -4057,6 +4059,20 @@ dependencies = [
"time", "time",
] ]
[[package]]
name = "tauri-plugin-sharetarget"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15a6e4638b6a5492a46847fc9e994df8cfd2dbc1bacc11f15c207d6a2163c341"
dependencies = [
"serde",
"serde_json",
"tauri",
"tauri-build",
"tauri-plugin",
"thiserror 1.0.69",
]
[[package]] [[package]]
name = "tauri-plugin-store" name = "tauri-plugin-store"
version = "2.2.0" version = "2.2.0"

View File

@ -27,6 +27,8 @@ tokio = { version = "1.36.0", features = ["full"] }
tauri-plugin-store = "2.0.0-beta.12" tauri-plugin-store = "2.0.0-beta.12"
tauri-plugin-http = "2.0.0-beta.12" tauri-plugin-http = "2.0.0-beta.12"
tauri-plugin-log = "2" tauri-plugin-log = "2"
tauri-plugin-sharetarget = "0.1.6"
tauri-plugin-fs = "2"
[target."cfg(target_os = \"macos\")".dependencies] [target."cfg(target_os = \"macos\")".dependencies]
cocoa = "0.26" cocoa = "0.26"

View File

@ -1,26 +1,39 @@
{ {
"$schema": "../gen/schemas/desktop-schema.json", "$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default", "identifier": "default",
"description": "Capability for the main window", "description": "Capability for the main window",
"windows": ["main"], "windows": [
"permissions": [ "main"
"core:default", ],
"core:window:allow-start-dragging", "permissions": [
"http:default", "core:default",
"core:window:allow-start-dragging",
"http:default",
"sharetarget:default",
{
"identifier": "fs:scope",
"allow": [
{ {
"identifier": "http:default", "path": "$APPDATA/databases/*"
"allow": [ }
{ ]
"url": "https://haystack.johncosta.tech" },
}, {
{ "identifier": "http:default",
"url": "http://localhost:3040" "allow": [
}, {
{ "url": "https://haystack.johncosta.tech"
"url": "http://192.168.1.199:3040"
}
]
}, },
"log:default" {
] "url": "http://localhost:3040"
},
{
"url": "http://192.168.1.199:3040"
}
]
},
"log:default",
"fs:default",
"fs:default"
]
} }

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- AndroidTV support --> <!-- AndroidTV support -->
<uses-feature android:name="android.software.leanback" android:required="false" /> <uses-feature android:name="android.software.leanback" android:required="false" />
@ -18,7 +19,10 @@
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
<data android:mimeType="image/*" />
<!-- AndroidTV support --> <!-- AndroidTV support -->
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>

View File

@ -11,9 +11,11 @@ pub fn run() {
let watcher_state = new_shared_watcher_state(); let watcher_state = new_shared_watcher_state();
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_log::Builder::new().build()) .plugin(tauri_plugin_log::Builder::new().build())
.plugin(tauri_plugin_store::Builder::new().build()) .plugin(tauri_plugin_store::Builder::new().build())
.plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_sharetarget::init())
// .plugin(tauri_plugin_dialog::init()) // .plugin(tauri_plugin_dialog::init())
// .plugin(tauri_plugin_opener::init()) // .plugin(tauri_plugin_opener::init())
// .manage(watcher_state) // .manage(watcher_state)

View File

@ -1,13 +1,22 @@
import { Route, Router } from "@solidjs/router"; import { Route, Router } from "@solidjs/router";
import { listen } from "@tauri-apps/api/event"; import { listen } from "@tauri-apps/api/event";
import { createEffect, onCleanup } from "solid-js"; import { createEffect, createSignal, For, onCleanup, Show } from "solid-js";
import { Login } from "./Login"; import { Login } from "./Login";
import { ProtectedRoute } from "./ProtectedRoute"; import { ProtectedRoute } from "./ProtectedRoute";
import { Search } from "./Search"; import { Search } from "./Search";
import { Settings } from "./Settings"; import { Settings } from "./Settings";
import { ImageViewer } from "./components/ImageViewer"; import { ImageViewer } from "./components/ImageViewer";
import type { PluginListener } from "@tauri-apps/api/core";
import {
listenForShareEvents,
type ShareEvent,
} from "tauri-plugin-sharetarget-api";
import { readFile } from "@tauri-apps/plugin-fs";
export const App = () => { export const App = () => {
const [logs, setLogs] = createSignal<string[]>([]);
const [file, setFile] = createSignal<File>();
createEffect(() => { createEffect(() => {
// TODO: Don't use window.location.href // TODO: Don't use window.location.href
const unlisten = listen("focus-search", () => { const unlisten = listen("focus-search", () => {
@ -19,9 +28,40 @@ export const App = () => {
}); });
}); });
createEffect(() => {
let listener: PluginListener;
const setupListener = async () => {
listener = await listenForShareEvents(
async (intent: ShareEvent) => {
const contents = await readFile(intent.stream).catch(
(error: Error) => {
console.warn("fetching shared content failed:");
throw error;
},
);
setFile(
new File([contents], intent.name ?? "no-name", {
type: intent.content_type,
}),
);
setLogs((l) => [...l, intent.uri]);
},
);
};
setupListener();
return () => {
listener?.unregister();
};
});
return ( return (
<> <>
<ImageViewer /> <ImageViewer />
<p>Hello</p>
<Show when={file()}>
{(f) => <img alt="my-image" src={URL.createObjectURL(f())} />}
</Show>
<For each={logs()}>{(log) => <p>{log}</p>}</For>
<Router> <Router>
<Route path="/login" component={Login} /> <Route path="/login" component={Login} />