feat: use native context menu in tray panel

This commit is contained in:
reya 2024-06-18 09:07:58 +07:00
parent d01cf8319d
commit 0061ecea78
5 changed files with 106 additions and 16 deletions

View File

@ -4,10 +4,17 @@ import { type LumeEvent, LumeWindow, NostrQuery, useEvent } from "@lume/system";
import { Kind } from "@lume/types";
import { createFileRoute } from "@tanstack/react-router";
import { getCurrent } from "@tauri-apps/api/window";
import { useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import * as Tabs from "@radix-ui/react-tabs";
import { InfoIcon, RepostIcon, SettingsIcon } from "@lume/icons";
import { decodeZapInvoice, formatCreatedAt } from "@lume/utils";
import { HorizontalDotsIcon, InfoIcon, RepostIcon } from "@lume/icons";
import {
checkForAppUpdates,
decodeZapInvoice,
formatCreatedAt,
} from "@lume/utils";
import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu";
import { open } from "@tauri-apps/plugin-shell";
import { exit } from "@tauri-apps/plugin-process";
interface EmitAccount {
account: string;
@ -66,6 +73,49 @@ function Screen() {
return groups;
}, [events]);
const showContextMenu = useCallback(async (e: React.MouseEvent) => {
e.preventDefault();
const menuItems = await Promise.all([
MenuItem.new({
text: "Open Lume",
action: () => LumeWindow.openMainWindow(),
}),
MenuItem.new({
text: "New Post",
action: () => LumeWindow.openEditor(),
}),
MenuItem.new({
text: "Search",
action: () => LumeWindow.openSearch(),
}),
PredefinedMenuItem.new({ item: "Separator" }),
MenuItem.new({
text: "About Lume",
action: async () => await open("https://lume.nu"),
}),
MenuItem.new({
text: "Check for Updates",
action: async () => await checkForAppUpdates(false),
}),
MenuItem.new({
text: "Settings",
action: () => LumeWindow.openSettings(),
}),
PredefinedMenuItem.new({ item: "Separator" }),
MenuItem.new({
text: "Quit",
action: async () => await exit(0),
}),
]);
const menu = await Menu.new({
items: menuItems,
});
await menu.popup().catch((e) => console.error(e));
}, []);
useEffect(() => {
if (account?.length && account?.startsWith("npub1")) {
NostrQuery.getNotifications()
@ -118,10 +168,10 @@ function Screen() {
</User.Provider>
<button
type="button"
onClick={() => LumeWindow.openSettings()}
onClick={(e) => showContextMenu(e)}
className="inline-flex items-center justify-center rounded-full size-7 bg-black/5 dark:bg-white/5"
>
<SettingsIcon className="size-4" />
<HorizontalDotsIcon className="size-4" />
</button>
</div>
</div>
@ -276,7 +326,7 @@ function TextNote({ event }: { event: LumeEvent }) {
onClick={() => LumeWindow.openEvent(event)}
>
<Note.Provider event={event}>
<Note.Root className="flex flex-col gap-1 p-2 rounded-lg shrink-0 backdrop-blur-md bg-black/10 dark:bg-white/10">
<Note.Root className="flex flex-col p-2 rounded-lg shrink-0 backdrop-blur-md bg-black/10 dark:bg-white/10">
<User.Provider pubkey={event.pubkey}>
<User.Root className="inline-flex items-center gap-2">
<User.Avatar className="rounded-full size-9 shrink-0" />

View File

@ -401,6 +401,9 @@ try {
},
async setBadge(count: number) : Promise<void> {
await TAURI_INVOKE("set_badge", { count });
},
async openMainWindow() : Promise<void> {
await TAURI_INVOKE("open_main_window");
}
}

View File

@ -3,6 +3,16 @@ import type { LumeEvent } from "./event";
import { commands } from "./commands";
export class LumeWindow {
static async openMainWindow() {
const query = await commands.openMainWindow();
if (query.status === "ok") {
return query.data;
} else {
throw new Error(query.error);
}
}
static async openEvent(event: NostrEvent | LumeEvent) {
const eTags = event.tags.filter((tag) => tag[0] === "e" || tag[0] === "q");
const root: string =

View File

@ -1,12 +1,13 @@
use std::path::PathBuf;
#[cfg(target_os = "macos")]
use cocoa::{appkit::NSApp, base::nil, foundation::NSString};
use std::path::PathBuf;
use tauri::utils::config::WindowEffectsConfig;
use tauri::window::Effect;
use tauri::{LogicalPosition, LogicalSize, Manager, WebviewUrl};
#[cfg(target_os = "macos")]
use tauri::TitleBarStyle;
use tauri::utils::config::WindowEffectsConfig;
use tauri::WebviewWindowBuilder;
use tauri::{LogicalPosition, LogicalSize, Manager, WebviewUrl};
use tauri::window::Effect;
use tauri_plugin_decorum::WebviewWindowExt;
#[tauri::command]
@ -184,3 +185,21 @@ pub fn set_badge(count: i32) {
let _: cocoa::base::id = msg_send![dock_tile, setBadgeLabel: label];
}
}
#[tauri::command]
#[specta::specta]
pub fn open_main_window(app: tauri::AppHandle) {
if let Some(window) = app.get_window("main") {
if window.is_visible().unwrap_or_default() {
let _ = window.set_focus();
} else {
let _ = window.show();
let _ = window.set_focus();
};
} else {
let _ = WebviewWindowBuilder::from_config(&app, app.config().app.windows.first().unwrap())
.unwrap()
.build()
.unwrap();
}
}

View File

@ -95,7 +95,8 @@ fn main() {
commands::window::reposition_column,
commands::window::resize_column,
commands::window::open_window,
commands::window::set_badge
commands::window::set_badge,
commands::window::open_main_window
]);
#[cfg(debug_assertions)]
@ -130,8 +131,8 @@ fn main() {
// Handle tray icon event
#[cfg(target_os = "macos")]
tray.on_tray_icon_event(|tray, event| match event {
TrayIconEvent::Click { button_state, .. } => {
tray.on_tray_icon_event(|tray, event| {
if let TrayIconEvent::Click { button_state, .. } = event {
if button_state == MouseButtonState::Up {
let app = tray.app_handle();
let panel = app.get_webview_panel("panel").unwrap();
@ -145,7 +146,6 @@ fn main() {
}
}
}
_ => {}
});
// Create data folder if not exist
@ -170,7 +170,7 @@ fn main() {
let lines = io::BufReader::new(file).lines();
// Add bootstrap relays to relay pool
for line in lines.flatten() {
for line in lines.map_while(Result::ok) {
if let Some((relay, option)) = line.split_once(',') {
match RelayMetadata::from_str(option) {
Ok(meta) => {
@ -216,6 +216,14 @@ fn main() {
.plugin(tauri_plugin_upload::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.invoke_handler(invoke_handler)
.run(ctx)
.build(ctx)
.expect("error while running tauri application")
.run(|app, event| {
if let tauri::RunEvent::ExitRequested { api, .. } = event {
// Hide app icon on macOS
// let _ = app.set_activation_policy(tauri::ActivationPolicy::Accessory);
// Keep API running
api.prevent_exit();
}
});
}