From 7724eccd724504cad62e06865ff653cf22f13b6a Mon Sep 17 00:00:00 2001
From: reya <123083837+reyamir@users.noreply.github.com>
Date: Wed, 15 May 2024 13:58:03 +0700
Subject: [PATCH] feat: improve tauri commands
---
apps/desktop2/src/components/balance.tsx | 64 ++--
apps/desktop2/src/components/column.tsx | 236 +++++++-------
apps/desktop2/src/components/conversation.tsx | 74 ++---
apps/desktop2/src/components/note/index.ts | 24 +-
apps/desktop2/src/components/notification.tsx | 48 +--
apps/desktop2/src/components/quote.tsx | 74 ++---
apps/desktop2/src/components/repost.tsx | 140 ++++----
apps/desktop2/src/components/text.tsx | 52 +--
apps/desktop2/src/routes/$account.home.tsx | 290 ++++++++---------
apps/desktop2/src/routes/$account.tsx | 300 +++++++++---------
apps/desktop2/src/routes/editor/index.tsx | 1 +
packages/ark/src/ark.ts | 48 ++-
src-tauri/src/nostr/event.rs | 42 ++-
src-tauri/src/nostr/keys.rs | 15 +-
src-tauri/src/nostr/metadata.rs | 4 +-
15 files changed, 701 insertions(+), 711 deletions(-)
diff --git a/apps/desktop2/src/components/balance.tsx b/apps/desktop2/src/components/balance.tsx
index e4cb027e..f117f619 100644
--- a/apps/desktop2/src/components/balance.tsx
+++ b/apps/desktop2/src/components/balance.tsx
@@ -4,39 +4,39 @@ import { useRouteContext } from "@tanstack/react-router";
import { useEffect, useMemo, useState } from "react";
export function Balance({ account }: { account: string }) {
- const { ark } = useRouteContext({ strict: false });
- const [balance, setBalance] = useState(0);
- const value = useMemo(() => getBitcoinDisplayValues(balance), [balance]);
+ const { ark } = useRouteContext({ strict: false });
+ const [balance, setBalance] = useState(0);
+ const value = useMemo(() => getBitcoinDisplayValues(balance), [balance]);
- useEffect(() => {
- async function getBalance() {
- const val = await ark.get_balance();
- setBalance(val);
- }
+ useEffect(() => {
+ async function getBalance() {
+ const val = await ark.get_balance();
+ setBalance(val);
+ }
- getBalance();
- }, []);
+ getBalance();
+ }, []);
- return (
-
-
-
-
- Your balance
-
-
- ₿ {value.bitcoinFormatted}
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+ Your balance
+
+
+ ₿ {value.bitcoinFormatted}
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/components/column.tsx b/apps/desktop2/src/components/column.tsx
index bc7eef47..a6add5e0 100644
--- a/apps/desktop2/src/components/column.tsx
+++ b/apps/desktop2/src/components/column.tsx
@@ -6,142 +6,142 @@ import { getCurrent } from "@tauri-apps/api/webviewWindow";
import { useEffect, useRef, useState } from "react";
export function Column({
- column,
- account,
- isScroll,
- isResize,
+ column,
+ account,
+ isScroll,
+ isResize,
}: {
- column: LumeColumn;
- account: string;
- isScroll: boolean;
- isResize: boolean;
+ column: LumeColumn;
+ account: string;
+ isScroll: boolean;
+ isResize: boolean;
}) {
- const container = useRef(null);
- const webviewLabel = `column-${account}_${column.label}`;
+ const container = useRef(null);
+ const webviewLabel = `column-${account}_${column.label}`;
- const [isCreated, setIsCreated] = useState(false);
+ 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 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,
- });
- };
+ 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 (isCreated) resizeWebview();
+ }, [isResize]);
- useEffect(() => {
- if (isScroll && isCreated) repositionWebview();
- }, [isScroll]);
+ useEffect(() => {
+ if (isScroll && isCreated) repositionWebview();
+ }, [isScroll]);
- useEffect(() => {
- const rect = container.current.getBoundingClientRect();
- const url = `${column.content}?account=${account}&label=${column.label}&name=${column.name}`;
+ 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));
+ // 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]);
+ // close webview when unmounted
+ return () => {
+ invoke("close_column", { label: webviewLabel });
+ };
+ }, [account]);
- return (
-
-
- {column.label !== "open" ? (
-
- ) : null}
-
-
-
- );
+ return (
+
+
+ {column.label !== "open" ? (
+
+ ) : null}
+
+
+
+ );
}
function Header({ label, name }: { label: string; name: string }) {
- const [title, setTitle] = useState(name);
- const [isChanged, setIsChanged] = useState(false);
+ 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 });
+ const saveNewTitle = async () => {
+ const mainWindow = getCurrent();
+ await mainWindow.emit("columns", { type: "set_title", label, title });
- // update search params
- // @ts-ignore, hahaha
- search.name = title;
+ // update search params
+ // @ts-ignore, hahaha
+ search.name = title;
- // reset state
- setIsChanged(false);
- };
+ // reset state
+ setIsChanged(false);
+ };
- const close = async () => {
- const mainWindow = getCurrent();
- await mainWindow.emit("columns", { type: "remove", label });
- };
+ const close = async () => {
+ const mainWindow = getCurrent();
+ await mainWindow.emit("columns", { type: "remove", label });
+ };
- useEffect(() => {
- if (title.length !== name.length) setIsChanged(true);
- }, [title]);
+ useEffect(() => {
+ if (title.length !== name.length) setIsChanged(true);
+ }, [title]);
- return (
-
-
-
-
-
setTitle(e.currentTarget.textContent)}
- className="text-sm font-medium focus:outline-none"
- >
- {name}
-
- {isChanged ? (
-
- ) : null}
-
-
-
-
- );
+ return (
+
+
+
+
+
setTitle(e.currentTarget.textContent)}
+ className="text-sm font-medium focus:outline-none"
+ >
+ {name}
+
+ {isChanged ? (
+
+ ) : null}
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/components/conversation.tsx b/apps/desktop2/src/components/conversation.tsx
index 879cd091..2f9c30b6 100644
--- a/apps/desktop2/src/components/conversation.tsx
+++ b/apps/desktop2/src/components/conversation.tsx
@@ -5,44 +5,44 @@ import { cn } from "@lume/utils";
import { useRouteContext } from "@tanstack/react-router";
export function Conversation({
- event,
- className,
+ event,
+ className,
}: {
- event: Event;
- className?: string;
+ event: Event;
+ className?: string;
}) {
- const { ark } = useRouteContext({ strict: false });
- const thread = ark.parse_event_thread(event.tags);
+ const { ark } = useRouteContext({ strict: false });
+ const thread = ark.parse_event_thread(event.tags);
- return (
-
-
-
- {thread?.root ?
: null}
-
- {thread?.reply ?
: null}
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+ {thread?.root ?
: null}
+
+ {thread?.reply ?
: null}
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/components/note/index.ts b/apps/desktop2/src/components/note/index.ts
index 0112a7e4..c52887b0 100644
--- a/apps/desktop2/src/components/note/index.ts
+++ b/apps/desktop2/src/components/note/index.ts
@@ -12,16 +12,16 @@ import { NoteRoot } from "./root";
import { NoteUser } from "./user";
export const Note = {
- Provider: NoteProvider,
- Root: NoteRoot,
- User: NoteUser,
- Menu: NoteMenu,
- Reply: NoteReply,
- Repost: NoteRepost,
- Content: NoteContent,
- ContentLarge: NoteContentLarge,
- Zap: NoteZap,
- Open: NoteOpenThread,
- Child: NoteChild,
- Activity: NoteActivity,
+ Provider: NoteProvider,
+ Root: NoteRoot,
+ User: NoteUser,
+ Menu: NoteMenu,
+ Reply: NoteReply,
+ Repost: NoteRepost,
+ Content: NoteContent,
+ ContentLarge: NoteContentLarge,
+ Zap: NoteZap,
+ Open: NoteOpenThread,
+ Child: NoteChild,
+ Activity: NoteActivity,
};
diff --git a/apps/desktop2/src/components/notification.tsx b/apps/desktop2/src/components/notification.tsx
index 7daf6d6b..3b1d6e04 100644
--- a/apps/desktop2/src/components/notification.tsx
+++ b/apps/desktop2/src/components/notification.tsx
@@ -3,30 +3,30 @@ import { Note } from "@/components/note";
import { cn } from "@lume/utils";
export function Notification({
- event,
- className,
+ event,
+ className,
}: {
- event: Event;
- className?: string;
+ event: Event;
+ className?: string;
}) {
- return (
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/components/quote.tsx b/apps/desktop2/src/components/quote.tsx
index d4a2913e..60655ee2 100644
--- a/apps/desktop2/src/components/quote.tsx
+++ b/apps/desktop2/src/components/quote.tsx
@@ -4,44 +4,44 @@ import { Note } from "@/components/note";
import { cn } from "@lume/utils";
export function Quote({
- event,
- className,
+ event,
+ className,
}: {
- event: Event;
- className?: string;
+ event: Event;
+ className?: string;
}) {
- const quoteEventId = event.tags.find(
- (tag) => tag[0] === "q" || tag[3] === "mention",
- )?.[1];
+ const quoteEventId = event.tags.find(
+ (tag) => tag[0] === "q" || tag[3] === "mention",
+ )?.[1];
- return (
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/components/repost.tsx b/apps/desktop2/src/components/repost.tsx
index 43ee5302..479005b0 100644
--- a/apps/desktop2/src/components/repost.tsx
+++ b/apps/desktop2/src/components/repost.tsx
@@ -7,79 +7,79 @@ import { useQuery } from "@tanstack/react-query";
import { useRouteContext } from "@tanstack/react-router";
export function RepostNote({
- event,
- className,
+ event,
+ className,
}: {
- event: Event;
- className?: string;
+ event: Event;
+ className?: string;
}) {
- const { ark } = useRouteContext({ strict: false });
- const {
- isLoading,
- isError,
- data: repostEvent,
- } = useQuery({
- queryKey: ["repost", event.id],
- queryFn: async () => {
- try {
- if (event.content.length > 50) {
- const embed: Event = JSON.parse(event.content);
- return embed;
- }
+ const { ark } = useRouteContext({ strict: false });
+ const {
+ isLoading,
+ isError,
+ data: repostEvent,
+ } = useQuery({
+ queryKey: ["repost", event.id],
+ queryFn: async () => {
+ try {
+ if (event.content.length > 50) {
+ const embed: Event = JSON.parse(event.content);
+ return embed;
+ }
- const id = event.tags.find((el) => el[0] === "e")?.[1];
- const repostEvent = await ark.get_event(id);
+ const id = event.tags.find((el) => el[0] === "e")?.[1];
+ const repostEvent = await ark.get_event(id);
- return repostEvent;
- } catch (e) {
- throw new Error(e);
- }
- },
- refetchOnWindowFocus: false,
- refetchOnMount: false,
- });
+ return repostEvent;
+ } catch (e) {
+ throw new Error(e);
+ }
+ },
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ });
- return (
-
-
-
-
- Reposted by
-
-
-
-
- {isLoading ? (
-
-
- Loading event...
-
- ) : isError || !repostEvent ? (
-
- Event not found within your current relay set
-
- ) : (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
- );
+ return (
+
+
+
+
+ Reposted by
+
+
+
+
+ {isLoading ? (
+
+
+ Loading event...
+
+ ) : isError || !repostEvent ? (
+
+ Event not found within your current relay set
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+ );
}
diff --git a/apps/desktop2/src/components/text.tsx b/apps/desktop2/src/components/text.tsx
index 8b91b639..087e6e29 100644
--- a/apps/desktop2/src/components/text.tsx
+++ b/apps/desktop2/src/components/text.tsx
@@ -3,32 +3,32 @@ import { cn } from "@lume/utils";
import { Note } from "@/components/note";
export function TextNote({
- event,
- className,
+ event,
+ className,
}: {
- event: Event;
- className?: string;
+ event: Event;
+ className?: string;
}) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/routes/$account.home.tsx b/apps/desktop2/src/routes/$account.home.tsx
index fea4fa0d..d10736a7 100644
--- a/apps/desktop2/src/routes/$account.home.tsx
+++ b/apps/desktop2/src/routes/$account.home.tsx
@@ -13,175 +13,175 @@ import { useDebouncedCallback } from "use-debounce";
import { VList, type VListHandle } from "virtua";
export const Route = createFileRoute("/$account/home")({
- loader: async ({ context }) => {
- try {
- const userColumns = await context.ark.get_columns();
- if (userColumns.length > 0) {
- return userColumns;
- } else {
- const systemPath = "resources/system_columns.json";
- const resourcePath = await resolveResource(systemPath);
- const resourceFile = await readTextFile(resourcePath);
- const systemColumns: LumeColumn[] = JSON.parse(resourceFile);
+ loader: async ({ context }) => {
+ try {
+ const userColumns = await context.ark.get_columns();
+ if (userColumns.length > 0) {
+ return userColumns;
+ } else {
+ const systemPath = "resources/system_columns.json";
+ const resourcePath = await resolveResource(systemPath);
+ const resourceFile = await readTextFile(resourcePath);
+ const systemColumns: LumeColumn[] = JSON.parse(resourceFile);
- return systemColumns;
- }
- } catch (e) {
- console.error(String(e));
- }
- },
- component: Screen,
+ return systemColumns;
+ }
+ } catch (e) {
+ console.error(String(e));
+ }
+ },
+ component: Screen,
});
function Screen() {
- const userSavedColumns = Route.useLoaderData();
- const vlistRef = useRef(null);
+ const userSavedColumns = Route.useLoaderData();
+ const vlistRef = useRef(null);
- const { account } = Route.useParams();
- const { ark } = Route.useRouteContext();
+ const { account } = Route.useParams();
+ const { ark } = Route.useRouteContext();
- const [selectedIndex, setSelectedIndex] = useState(-1);
- const [columns, setColumns] = useState([]);
- const [isScroll, setIsScroll] = useState(false);
- const [isResize, setIsResize] = useState(false);
+ const [selectedIndex, setSelectedIndex] = useState(-1);
+ const [columns, setColumns] = useState([]);
+ const [isScroll, setIsScroll] = useState(false);
+ const [isResize, setIsResize] = useState(false);
- const goLeft = () => {
- const prevIndex = Math.max(selectedIndex - 1, 0);
- setSelectedIndex(prevIndex);
- vlistRef.current.scrollToIndex(prevIndex, {
- align: "center",
- });
- };
+ const goLeft = () => {
+ const prevIndex = Math.max(selectedIndex - 1, 0);
+ setSelectedIndex(prevIndex);
+ vlistRef.current.scrollToIndex(prevIndex, {
+ align: "center",
+ });
+ };
- const goRight = () => {
- const nextIndex = Math.min(selectedIndex + 1, columns.length - 1);
- setSelectedIndex(nextIndex);
- vlistRef.current.scrollToIndex(nextIndex, {
- align: "center",
- });
- };
+ const goRight = () => {
+ const nextIndex = Math.min(selectedIndex + 1, columns.length - 1);
+ setSelectedIndex(nextIndex);
+ vlistRef.current.scrollToIndex(nextIndex, {
+ align: "center",
+ });
+ };
- const add = useDebouncedCallback((column: LumeColumn) => {
- // update col label
- column.label = `${column.label}-${nanoid()}`;
+ const add = useDebouncedCallback((column: LumeColumn) => {
+ // update col label
+ column.label = `${column.label}-${nanoid()}`;
- // create new cols
- const cols = [...columns];
- const openColIndex = cols.findIndex((col) => col.label === "open");
- const newCols = [
- ...cols.slice(0, openColIndex),
- column,
- ...cols.slice(openColIndex),
- ];
+ // create new cols
+ const cols = [...columns];
+ const openColIndex = cols.findIndex((col) => col.label === "open");
+ const newCols = [
+ ...cols.slice(0, openColIndex),
+ column,
+ ...cols.slice(openColIndex),
+ ];
- setColumns(newCols);
- setSelectedIndex(newCols.length);
- setIsScroll(true);
+ setColumns(newCols);
+ setSelectedIndex(newCols.length);
+ setIsScroll(true);
- // scroll to the newest column
- vlistRef.current.scrollToIndex(newCols.length - 1, {
- align: "end",
- });
- }, 150);
+ // scroll to the newest column
+ vlistRef.current.scrollToIndex(newCols.length - 1, {
+ align: "end",
+ });
+ }, 150);
- const remove = useDebouncedCallback((label: string) => {
- const newCols = columns.filter((t) => t.label !== label);
+ const remove = useDebouncedCallback((label: string) => {
+ const newCols = columns.filter((t) => t.label !== label);
- setColumns(newCols);
- setSelectedIndex(newCols.length);
- setIsScroll(true);
+ setColumns(newCols);
+ setSelectedIndex(newCols.length);
+ setIsScroll(true);
- // scroll to the first column
- vlistRef.current.scrollToIndex(newCols.length - 1, {
- align: "start",
- });
- }, 150);
+ // scroll to the first column
+ vlistRef.current.scrollToIndex(newCols.length - 1, {
+ align: "start",
+ });
+ }, 150);
- const updateName = useDebouncedCallback((label: string, title: string) => {
- const currentColIndex = columns.findIndex((col) => col.label === label);
+ const updateName = useDebouncedCallback((label: string, title: string) => {
+ const currentColIndex = columns.findIndex((col) => col.label === label);
- const updatedCol = Object.assign({}, columns[currentColIndex]);
- updatedCol.name = title;
+ const updatedCol = Object.assign({}, columns[currentColIndex]);
+ updatedCol.name = title;
- const newCols = columns.slice();
- newCols[currentColIndex] = updatedCol;
+ const newCols = columns.slice();
+ newCols[currentColIndex] = updatedCol;
- setColumns(newCols);
- }, 150);
+ setColumns(newCols);
+ }, 150);
- const startResize = useDebouncedCallback(
- () => setIsResize((prev) => !prev),
- 150,
- );
+ const startResize = useDebouncedCallback(
+ () => setIsResize((prev) => !prev),
+ 150,
+ );
- useEffect(() => {
- setColumns(userSavedColumns);
- }, [userSavedColumns]);
+ useEffect(() => {
+ setColumns(userSavedColumns);
+ }, [userSavedColumns]);
- useEffect(() => {
- // save state
- ark.set_columns(columns);
- }, [columns]);
+ useEffect(() => {
+ // save state
+ ark.set_columns(columns);
+ }, [columns]);
- useEffect(() => {
- const unlistenColEvent = listen("columns", (data) => {
- if (data.payload.type === "add") add(data.payload.column);
- if (data.payload.type === "remove") remove(data.payload.label);
- if (data.payload.type === "set_title")
- updateName(data.payload.label, data.payload.title);
- });
+ useEffect(() => {
+ const unlistenColEvent = listen("columns", (data) => {
+ if (data.payload.type === "add") add(data.payload.column);
+ if (data.payload.type === "remove") remove(data.payload.label);
+ if (data.payload.type === "set_title")
+ updateName(data.payload.label, data.payload.title);
+ });
- const unlistenWindowResize = getCurrent().listen("tauri://resize", () => {
- startResize();
- });
+ const unlistenWindowResize = getCurrent().listen("tauri://resize", () => {
+ startResize();
+ });
- return () => {
- unlistenColEvent.then((f) => f());
- unlistenWindowResize.then((f) => f());
- };
- }, []);
+ return () => {
+ unlistenColEvent.then((f) => f());
+ unlistenWindowResize.then((f) => f());
+ };
+ }, []);
- return (
-
-
setIsScroll(true)}
- onScrollEnd={() => setIsScroll(false)}
- className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none"
- cache={null}
- >
- {columns.map((column) => (
-
- ))}
-
-
-
-
-
-
-
-
- );
+ return (
+
+
setIsScroll(true)}
+ onScrollEnd={() => setIsScroll(false)}
+ className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none"
+ cache={null}
+ >
+ {columns.map((column) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/desktop2/src/routes/$account.tsx b/apps/desktop2/src/routes/$account.tsx
index 4da85563..f1c034f9 100644
--- a/apps/desktop2/src/routes/$account.tsx
+++ b/apps/desktop2/src/routes/$account.tsx
@@ -2,10 +2,10 @@ import { BellIcon, ComposeFilledIcon, PlusIcon, SearchIcon } from "@lume/icons";
import { Event, Kind } from "@lume/types";
import { User } from "@/components/user";
import {
- cn,
- decodeZapInvoice,
- displayNpub,
- sendNativeNotification,
+ cn,
+ decodeZapInvoice,
+ displayNpub,
+ sendNativeNotification,
} from "@lume/utils";
import { Outlet, createFileRoute } from "@tanstack/react-router";
import { invoke } from "@tauri-apps/api/core";
@@ -14,171 +14,171 @@ import { useEffect, useState } from "react";
import { toast } from "sonner";
export const Route = createFileRoute("/$account")({
- beforeLoad: async ({ context }) => {
- const ark = context.ark;
- const accounts = await ark.get_all_accounts();
+ beforeLoad: async ({ context }) => {
+ const ark = context.ark;
+ const accounts = await ark.get_all_accounts();
- return { accounts };
- },
- component: Screen,
+ return { accounts };
+ },
+ component: Screen,
});
function Screen() {
- const { ark, platform } = Route.useRouteContext();
- const navigate = Route.useNavigate();
+ const { ark, platform } = Route.useRouteContext();
+ const navigate = Route.useNavigate();
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
function Accounts() {
- const navigate = Route.useNavigate();
- const { ark, accounts } = Route.useRouteContext();
- const { account } = Route.useParams();
+ const navigate = Route.useNavigate();
+ const { ark, accounts } = Route.useRouteContext();
+ const { account } = Route.useParams();
- const changeAccount = async (npub: string) => {
- if (npub === account) {
- return await ark.open_profile(account);
- }
+ const changeAccount = async (npub: string) => {
+ if (npub === account) {
+ return await ark.open_profile(account);
+ }
- // change current account and update signer
- const select = await ark.load_selected_account(npub);
+ // change current account and update signer
+ const select = await ark.load_selected_account(npub);
- if (select) {
- return navigate({ to: "/$account/home", params: { account: npub } });
- } else {
- toast.warning("Something wrong.");
- }
- };
+ if (select) {
+ return navigate({ to: "/$account/home", params: { account: npub } });
+ } else {
+ toast.warning("Something wrong.");
+ }
+ };
- return (
-
- {accounts.map((user) => (
-
- ))}
-
- );
+ return (
+
+ {accounts.map((user) => (
+
+ ))}
+
+ );
}
function Bell() {
- const { ark } = Route.useRouteContext();
- const { account } = Route.useParams();
+ const { ark } = Route.useRouteContext();
+ const { account } = Route.useParams();
- const [count, setCount] = useState(0);
+ const [count, setCount] = useState(0);
- useEffect(() => {
- const unlisten = getCurrent().listen(
- "activity",
- async (payload) => {
- setCount((prevCount) => prevCount + 1);
- await invoke("set_badge", { count });
+ useEffect(() => {
+ const unlisten = getCurrent().listen(
+ "activity",
+ async (payload) => {
+ setCount((prevCount) => prevCount + 1);
+ await invoke("set_badge", { count });
- const event: Event = JSON.parse(payload.payload);
- const user = await ark.get_profile(event.pubkey);
- const userName =
- user.display_name || user.name || displayNpub(event.pubkey, 16);
+ const event: Event = JSON.parse(payload.payload);
+ const user = await ark.get_profile(event.pubkey);
+ const userName =
+ user.display_name || user.name || displayNpub(event.pubkey, 16);
- switch (event.kind) {
- case Kind.Text: {
- sendNativeNotification("Mentioned you in a note", userName);
- break;
- }
- case Kind.Repost: {
- sendNativeNotification("Reposted your note", userName);
- break;
- }
- case Kind.ZapReceipt: {
- const amount = decodeZapInvoice(event.tags);
- sendNativeNotification(
- `Zapped ₿ ${amount.bitcoinFormatted}`,
- userName,
- );
- break;
- }
- default:
- break;
- }
- },
- );
+ switch (event.kind) {
+ case Kind.Text: {
+ sendNativeNotification("Mentioned you in a note", userName);
+ break;
+ }
+ case Kind.Repost: {
+ sendNativeNotification("Reposted your note", userName);
+ break;
+ }
+ case Kind.ZapReceipt: {
+ const amount = decodeZapInvoice(event.tags);
+ sendNativeNotification(
+ `Zapped ₿ ${amount.bitcoinFormatted}`,
+ userName,
+ );
+ break;
+ }
+ default:
+ break;
+ }
+ },
+ );
- return () => {
- unlisten.then((f) => f());
- };
- }, []);
+ return () => {
+ unlisten.then((f) => f());
+ };
+ }, []);
- return (
-
- );
+ return (
+
+ );
}
diff --git a/apps/desktop2/src/routes/editor/index.tsx b/apps/desktop2/src/routes/editor/index.tsx
index 2515bc71..8f7c120b 100644
--- a/apps/desktop2/src/routes/editor/index.tsx
+++ b/apps/desktop2/src/routes/editor/index.tsx
@@ -25,6 +25,7 @@ import { MediaButton } from "./-components/media";
import { NsfwToggle } from "./-components/nsfw";
import { MentionButton } from "./-components/mention";
import { MentionNote } from "@/components/note/mentions/note";
+import { toast } from "sonner";
type EditorSearch = {
reply_to: string;
diff --git a/packages/ark/src/ark.ts b/packages/ark/src/ark.ts
index 6837a300..59d4434f 100644
--- a/packages/ark/src/ark.ts
+++ b/packages/ark/src/ark.ts
@@ -207,12 +207,10 @@ export class Ark {
global?: boolean,
) {
try {
- let until: string = undefined;
+ const until: string = asOf && asOf > 0 ? asOf.toString() : undefined;
const isGlobal = global ?? false;
+ const seens = new Set();
- if (asOf && asOf > 0) until = asOf.toString();
-
- const seenIds = new Set();
const nostrEvents: Event[] = await invoke("get_events", {
limit,
until,
@@ -220,39 +218,31 @@ export class Ark {
global: isGlobal,
});
- // remove duplicate event
- for (const event of nostrEvents) {
- if (event.kind === Kind.Repost) {
- const repostId = event.tags.find((tag) => tag[0] === "e")?.[1];
- seenIds.add(repostId);
+ const events = nostrEvents.filter((event) => {
+ const eTags = event.tags.filter((el) => el[0] === "e");
+ const ids = eTags.map((item) => item[1]);
+ const isDup = ids.some((id) => seens.has(id));
+
+ // Add found ids to seen list
+ for (const id of ids) {
+ seens.add(id);
}
- const eventIds = event.tags
- .filter((el) => el[0] === "e")
- ?.map((item) => item[1]);
+ // Filter NSFW event
+ if (this.settings?.nsfw) {
+ const wTags = event.tags.filter((t) => t[0] === "content-warning");
+ const isLewd = wTags.length > 0;
- if (eventIds?.length) {
- for (const id of eventIds) {
- seenIds.add(id);
- }
+ return !isDup && !isLewd;
}
- }
- const events = nostrEvents
- .filter((event) => !seenIds.has(event.id))
- .sort((a, b) => b.created_at - a.created_at);
-
- if (this.settings?.nsfw) {
- return events.filter(
- (event) =>
- event.tags.filter((event) => event[0] === "content-warning")
- .length > 0,
- );
- }
+ // Filter duplicate event
+ return !isDup;
+ });
return events;
} catch (e) {
- console.info(String(e));
+ console.error("[get_events] failed", String(e));
return [];
}
}
diff --git a/src-tauri/src/nostr/event.rs b/src-tauri/src/nostr/event.rs
index 38ed3028..4c53bed6 100644
--- a/src-tauri/src/nostr/event.rs
+++ b/src-tauri/src/nostr/event.rs
@@ -9,7 +9,15 @@ pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result = match Nip19::from_bech32(id) {
Ok(val) => match val {
Nip19::EventId(id) => Some(id),
- Nip19::Event(event) => Some(event.event_id),
+ Nip19::Event(event) => {
+ let relays = event.relays;
+ for relay in relays.into_iter() {
+ let url = Url::from_str(&relay).unwrap();
+ let _ = client.add_relay(url.clone()).await.unwrap_or_default();
+ client.connect_relay(url).await.unwrap_or_default();
+ }
+ Some(event.event_id)
+ }
_ => None,
},
Err(_) => match EventId::from_hex(id) {
@@ -18,23 +26,25 @@ pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result {
+ let filter = Filter::new().id(id);
- if let Ok(events) = &client
- .get_events_of(vec![filter], Some(Duration::from_secs(10)))
- .await
- {
- if let Some(event) = events.first() {
- Ok(event.as_json())
- } else {
- Err("Event not found with current relay list".into())
+ match &client
+ .get_events_of(vec![filter], Some(Duration::from_secs(10)))
+ .await
+ {
+ Ok(events) => {
+ if let Some(event) = events.first() {
+ Ok(event.as_json())
+ } else {
+ Err("Cannot found this event with current relay list".into())
+ }
+ }
+ Err(err) => Err(err.to_string()),
}
- } else {
- Err("Event not found with current relay list".into())
}
- } else {
- Err("EventId is not valid".into())
+ None => Err("Event ID is not valid.".into()),
}
}
@@ -213,8 +223,6 @@ pub async fn search(
limit: usize,
state: State<'_, Nostr>,
) -> Result, String> {
- println!("search: {}", content);
-
let client = &state.client;
let filter = Filter::new()
.kinds(vec![Kind::TextNote, Kind::Metadata])
diff --git a/src-tauri/src/nostr/keys.rs b/src-tauri/src/nostr/keys.rs
index fceb89bf..501779c7 100644
--- a/src-tauri/src/nostr/keys.rs
+++ b/src-tauri/src/nostr/keys.rs
@@ -206,15 +206,12 @@ pub async fn load_selected_account(npub: &str, state: State<'_, Nostr>) -> Resul
// Add relay to relay pool
let _ = client
- .add_relay_with_opts(relay_url, opts)
+ .add_relay_with_opts(relay_url.clone(), opts)
.await
.unwrap_or_default();
// Connect relay
- client
- .connect_relay(item.0.to_string())
- .await
- .unwrap_or_default();
+ client.connect_relay(relay_url).await.unwrap_or_default();
}
}
}
@@ -251,14 +248,10 @@ pub fn to_npub(hex: &str) -> Result {
Ok(npub.to_bech32().unwrap())
}
-#[tauri::command(async)]
+#[tauri::command]
pub async fn verify_nip05(key: &str, nip05: &str) -> Result {
let public_key = PublicKey::from_str(key).unwrap();
let status = nip05::verify(public_key, nip05, None).await;
- if status.is_ok() {
- Ok(true)
- } else {
- Ok(false)
- }
+ Ok(status.is_ok())
}
diff --git a/src-tauri/src/nostr/metadata.rs b/src-tauri/src/nostr/metadata.rs
index a5102f15..19d588b5 100644
--- a/src-tauri/src/nostr/metadata.rs
+++ b/src-tauri/src/nostr/metadata.rs
@@ -104,8 +104,6 @@ pub async fn friend_to_friend(npub: &str, state: State<'_, Nostr>) -> Result Ok(true),
Err(err) => Err(err.to_string()),
@@ -289,7 +287,7 @@ pub async fn unfollow(id: &str, state: State<'_, Nostr>) -> Result