From b60d4db0df895fe1cd8d554ca5da0711adc2d545 Mon Sep 17 00:00:00 2001 From: reya <123083837+reyamir@users.noreply.github.com> Date: Wed, 15 May 2024 10:14:21 +0700 Subject: [PATCH] feat: improve multi-account switching --- apps/desktop2/src/components/balance.tsx | 66 ++-- apps/desktop2/src/components/col.tsx | 160 ---------- apps/desktop2/src/components/column.tsx | 147 +++++++++ apps/desktop2/src/components/conversation.tsx | 76 ++--- apps/desktop2/src/components/note/index.ts | 24 +- apps/desktop2/src/components/notification.tsx | 50 +-- apps/desktop2/src/components/quote.tsx | 76 ++--- apps/desktop2/src/components/repost.tsx | 144 ++++----- apps/desktop2/src/components/text.tsx | 54 ++-- apps/desktop2/src/routes/$account.home.tsx | 289 ++++++++--------- apps/desktop2/src/routes/$account.tsx | 296 +++++++++--------- src-tauri/gen/schemas/capabilities.json | 2 +- src-tauri/src/nostr/metadata.rs | 42 +-- 13 files changed, 706 insertions(+), 720 deletions(-) delete mode 100644 apps/desktop2/src/components/col.tsx create mode 100644 apps/desktop2/src/components/column.tsx diff --git a/apps/desktop2/src/components/balance.tsx b/apps/desktop2/src/components/balance.tsx index efb846d9..e4cb027e 100644 --- a/apps/desktop2/src/components/balance.tsx +++ b/apps/desktop2/src/components/balance.tsx @@ -1,42 +1,42 @@ -import { User } from "./user"; +import { User } from "@/components/user"; import { getBitcoinDisplayValues } from "@lume/utils"; 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/col.tsx b/apps/desktop2/src/components/col.tsx deleted file mode 100644 index c6e06b8a..00000000 --- a/apps/desktop2/src/components/col.tsx +++ /dev/null @@ -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(null); - const [webview, setWebview] = useState(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 ( -
-
- {column.label !== "open" ? ( -
- ) : null} -
-
-
- ); -} - -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 ( -
-
-
-
-
setTitle(e.currentTarget.textContent)} - className="text-sm font-medium focus:outline-none" - > - {name} -
- {isChanged ? ( - - ) : null} -
-
- -
- ); -} diff --git a/apps/desktop2/src/components/column.tsx b/apps/desktop2/src/components/column.tsx new file mode 100644 index 00000000..bc7eef47 --- /dev/null +++ b/apps/desktop2/src/components/column.tsx @@ -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(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 ( +
+
+ {column.label !== "open" ? ( +
+ ) : null} +
+
+
+ ); +} + +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 ( +
+
+
+
+
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 d8fbadc6..879cd091 100644 --- a/apps/desktop2/src/components/conversation.tsx +++ b/apps/desktop2/src/components/conversation.tsx @@ -1,48 +1,48 @@ import { ThreadIcon } from "@lume/icons"; import type { Event } from "@lume/types"; -import { Note } from "./note"; +import { Note } from "@/components/note"; 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 -
-
-
- {thread?.reply ? : null} -
-
- -
- -
-
-
- -
- - - ); + return ( + + +
+ {thread?.root ? : null} +
+
+ + Thread +
+
+
+ {thread?.reply ? : null} +
+
+ +
+ +
+
+
+ +
+ + + ); } diff --git a/apps/desktop2/src/components/note/index.ts b/apps/desktop2/src/components/note/index.ts index c52887b0..0112a7e4 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 8b6964d2..7daf6d6b 100644 --- a/apps/desktop2/src/components/notification.tsx +++ b/apps/desktop2/src/components/notification.tsx @@ -1,32 +1,32 @@ import type { Event } from "@lume/types"; -import { Note } from "./note"; +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 06d738d6..d4a2913e 100644 --- a/apps/desktop2/src/components/quote.tsx +++ b/apps/desktop2/src/components/quote.tsx @@ -1,47 +1,47 @@ import { QuoteIcon } from "@lume/icons"; import type { Event } from "@lume/types"; -import { Note } from "./note"; +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 ( - - -
- -
-
- - Quote -
-
-
-
-
- -
- -
-
-
- -
- - - ); + return ( + + +
+ +
+
+ + Quote +
+
+
+
+
+ +
+ +
+
+
+ +
+ + + ); } diff --git a/apps/desktop2/src/components/repost.tsx b/apps/desktop2/src/components/repost.tsx index 0ffb9b00..43ee5302 100644 --- a/apps/desktop2/src/components/repost.tsx +++ b/apps/desktop2/src/components/repost.tsx @@ -1,85 +1,85 @@ import type { Event } from "@lume/types"; import { Spinner } from "@lume/ui"; -import { Note } from "./note"; -import { User } from "./user"; +import { Note } from "@/components/note"; +import { User } from "@/components/user"; import { cn } from "@lume/utils"; 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 7ec993d4..8b91b639 100644 --- a/apps/desktop2/src/components/text.tsx +++ b/apps/desktop2/src/components/text.tsx @@ -1,34 +1,34 @@ import type { Event } from "@lume/types"; import { cn } from "@lume/utils"; -import { Note } from "./note"; +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 c69037e0..fea4fa0d 100644 --- a/apps/desktop2/src/routes/$account.home.tsx +++ b/apps/desktop2/src/routes/$account.home.tsx @@ -1,4 +1,4 @@ -import { Col } from "@/components/col"; +import { Column } from "@/components/column"; import { Toolbar } from "@/components/toolbar"; import { ArrowLeftIcon, ArrowRightIcon } from "@lume/icons"; import type { EventColumns, LumeColumn } from "@lume/types"; @@ -13,170 +13,175 @@ import { useDebouncedCallback } from "use-debounce"; import { VList, type VListHandle } from "virtua"; export const Route = createFileRoute("/$account/home")({ - beforeLoad: async ({ context }) => { - try { - const ark = context.ark; - const resourcePath = await resolveResource( - "resources/system_columns.json", - ); - const systemColumns: LumeColumn[] = JSON.parse( - await readTextFile(resourcePath), - ); - const userColumns = await ark.get_columns(); + 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 { - storedColumns: !userColumns.length ? systemColumns : userColumns, - }; - } catch (e) { - console.error(String(e)); - } - }, - component: Screen, + return systemColumns; + } + } catch (e) { + console.error(String(e)); + } + }, + component: Screen, }); function Screen() { - const vlistRef = useRef(null); + const userSavedColumns = Route.useLoaderData(); + const vlistRef = useRef(null); - const { account } = Route.useParams(); - const { ark, storedColumns } = Route.useRouteContext(); + const { account } = Route.useParams(); + const { ark } = Route.useRouteContext(); - const [selectedIndex, setSelectedIndex] = useState(-1); - const [columns, setColumns] = useState(storedColumns); - 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(() => { - // save state - ark.set_columns(columns); - }, [columns]); + useEffect(() => { + setColumns(userSavedColumns); + }, [userSavedColumns]); - 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(() => { + // save state + ark.set_columns(columns); + }, [columns]); - const unlistenWindowResize = getCurrent().listen("tauri://resize", () => { - startResize(); - }); + 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); + }); - return () => { - unlistenColEvent.then((f) => f()); - unlistenWindowResize.then((f) => f()); - }; - }, []); + const unlistenWindowResize = getCurrent().listen("tauri://resize", () => { + startResize(); + }); - return ( -
- setIsScroll(true)} - onScrollEnd={() => setIsScroll(false)} - className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none" - > - {columns.map((column) => ( - - ))} - - -
- - -
-
-
- ); + 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) => ( + + ))} + + +
+ + +
+
+
+ ); } diff --git a/apps/desktop2/src/routes/$account.tsx b/apps/desktop2/src/routes/$account.tsx index 04caf33e..4da85563 100644 --- a/apps/desktop2/src/routes/$account.tsx +++ b/apps/desktop2/src/routes/$account.tsx @@ -2,177 +2,183 @@ 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"; import { getCurrent } from "@tauri-apps/api/window"; 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; + const changeAccount = async (npub: string) => { + if (npub === account) { + return await ark.open_profile(account); + } - 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 } }); - } - }; + 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/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json index fb7cfe46..837ce7b6 100644 --- a/src-tauri/gen/schemas/capabilities.json +++ b/src-tauri/gen/schemas/capabilities.json @@ -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"]}} \ No newline at end of file +{"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"]}} \ No newline at end of file diff --git a/src-tauri/src/nostr/metadata.rs b/src-tauri/src/nostr/metadata.rs index fa8c339b..a5102f15 100644 --- a/src-tauri/src/nostr/metadata.rs +++ b/src-tauri/src/nostr/metadata.rs @@ -289,7 +289,7 @@ pub async fn unfollow(id: &str, state: State<'_, Nostr>) -> Result { - println!("set nstore: {}", event_id); - Ok(event_id) - } + Ok(event_id) => Ok(event_id), Err(err) => Err(err.to_string()), } } @@ -322,38 +319,29 @@ pub async fn get_nstore(key: &str, state: State<'_, Nostr>) -> Result { if let Some(event) = events.first() { - println!("get nstore key: {} - received: {}", key, event.id); - let content = event.content(); - - match signer.nip44_decrypt(author, content).await { + match signer.nip44_decrypt(public_key, content).await { Ok(decrypted) => Ok(decrypted), Err(_) => Err(event.content.to_string()), } } else { - println!("get nstore key: {}", key); Err("Value not found".into()) } - } else { - Err("Query nstore event failed".into()) } - } else { - Err("Something is wrong".into()) + Err(err) => Err(err.to_string()), } } else { Err("Signer is required".into())