feat: save state when close app
This commit is contained in:
@@ -577,31 +577,24 @@ pub async fn get_notifications(state: State<'_, Nostr>) -> Result<Vec<String>, S
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub async fn get_settings(state: State<'_, Nostr>) -> Result<Settings, ()> {
|
pub async fn get_user_settings(state: State<'_, Nostr>) -> Result<Settings, ()> {
|
||||||
Ok(state.settings.lock().await.clone())
|
Ok(state.settings.lock().await.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub async fn set_settings(
|
pub async fn set_user_settings(
|
||||||
settings: &str,
|
settings: String,
|
||||||
state: State<'_, Nostr>,
|
state: State<'_, Nostr>,
|
||||||
handle: tauri::AppHandle,
|
handle: tauri::AppHandle,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let client = &state.client;
|
let client = &state.client;
|
||||||
let ident = "lume_v4:settings";
|
let tags = vec![Tag::identifier("lume_user_setting")];
|
||||||
let signer = client.signer().await.map_err(|e| e.to_string())?;
|
let builder = EventBuilder::new(Kind::ApplicationSpecificData, &settings, tags);
|
||||||
let public_key = signer.public_key().await.map_err(|e| e.to_string())?;
|
|
||||||
let encrypted = signer
|
|
||||||
.nip44_encrypt(&public_key, settings)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
let tag = Tag::identifier(ident);
|
|
||||||
let builder = EventBuilder::new(Kind::ApplicationSpecificData, encrypted, vec![tag]);
|
|
||||||
|
|
||||||
match client.send_event_builder(builder).await {
|
match client.send_event_builder(builder).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let parsed: Settings = serde_json::from_str(settings).map_err(|e| e.to_string())?;
|
let parsed: Settings = serde_json::from_str(&settings).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
state.settings.lock().await.clone_from(&parsed);
|
state.settings.lock().await.clone_from(&parsed);
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ fn main() {
|
|||||||
zap_event,
|
zap_event,
|
||||||
copy_friend,
|
copy_friend,
|
||||||
get_notifications,
|
get_notifications,
|
||||||
get_settings,
|
get_user_settings,
|
||||||
set_settings,
|
set_user_settings,
|
||||||
verify_nip05,
|
verify_nip05,
|
||||||
is_trusted_user,
|
is_trusted_user,
|
||||||
get_event_meta,
|
get_event_meta,
|
||||||
@@ -523,6 +523,7 @@ fn main() {
|
|||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_upload::init())
|
.plugin(tauri_plugin_upload::init())
|
||||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
|
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,17 +270,17 @@ async getNotifications() : Promise<Result<string[], string>> {
|
|||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getSettings() : Promise<Result<Settings, null>> {
|
async getUserSettings() : Promise<Result<Settings, null>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("get_settings") };
|
return { status: "ok", data: await TAURI_INVOKE("get_user_settings") };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if(e instanceof Error) throw e;
|
if(e instanceof Error) throw e;
|
||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async setSettings(settings: string) : Promise<Result<null, string>> {
|
async setUserSettings(settings: string) : Promise<Result<null, string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("set_settings", { settings }) };
|
return { status: "ok", data: await TAURI_INVOKE("set_user_settings", { settings }) };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if(e instanceof Error) throw e;
|
if(e instanceof Error) throw e;
|
||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export const Route = createLazyFileRoute("/$account/_app/home")({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function Screen() {
|
function Screen() {
|
||||||
|
const params = Route.useParams();
|
||||||
const columns = useStore(appColumns, (state) => state);
|
const columns = useStore(appColumns, (state) => state);
|
||||||
|
|
||||||
const [emblaRef, emblaApi] = useEmblaCarousel({
|
const [emblaRef, emblaApi] = useEmblaCarousel({
|
||||||
@@ -159,7 +160,21 @@ function Screen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!columns.length) {
|
if (!columns.length) {
|
||||||
getSystemColumns();
|
const prevColumns = window.localStorage.getItem(
|
||||||
|
`${params.account}_columns`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!prevColumns) {
|
||||||
|
getSystemColumns();
|
||||||
|
} else {
|
||||||
|
const parsed: LumeColumn[] = JSON.parse(prevColumns);
|
||||||
|
appColumns.setState(() => parsed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.localStorage.setItem(
|
||||||
|
`${params.account}_columns`,
|
||||||
|
JSON.stringify(columns),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [columns.length]);
|
}, [columns.length]);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function Screen() {
|
|||||||
const updateSettings = () => {
|
const updateSettings = () => {
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
const newSettings = JSON.stringify(appSettings.state);
|
const newSettings = JSON.stringify(appSettings.state);
|
||||||
const res = await commands.setSettings(newSettings);
|
const res = await commands.setUserSettings(newSettings);
|
||||||
|
|
||||||
if (res.status === "error") {
|
if (res.status === "error") {
|
||||||
await message(res.error, { kind: "error" });
|
await message(res.error, { kind: "error" });
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { createFileRoute } from "@tanstack/react-router";
|
|||||||
|
|
||||||
export const Route = createFileRoute("/$account/_settings/general")({
|
export const Route = createFileRoute("/$account/_settings/general")({
|
||||||
beforeLoad: async () => {
|
beforeLoad: async () => {
|
||||||
const res = await commands.getSettings();
|
const res = await commands.getUserSettings();
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
appSettings.setState((state) => {
|
appSettings.setState((state) => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const Route = createFileRoute("/columns/_layout")({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
beforeLoad: async () => {
|
beforeLoad: async () => {
|
||||||
const res = await commands.getSettings();
|
const res = await commands.getUserSettings();
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
appSettings.setState((state) => {
|
appSettings.setState((state) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { commands } from "@/commands.gen";
|
import { commands } from "@/commands.gen";
|
||||||
import { toLumeEvents } from "@/commons";
|
import { cn, toLumeEvents } from "@/commons";
|
||||||
import { Spinner, User } from "@/components";
|
import { Spinner, User } from "@/components";
|
||||||
import { LumeWindow } from "@/system";
|
import { LumeWindow } from "@/system";
|
||||||
import type { LumeColumn, NostrEvent } from "@/types";
|
import type { LumeColumn, NostrEvent } from "@/types";
|
||||||
@@ -24,8 +24,8 @@ function Screen() {
|
|||||||
className="overflow-hidden size-full"
|
className="overflow-hidden size-full"
|
||||||
>
|
>
|
||||||
<ScrollArea.Viewport className="relative h-full px-3 pb-3">
|
<ScrollArea.Viewport className="relative h-full px-3 pb-3">
|
||||||
<MyGroups />
|
<Groups />
|
||||||
<MyInterests />
|
<Interests />
|
||||||
<Core />
|
<Core />
|
||||||
</ScrollArea.Viewport>
|
</ScrollArea.Viewport>
|
||||||
<ScrollArea.Scrollbar
|
<ScrollArea.Scrollbar
|
||||||
@@ -95,10 +95,10 @@ function Core() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MyGroups() {
|
function Groups() {
|
||||||
const { account } = Route.useSearch();
|
const { account } = Route.useSearch();
|
||||||
const { isLoading, data, refetch } = useQuery({
|
const { isLoading, data, refetch, isRefetching } = useQuery({
|
||||||
queryKey: ["mygroups", account],
|
queryKey: ["groups", account],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await commands.getAllGroups();
|
const res = await commands.getAllGroups();
|
||||||
|
|
||||||
@@ -167,12 +167,15 @@ function MyGroups() {
|
|||||||
return (
|
return (
|
||||||
<div className="mb-12 flex flex-col gap-3">
|
<div className="mb-12 flex flex-col gap-3">
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="flex items-center justify-between px-2">
|
||||||
<h3 className="font-semibold">My groups</h3>
|
<h3 className="font-semibold">Groups</h3>
|
||||||
<div className="inline-flex items-center justify-center gap-2">
|
<div className="inline-flex items-center justify-center gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => refetch()}
|
onClick={() => refetch()}
|
||||||
className="size-7 inline-flex items-center justify-center rounded-full"
|
className={cn(
|
||||||
|
"size-7 inline-flex items-center justify-center rounded-full",
|
||||||
|
isRefetching ? "animate-spin" : "",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ArrowClockwise className="size-4" />
|
<ArrowClockwise className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
@@ -206,10 +209,10 @@ function MyGroups() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MyInterests() {
|
function Interests() {
|
||||||
const { account } = Route.useSearch();
|
const { account } = Route.useSearch();
|
||||||
const { isLoading, data, refetch } = useQuery({
|
const { isLoading, data, refetch, isRefetching } = useQuery({
|
||||||
queryKey: ["myinterests", account],
|
queryKey: ["interests", account],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await commands.getAllInterests();
|
const res = await commands.getAllInterests();
|
||||||
|
|
||||||
@@ -275,12 +278,15 @@ function MyInterests() {
|
|||||||
return (
|
return (
|
||||||
<div className="mb-12 flex flex-col gap-3">
|
<div className="mb-12 flex flex-col gap-3">
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="flex items-center justify-between px-2">
|
||||||
<h3 className="font-semibold">My interests</h3>
|
<h3 className="font-semibold">Interests</h3>
|
||||||
<div className="inline-flex items-center justify-center gap-2">
|
<div className="inline-flex items-center justify-center gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => refetch()}
|
onClick={() => refetch()}
|
||||||
className="size-7 inline-flex items-center justify-center rounded-full"
|
className={cn(
|
||||||
|
"size-7 inline-flex items-center justify-center rounded-full",
|
||||||
|
isRefetching ? "animate-spin" : "",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ArrowClockwise className="size-4" />
|
<ArrowClockwise className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ function Screen() {
|
|||||||
const res = await commands.login(value, password);
|
const res = await commands.login(value, password);
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
const settings = await commands.getSettings();
|
const settings = await commands.getUserSettings();
|
||||||
|
|
||||||
if (settings.status === "ok") {
|
if (settings.status === "ok") {
|
||||||
appSettings.setState(() => settings.data);
|
appSettings.setState(() => settings.data);
|
||||||
|
|||||||
Reference in New Issue
Block a user