refactor: tray panel

This commit is contained in:
reya
2024-07-01 13:04:32 +07:00
parent 017a3676a4
commit 843c2d52e7
13 changed files with 580 additions and 643 deletions

View File

@@ -1,18 +1,16 @@
use std::ffi::CString;
use cocoa::appkit::NSWindowCollectionBehavior;
use tauri::Manager;
use tauri::{AppHandle, Manager, WebviewWindow};
use tauri_nspanel::{
block::ConcreteBlock,
cocoa::{
appkit::{NSMainMenuWindowLevel, NSView, NSWindow},
appkit::{NSMainMenuWindowLevel, NSView, NSWindow, NSWindowCollectionBehavior},
base::{id, nil},
foundation::{NSPoint, NSRect},
},
objc::{class, msg_send, runtime::NO, sel, sel_impl},
panel_delegate, ManagerExt, WebviewWindowExt,
};
use tauri_plugin_decorum::WebviewWindowExt as WebviewWindowExt2;
#[allow(non_upper_case_globals)]
const NSWindowStyleMaskNonActivatingPanel: i32 = 1 << 7;
@@ -23,14 +21,17 @@ pub fn swizzle_to_menubar_panel(app_handle: &tauri::AppHandle) {
});
let window = app_handle.get_webview_window("panel").unwrap();
window.make_transparent().unwrap();
let panel = window.to_panel().unwrap();
let handle = app_handle.clone();
panel_delegate.set_listener(Box::new(move |delegate_name: String| {
if delegate_name.as_str() == "window_did_resign_key" {
let _ = handle.emit("menubar_panel_did_resign_key", ());
match delegate_name.as_str() {
"window_did_resign_key" => {
let _ = handle.emit("menubar_panel_did_resign_key", ());
}
_ => (),
}
}));
@@ -47,12 +48,14 @@ pub fn swizzle_to_menubar_panel(app_handle: &tauri::AppHandle) {
panel.set_delegate(panel_delegate);
}
pub fn setup_menubar_panel_listeners(app_handle: &tauri::AppHandle) {
pub fn setup_menubar_panel_listeners(app_handle: &AppHandle) {
fn hide_menubar_panel(app_handle: &tauri::AppHandle) {
if check_menubar_frontmost() {
return;
}
let panel = app_handle.get_webview_panel("panel").unwrap();
panel.order_out(None);
}
@@ -79,19 +82,16 @@ pub fn setup_menubar_panel_listeners(app_handle: &tauri::AppHandle) {
);
}
pub fn update_menubar_appearance(app_handle: &tauri::AppHandle) {
let window = app_handle.get_window("panel").unwrap();
set_corner_radius(&window, 13.0);
}
pub fn set_corner_radius(window: &tauri::Window, radius: f64) {
pub fn set_corner_radius(window: &WebviewWindow, radius: f64) {
let win: id = window.ns_window().unwrap() as _;
unsafe {
let view: id = win.contentView();
view.wantsLayer();
let layer: id = view.layer();
let _: () = msg_send![layer, setCornerRadius: radius];
}
}
@@ -138,7 +138,6 @@ pub fn position_menubar_panel(app_handle: &tauri::AppHandle, padding_top: f64) {
fn register_workspace_listener(name: String, callback: Box<dyn Fn()>) {
let workspace: id = unsafe { msg_send![class!(NSWorkspace), sharedWorkspace] };
let notification_center: id = unsafe { msg_send![workspace, notificationCenter] };
let block = ConcreteBlock::new(move |_notif: id| {
@@ -160,7 +159,6 @@ fn register_workspace_listener(name: String, callback: Box<dyn Fn()>) {
fn app_pid() -> i32 {
let process_info: id = unsafe { msg_send![class!(NSProcessInfo), processInfo] };
let pid: i32 = unsafe { msg_send![process_info, processIdentifier] };
pid

View File

@@ -1,49 +0,0 @@
use std::process::Command;
#[tauri::command]
#[specta::specta]
pub async fn show_in_folder(path: String) {
#[cfg(target_os = "windows")]
{
Command::new("explorer")
.args(["/select,", &path]) // The comma after select is not a typo
.spawn()
.unwrap();
}
#[cfg(target_os = "linux")]
{
use std::fs::metadata;
use std::path::PathBuf;
if path.contains(",") {
// see https://gitlab.freedesktop.org/dbus/dbus/-/issues/76
let new_path = match metadata(&path).unwrap().is_dir() {
true => path,
false => {
let mut path2 = PathBuf::from(path);
path2.pop();
path2.into_os_string().into_string().unwrap()
}
};
Command::new("xdg-open").arg(&new_path).spawn().unwrap();
} else {
Command::new("dbus-send")
.args([
"--session",
"--dest=org.freedesktop.FileManager1",
"--type=method_call",
"/org/freedesktop/FileManager1",
"org.freedesktop.FileManager1.ShowItems",
format!("array:string:file://{path}").as_str(),
"string:\"\"",
])
.spawn()
.unwrap();
}
}
#[cfg(target_os = "macos")]
{
Command::new("open").args(["-R", &path]).spawn().unwrap();
}
}

View File

@@ -1,2 +1,3 @@
pub mod folder;
pub mod fns;
pub mod tray;
pub mod window;

View File

@@ -0,0 +1,65 @@
use std::path::PathBuf;
use tauri::window::{Effect, EffectsBuilder};
use tauri::{
tray::{MouseButtonState, TrayIconEvent},
WebviewWindowBuilder,
};
use tauri::{AppHandle, Manager, WebviewUrl};
use tauri_nspanel::ManagerExt;
use super::fns::{
position_menubar_panel, set_corner_radius, setup_menubar_panel_listeners,
swizzle_to_menubar_panel,
};
pub fn create_tray_panel(account: &str, app: &AppHandle) {
let tray = app.tray_by_id("main").unwrap();
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();
match panel.is_visible() {
true => panel.order_out(None),
false => {
position_menubar_panel(app, 0.0);
panel.show();
}
}
}
}
});
if let Some(window) = app.get_webview_window("panel") {
let _ = window.destroy();
};
let mut url = "/panel/".to_owned();
url.push_str(account);
let window = WebviewWindowBuilder::new(app, "panel", WebviewUrl::App(PathBuf::from(url)))
.title("Panel")
.inner_size(350.0, 500.0)
.fullscreen(false)
.resizable(false)
.visible(false)
.decorations(false)
.transparent(true)
.build()
.unwrap();
let _ = window.set_effects(
EffectsBuilder::new()
.effect(Effect::Popover)
.state(tauri::window::EffectState::FollowsWindowActiveState)
.build(),
);
set_corner_radius(&window, 13.0);
// Convert window to panel
swizzle_to_menubar_panel(app);
setup_menubar_panel_listeners(app);
}

View File

@@ -9,6 +9,9 @@ extern crate cocoa;
#[macro_use]
extern crate objc;
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use specta::Type;
use std::sync::Mutex;
use std::time::Duration;
use std::{
@@ -16,24 +19,10 @@ use std::{
io::{self, BufRead},
str::FromStr,
};
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use specta::Type;
#[cfg(target_os = "macos")]
use tauri::tray::{MouseButtonState, TrayIconEvent};
use tauri::{path::BaseDirectory, Manager};
use tauri_nspanel::ManagerExt;
use tauri_plugin_decorum::WebviewWindowExt;
#[cfg(target_os = "macos")]
use crate::fns::{
position_menubar_panel, setup_menubar_panel_listeners, swizzle_to_menubar_panel,
update_menubar_appearance,
};
pub mod commands;
pub mod fns;
pub mod nostr;
#[derive(Serialize)]
@@ -129,7 +118,6 @@ fn main() {
nostr::event::event_to_bech32,
nostr::event::user_to_bech32,
nostr::event::unlisten,
commands::folder::show_in_folder,
commands::window::create_column,
commands::window::close_column,
commands::window::reposition_column,
@@ -161,37 +149,6 @@ fn main() {
#[cfg(target_os = "macos")]
main_window.set_traffic_lights_inset(8.0, 16.0).unwrap();
// Create panel
#[cfg(target_os = "macos")]
swizzle_to_menubar_panel(app.handle());
#[cfg(target_os = "macos")]
update_menubar_appearance(app.handle());
#[cfg(target_os = "macos")]
setup_menubar_panel_listeners(app.handle());
// Setup tray icon
#[cfg(target_os = "macos")]
let tray = app.tray_by_id("tray_panel").unwrap();
// Handle tray icon event
#[cfg(target_os = "macos")]
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();
match panel.is_visible() {
true => panel.order_out(None),
false => {
position_menubar_panel(app, 0.0);
panel.show();
}
}
}
}
});
// Create data folder if not exist
let home_dir = app.path().home_dir().unwrap();
let _ = fs::create_dir_all(home_dir.join("Lume/"));

View File

@@ -7,6 +7,7 @@ use std::time::Duration;
use tauri::{EventTarget, Manager, State};
use tauri_plugin_notification::NotificationExt;
use crate::commands::tray::create_tray_panel;
use crate::nostr::event::RichEvent;
use crate::nostr::internal::{get_user_settings, init_nip65};
use crate::nostr::utils::parse_event;
@@ -202,6 +203,10 @@ pub async fn load_account(
// Connect to user's relay (NIP-65)
init_nip65(client).await;
// Create tray (macOS)
#[cfg(target_os = "macos")]
create_tray_panel(npub, &handle);
// Get user's contact list
if let Ok(contacts) = client.get_contact_list(None).await {
*state.contact_list.lock().unwrap() = contacts