feat: improve multi-account switching
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { User } from "./user";
|
import { User } from "@/components/user";
|
||||||
import { getBitcoinDisplayValues } from "@lume/utils";
|
import { getBitcoinDisplayValues } from "@lume/utils";
|
||||||
import { useRouteContext } from "@tanstack/react-router";
|
import { useRouteContext } from "@tanstack/react-router";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
import { CancelIcon, CheckIcon } from "@lume/icons";
|
|
||||||
import type { LumeColumn } from "@lume/types";
|
|
||||||
import { cn } from "@lume/utils";
|
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
|
||||||
import { getCurrent } from "@tauri-apps/api/webviewWindow";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
|
|
||||||
export function Col({
|
|
||||||
column,
|
|
||||||
account,
|
|
||||||
isScroll,
|
|
||||||
isResize,
|
|
||||||
}: {
|
|
||||||
column: LumeColumn;
|
|
||||||
account: string;
|
|
||||||
isScroll: boolean;
|
|
||||||
isResize: boolean;
|
|
||||||
}) {
|
|
||||||
const container = useRef<HTMLDivElement>(null);
|
|
||||||
const [webview, setWebview] = useState<string | undefined>(undefined);
|
|
||||||
|
|
||||||
const repositionWebview = async () => {
|
|
||||||
if (webview && webview.length > 1) {
|
|
||||||
const newRect = container.current.getBoundingClientRect();
|
|
||||||
await invoke("reposition_column", {
|
|
||||||
label: webview,
|
|
||||||
x: newRect.x,
|
|
||||||
y: newRect.y,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const resizeWebview = async () => {
|
|
||||||
if (webview && webview.length > 1) {
|
|
||||||
const newRect = container.current.getBoundingClientRect();
|
|
||||||
await invoke("resize_column", {
|
|
||||||
label: webview,
|
|
||||||
width: newRect.width,
|
|
||||||
height: newRect.height,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
resizeWebview();
|
|
||||||
}, [isResize]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isScroll) repositionWebview();
|
|
||||||
}, [isScroll]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (webview && webview.length > 1) return;
|
|
||||||
|
|
||||||
const rect = container.current.getBoundingClientRect();
|
|
||||||
const windowLabel = `column-${column.label}`;
|
|
||||||
const url = `${column.content}?account=${account}&label=${column.label}&name=${column.name}`;
|
|
||||||
|
|
||||||
// create new webview
|
|
||||||
const label: string = await invoke("create_column", {
|
|
||||||
label: windowLabel,
|
|
||||||
x: rect.x,
|
|
||||||
y: rect.y,
|
|
||||||
width: rect.width,
|
|
||||||
height: rect.height,
|
|
||||||
url,
|
|
||||||
});
|
|
||||||
|
|
||||||
setWebview(label);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// close webview when unmounted
|
|
||||||
return () => {
|
|
||||||
if (webview && webview.length > 1) {
|
|
||||||
invoke("close_column", {
|
|
||||||
label: webview,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [webview]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="h-full w-[440px] shrink-0 p-2">
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex flex-col w-full h-full rounded-xl",
|
|
||||||
column.label !== "open"
|
|
||||||
? "bg-black/5 dark:bg-white/5 backdrop-blur-sm"
|
|
||||||
: "",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{column.label !== "open" ? (
|
|
||||||
<Header label={column.label} name={column.name} />
|
|
||||||
) : null}
|
|
||||||
<div ref={container} className="flex-1 w-full h-full" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Header({ label, name }: { label: string; name: string }) {
|
|
||||||
const [title, setTitle] = useState(name);
|
|
||||||
const [isChanged, setIsChanged] = useState(false);
|
|
||||||
|
|
||||||
const saveNewTitle = async () => {
|
|
||||||
const mainWindow = getCurrent();
|
|
||||||
await mainWindow.emit("columns", { type: "set_title", label, title });
|
|
||||||
|
|
||||||
// update search params
|
|
||||||
// @ts-ignore, hahaha
|
|
||||||
search.name = title;
|
|
||||||
|
|
||||||
// reset state
|
|
||||||
setIsChanged(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const close = async () => {
|
|
||||||
const mainWindow = getCurrent();
|
|
||||||
await mainWindow.emit("columns", { type: "remove", label });
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (title.length !== name.length) setIsChanged(true);
|
|
||||||
}, [title]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="h-9 w-full flex items-center justify-between shrink-0 px-1">
|
|
||||||
<div className="size-7" />
|
|
||||||
<div className="shrink-0 h-9 flex items-center justify-center">
|
|
||||||
<div className="relative flex gap-2 items-center">
|
|
||||||
<div
|
|
||||||
contentEditable
|
|
||||||
suppressContentEditableWarning={true}
|
|
||||||
onBlur={(e) => setTitle(e.currentTarget.textContent)}
|
|
||||||
className="text-sm font-medium focus:outline-none"
|
|
||||||
>
|
|
||||||
{name}
|
|
||||||
</div>
|
|
||||||
{isChanged ? (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => saveNewTitle()}
|
|
||||||
className="text-teal-500 hover:text-teal-600"
|
|
||||||
>
|
|
||||||
<CheckIcon className="size-4" />
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => close()}
|
|
||||||
className="size-7 inline-flex hover:bg-black/10 rounded-lg dark:hover:bg-white/10 items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200"
|
|
||||||
>
|
|
||||||
<CancelIcon className="size-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
147
apps/desktop2/src/components/column.tsx
Normal file
147
apps/desktop2/src/components/column.tsx
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import { CancelIcon, CheckIcon } from "@lume/icons";
|
||||||
|
import type { LumeColumn } from "@lume/types";
|
||||||
|
import { cn } from "@lume/utils";
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import { getCurrent } from "@tauri-apps/api/webviewWindow";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
export function Column({
|
||||||
|
column,
|
||||||
|
account,
|
||||||
|
isScroll,
|
||||||
|
isResize,
|
||||||
|
}: {
|
||||||
|
column: LumeColumn;
|
||||||
|
account: string;
|
||||||
|
isScroll: boolean;
|
||||||
|
isResize: boolean;
|
||||||
|
}) {
|
||||||
|
const container = useRef<HTMLDivElement>(null);
|
||||||
|
const webviewLabel = `column-${account}_${column.label}`;
|
||||||
|
|
||||||
|
const [isCreated, setIsCreated] = useState(false);
|
||||||
|
|
||||||
|
const repositionWebview = async () => {
|
||||||
|
const newRect = container.current.getBoundingClientRect();
|
||||||
|
await invoke("reposition_column", {
|
||||||
|
label: webviewLabel,
|
||||||
|
x: newRect.x,
|
||||||
|
y: newRect.y,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resizeWebview = async () => {
|
||||||
|
const newRect = container.current.getBoundingClientRect();
|
||||||
|
await invoke("resize_column", {
|
||||||
|
label: webviewLabel,
|
||||||
|
width: newRect.width,
|
||||||
|
height: newRect.height,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isCreated) resizeWebview();
|
||||||
|
}, [isResize]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isScroll && isCreated) repositionWebview();
|
||||||
|
}, [isScroll]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const rect = container.current.getBoundingClientRect();
|
||||||
|
const url = `${column.content}?account=${account}&label=${column.label}&name=${column.name}`;
|
||||||
|
|
||||||
|
// create new webview
|
||||||
|
invoke("create_column", {
|
||||||
|
label: webviewLabel,
|
||||||
|
x: rect.x,
|
||||||
|
y: rect.y,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
url,
|
||||||
|
}).then(() => setIsCreated(true));
|
||||||
|
|
||||||
|
// close webview when unmounted
|
||||||
|
return () => {
|
||||||
|
invoke("close_column", { label: webviewLabel });
|
||||||
|
};
|
||||||
|
}, [account]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full w-[440px] shrink-0 p-2">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col w-full h-full rounded-xl",
|
||||||
|
column.label !== "open"
|
||||||
|
? "bg-black/5 dark:bg-white/5 backdrop-blur-sm"
|
||||||
|
: "",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{column.label !== "open" ? (
|
||||||
|
<Header label={column.label} name={column.name} />
|
||||||
|
) : null}
|
||||||
|
<div ref={container} className="flex-1 w-full h-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Header({ label, name }: { label: string; name: string }) {
|
||||||
|
const [title, setTitle] = useState(name);
|
||||||
|
const [isChanged, setIsChanged] = useState(false);
|
||||||
|
|
||||||
|
const saveNewTitle = async () => {
|
||||||
|
const mainWindow = getCurrent();
|
||||||
|
await mainWindow.emit("columns", { type: "set_title", label, title });
|
||||||
|
|
||||||
|
// update search params
|
||||||
|
// @ts-ignore, hahaha
|
||||||
|
search.name = title;
|
||||||
|
|
||||||
|
// reset state
|
||||||
|
setIsChanged(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const close = async () => {
|
||||||
|
const mainWindow = getCurrent();
|
||||||
|
await mainWindow.emit("columns", { type: "remove", label });
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (title.length !== name.length) setIsChanged(true);
|
||||||
|
}, [title]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-9 w-full flex items-center justify-between shrink-0 px-1">
|
||||||
|
<div className="size-7" />
|
||||||
|
<div className="shrink-0 h-9 flex items-center justify-center">
|
||||||
|
<div className="relative flex gap-2 items-center">
|
||||||
|
<div
|
||||||
|
contentEditable
|
||||||
|
suppressContentEditableWarning={true}
|
||||||
|
onBlur={(e) => setTitle(e.currentTarget.textContent)}
|
||||||
|
className="text-sm font-medium focus:outline-none"
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
{isChanged ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => saveNewTitle()}
|
||||||
|
className="text-teal-500 hover:text-teal-600"
|
||||||
|
>
|
||||||
|
<CheckIcon className="size-4" />
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => close()}
|
||||||
|
className="size-7 inline-flex hover:bg-black/10 rounded-lg dark:hover:bg-white/10 items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200"
|
||||||
|
>
|
||||||
|
<CancelIcon className="size-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ThreadIcon } from "@lume/icons";
|
import { ThreadIcon } from "@lume/icons";
|
||||||
import type { Event } from "@lume/types";
|
import type { Event } from "@lume/types";
|
||||||
import { Note } from "./note";
|
import { Note } from "@/components/note";
|
||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
import { useRouteContext } from "@tanstack/react-router";
|
import { useRouteContext } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Event } from "@lume/types";
|
import type { Event } from "@lume/types";
|
||||||
import { Note } from "./note";
|
import { Note } from "@/components/note";
|
||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
|
|
||||||
export function Notification({
|
export function Notification({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { QuoteIcon } from "@lume/icons";
|
import { QuoteIcon } from "@lume/icons";
|
||||||
import type { Event } from "@lume/types";
|
import type { Event } from "@lume/types";
|
||||||
import { Note } from "./note";
|
import { Note } from "@/components/note";
|
||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
|
|
||||||
export function Quote({
|
export function Quote({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Event } from "@lume/types";
|
import type { Event } from "@lume/types";
|
||||||
import { Spinner } from "@lume/ui";
|
import { Spinner } from "@lume/ui";
|
||||||
import { Note } from "./note";
|
import { Note } from "@/components/note";
|
||||||
import { User } from "./user";
|
import { User } from "@/components/user";
|
||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useRouteContext } from "@tanstack/react-router";
|
import { useRouteContext } from "@tanstack/react-router";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Event } from "@lume/types";
|
import type { Event } from "@lume/types";
|
||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
import { Note } from "./note";
|
import { Note } from "@/components/note";
|
||||||
|
|
||||||
export function TextNote({
|
export function TextNote({
|
||||||
event,
|
event,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Col } from "@/components/col";
|
import { Column } from "@/components/column";
|
||||||
import { Toolbar } from "@/components/toolbar";
|
import { Toolbar } from "@/components/toolbar";
|
||||||
import { ArrowLeftIcon, ArrowRightIcon } from "@lume/icons";
|
import { ArrowLeftIcon, ArrowRightIcon } from "@lume/icons";
|
||||||
import type { EventColumns, LumeColumn } from "@lume/types";
|
import type { EventColumns, LumeColumn } from "@lume/types";
|
||||||
@@ -13,20 +13,19 @@ import { useDebouncedCallback } from "use-debounce";
|
|||||||
import { VList, type VListHandle } from "virtua";
|
import { VList, type VListHandle } from "virtua";
|
||||||
|
|
||||||
export const Route = createFileRoute("/$account/home")({
|
export const Route = createFileRoute("/$account/home")({
|
||||||
beforeLoad: async ({ context }) => {
|
loader: async ({ context }) => {
|
||||||
try {
|
try {
|
||||||
const ark = context.ark;
|
const userColumns = await context.ark.get_columns();
|
||||||
const resourcePath = await resolveResource(
|
if (userColumns.length > 0) {
|
||||||
"resources/system_columns.json",
|
return userColumns;
|
||||||
);
|
} else {
|
||||||
const systemColumns: LumeColumn[] = JSON.parse(
|
const systemPath = "resources/system_columns.json";
|
||||||
await readTextFile(resourcePath),
|
const resourcePath = await resolveResource(systemPath);
|
||||||
);
|
const resourceFile = await readTextFile(resourcePath);
|
||||||
const userColumns = await ark.get_columns();
|
const systemColumns: LumeColumn[] = JSON.parse(resourceFile);
|
||||||
|
|
||||||
return {
|
return systemColumns;
|
||||||
storedColumns: !userColumns.length ? systemColumns : userColumns,
|
}
|
||||||
};
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(String(e));
|
console.error(String(e));
|
||||||
}
|
}
|
||||||
@@ -35,13 +34,14 @@ export const Route = createFileRoute("/$account/home")({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function Screen() {
|
function Screen() {
|
||||||
|
const userSavedColumns = Route.useLoaderData();
|
||||||
const vlistRef = useRef<VListHandle>(null);
|
const vlistRef = useRef<VListHandle>(null);
|
||||||
|
|
||||||
const { account } = Route.useParams();
|
const { account } = Route.useParams();
|
||||||
const { ark, storedColumns } = Route.useRouteContext();
|
const { ark } = Route.useRouteContext();
|
||||||
|
|
||||||
const [selectedIndex, setSelectedIndex] = useState(-1);
|
const [selectedIndex, setSelectedIndex] = useState(-1);
|
||||||
const [columns, setColumns] = useState(storedColumns);
|
const [columns, setColumns] = useState([]);
|
||||||
const [isScroll, setIsScroll] = useState(false);
|
const [isScroll, setIsScroll] = useState(false);
|
||||||
const [isResize, setIsResize] = useState(false);
|
const [isResize, setIsResize] = useState(false);
|
||||||
|
|
||||||
@@ -114,6 +114,10 @@ function Screen() {
|
|||||||
150,
|
150,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setColumns(userSavedColumns);
|
||||||
|
}, [userSavedColumns]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// save state
|
// save state
|
||||||
ark.set_columns(columns);
|
ark.set_columns(columns);
|
||||||
@@ -148,9 +152,10 @@ function Screen() {
|
|||||||
onScroll={() => setIsScroll(true)}
|
onScroll={() => setIsScroll(true)}
|
||||||
onScrollEnd={() => setIsScroll(false)}
|
onScrollEnd={() => setIsScroll(false)}
|
||||||
className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none"
|
className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none"
|
||||||
|
cache={null}
|
||||||
>
|
>
|
||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
<Col
|
<Column
|
||||||
key={column.label}
|
key={column.label}
|
||||||
column={column}
|
column={column}
|
||||||
account={account}
|
account={account}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Outlet, createFileRoute } from "@tanstack/react-router";
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { getCurrent } from "@tauri-apps/api/window";
|
import { getCurrent } from "@tauri-apps/api/window";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export const Route = createFileRoute("/$account")({
|
export const Route = createFileRoute("/$account")({
|
||||||
beforeLoad: async ({ context }) => {
|
beforeLoad: async ({ context }) => {
|
||||||
@@ -78,12 +79,17 @@ function Accounts() {
|
|||||||
const { account } = Route.useParams();
|
const { account } = Route.useParams();
|
||||||
|
|
||||||
const changeAccount = async (npub: string) => {
|
const changeAccount = async (npub: string) => {
|
||||||
if (npub === account) return;
|
if (npub === account) {
|
||||||
|
return await ark.open_profile(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
// change current account and update signer
|
||||||
const select = await ark.load_selected_account(npub);
|
const select = await ark.load_selected_account(npub);
|
||||||
|
|
||||||
if (select) {
|
if (select) {
|
||||||
return navigate({ to: "/$account/home", params: { account: npub } });
|
return navigate({ to: "/$account/home", params: { account: npub } });
|
||||||
|
} else {
|
||||||
|
toast.warning("Something wrong.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,7 +100,7 @@ function Accounts() {
|
|||||||
<User.Provider pubkey={user}>
|
<User.Provider pubkey={user}>
|
||||||
<User.Root
|
<User.Root
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-full",
|
"rounded-full transition-all ease-in-out duration-150 will-change-auto",
|
||||||
user === account
|
user === account
|
||||||
? "ring-1 ring-teal-500 ring-offset-2 ring-offset-neutral-200 dark:ring-offset-neutral-950"
|
? "ring-1 ring-teal-500 ring-offset-2 ring-offset-neutral-200 dark:ring-offset-neutral-950"
|
||||||
: "",
|
: "",
|
||||||
@@ -102,7 +108,7 @@ function Accounts() {
|
|||||||
>
|
>
|
||||||
<User.Avatar
|
<User.Avatar
|
||||||
className={cn(
|
className={cn(
|
||||||
"aspect-square h-auto rounded-full object-cover",
|
"aspect-square h-auto rounded-full object-cover transition-all ease-in-out duration-150 will-change-auto",
|
||||||
user === account ? "w-7" : "w-8",
|
user === account ? "w-7" : "w-8",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","splash","settings","search","nwc","activity","zap-*","event-*","user-*","editor-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","updater:default","updater:allow-check","updater:allow-download-and-install","window:allow-start-dragging","window:allow-create","window:allow-close","window:allow-set-focus","clipboard-manager:allow-write","clipboard-manager:allow-read","webview:allow-create-webview-window","webview:allow-create-webview","webview:allow-set-webview-size","webview:allow-set-webview-position","webview:allow-webview-close","dialog:default","dialog:allow-ask","dialog:allow-message","fs:allow-read-file","shell:allow-open",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}}
|
{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","splash","settings","search","nwc","activity","zap-*","event-*","user-*","editor-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","updater:default","updater:allow-check","updater:allow-download-and-install","window:allow-start-dragging","window:allow-create","window:allow-close","window:allow-set-focus","clipboard-manager:allow-write","clipboard-manager:allow-read","webview:allow-create-webview-window","webview:allow-create-webview","webview:allow-set-webview-size","webview:allow-set-webview-position","webview:allow-webview-close","dialog:default","dialog:allow-ask","dialog:allow-message","process:allow-restart","fs:allow-read-file","shell:allow-open",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}}
|
||||||
@@ -289,7 +289,7 @@ pub async fn unfollow(id: &str, state: State<'_, Nostr>) -> Result<EventId, Stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command(async)]
|
||||||
pub async fn set_nstore(
|
pub async fn set_nstore(
|
||||||
key: &str,
|
key: &str,
|
||||||
content: &str,
|
content: &str,
|
||||||
@@ -306,10 +306,7 @@ pub async fn set_nstore(
|
|||||||
let builder = EventBuilder::new(Kind::ApplicationSpecificData, encrypted, vec![tag]);
|
let builder = EventBuilder::new(Kind::ApplicationSpecificData, encrypted, vec![tag]);
|
||||||
|
|
||||||
match client.send_event_builder(builder).await {
|
match client.send_event_builder(builder).await {
|
||||||
Ok(event_id) => {
|
Ok(event_id) => Ok(event_id),
|
||||||
println!("set nstore: {}", event_id);
|
|
||||||
Ok(event_id)
|
|
||||||
}
|
|
||||||
Err(err) => Err(err.to_string()),
|
Err(err) => Err(err.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,38 +319,29 @@ pub async fn get_nstore(key: &str, state: State<'_, Nostr>) -> Result<String, St
|
|||||||
let client = &state.client;
|
let client = &state.client;
|
||||||
|
|
||||||
if let Ok(signer) = client.signer().await {
|
if let Ok(signer) = client.signer().await {
|
||||||
let public_key = signer.public_key().await;
|
let public_key = signer.public_key().await.unwrap();
|
||||||
|
|
||||||
if let Ok(author) = public_key {
|
|
||||||
let filter = Filter::new()
|
let filter = Filter::new()
|
||||||
.author(author)
|
.author(public_key)
|
||||||
.kind(Kind::ApplicationSpecificData)
|
.kind(Kind::ApplicationSpecificData)
|
||||||
.identifier(key)
|
.identifier(key)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
let query = client
|
match client
|
||||||
.get_events_of(vec![filter], Some(Duration::from_secs(10)))
|
.get_events_of(vec![filter], Some(Duration::from_secs(5)))
|
||||||
.await;
|
.await
|
||||||
|
{
|
||||||
if let Ok(events) = query {
|
Ok(events) => {
|
||||||
if let Some(event) = events.first() {
|
if let Some(event) = events.first() {
|
||||||
println!("get nstore key: {} - received: {}", key, event.id);
|
|
||||||
|
|
||||||
let content = event.content();
|
let content = event.content();
|
||||||
|
match signer.nip44_decrypt(public_key, content).await {
|
||||||
match signer.nip44_decrypt(author, content).await {
|
|
||||||
Ok(decrypted) => Ok(decrypted),
|
Ok(decrypted) => Ok(decrypted),
|
||||||
Err(_) => Err(event.content.to_string()),
|
Err(_) => Err(event.content.to_string()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("get nstore key: {}", key);
|
|
||||||
Err("Value not found".into())
|
Err("Value not found".into())
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Err("Query nstore event failed".into())
|
|
||||||
}
|
}
|
||||||
} else {
|
Err(err) => Err(err.to_string()),
|
||||||
Err("Something is wrong".into())
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err("Signer is required".into())
|
Err("Signer is required".into())
|
||||||
|
|||||||
Reference in New Issue
Block a user