Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ __marimo__/
# otherwise record as gitlinks to commits no clone of this one can resolve.
.claude/

# The macOS app: what pnpm installs, and the schemas tauri-build writes on every build.
# The macOS app: what pnpm installs, and the schemas and the permissions of its own commands
# tauri-build writes on every build.
desktop/node_modules/
desktop/src-tauri/gen/
desktop/src-tauri/permissions/autogenerated/
6 changes: 6 additions & 0 deletions desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ libc = "0.2"
log = "0.4"
# The update's alerts: CFUserNotification, which never holds up a quit as a sheet would.
objc2-core-foundation = { version = "0.3", default-features = false, features = ["std", "CFDate", "CFDictionary", "CFString", "CFURL", "CFUserNotification"] }
# Notifications the page asks for: UNUserNotificationCenter, and a delegate told of a click.
block2 = { version = "0.6", default-features = false, features = ["std"] }
objc2 = { version = "0.6", default-features = false, features = ["std"] }
objc2-foundation = { version = "0.3", default-features = false, features = ["std", "NSError", "NSObject", "NSString"] }
objc2-user-notifications = { version = "0.3", default-features = false, features = ["std", "bitflags", "block2", "UNNotification", "UNNotificationContent", "UNNotificationRequest", "UNNotificationResponse", "UNNotificationSound", "UNNotificationTrigger", "UNUserNotificationCenter"] }
semver = "1"
serde = { version = "1", features = ["derive"] }
# What generate_context! writes the updater's configuration out with.
Expand Down
8 changes: 7 additions & 1 deletion desktop/src-tauri/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/// The app's commands, each granted by a capability: `notify` to `hmz web`'s page, the rest to
/// the app's own.
const COMMANDS: &[&str] = &["status", "retry", "keep", "update_now", "notify"];

fn main() {
tauri_build::build();
let manifest = tauri_build::AppManifest::new().commands(COMMANDS);
tauri_build::try_build(tauri_build::Attributes::new().app_manifest(manifest))
.expect("failed to run the Tauri build script");
}
11 changes: 9 additions & 2 deletions desktop/src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "The app's own page: its own commands need no permission, and it is granted only to drag and zoom the window.",
"description": "The app's own page: granted its own commands, which say and change how hmz web starts, and to drag and zoom the window.",
"windows": ["main"],
"permissions": ["core:window:allow-start-dragging", "core:window:allow-internal-toggle-maximize"]
"permissions": [
"allow-status",
"allow-retry",
"allow-keep",
"allow-update-now",
"core:window:allow-start-dragging",
"core:window:allow-internal-toggle-maximize"
]
}
4 changes: 2 additions & 2 deletions desktop/src-tauri/capabilities/page.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "page",
"description": "hmz web's page, on whichever port of this machine the app started it, the window loading no other: granted only to drag and zoom the window by its top row, and none of the app's commands.",
"description": "hmz web's page, on whichever port of this machine the app started it, the window loading no other: granted only to post a notification, and to drag and zoom the window by its top row.",
"windows": ["main"],
"remote": { "urls": ["http://127.0.0.1:*"] },
"permissions": ["core:window:allow-start-dragging", "core:window:allow-internal-toggle-maximize"]
"permissions": ["allow-notify", "core:window:allow-start-dragging", "core:window:allow-internal-toggle-maximize"]
}
20 changes: 18 additions & 2 deletions desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod child;
mod chrome;
mod install;
mod menu;
mod notify;
mod server;
mod shell_env;
mod update;
Expand Down Expand Up @@ -92,6 +93,8 @@ struct Shell {
page: Mutex<Option<Url>>,
/// An epic's archive opened before then, imported once it is set.
opening: Mutex<Option<PathBuf>>,
/// The address of a notification clicked before then, opened once it is set.
notified: Mutex<Option<String>>,
}

/// Where `hmz web` stands, once it is anything but starting, and other than the page drew last.
Expand All @@ -106,6 +109,13 @@ async fn status(after: Option<Status>, shell: State<'_, Shell>) -> Result<Status
.unwrap_or(Status::Starting))
}

/// Posts a notification from `hmz web`'s page; clicking it brings the window forward, on the
/// page's hash `address` where it is one.
#[tauri::command]
fn notify(title: String, body: String, address: Option<String>) {
notify::post(&title, &body, address.as_deref().unwrap_or_default());
}

/// Starts again where it stopped short: installing `hmz`, then `hmz web`.
#[tauri::command]
fn retry(app: AppHandle, shell: State<'_, Shell>) {
Expand Down Expand Up @@ -205,7 +215,9 @@ fn start(app: AppHandle, how: How) {
*lock(&shell.page) = Some(page.clone());
let opening = lock(&shell.opening).take();
let opening = opening.and_then(|path| importing(&page, &path));
show(app, opening.unwrap_or(page));
let notified = lock(&shell.notified).take();
let notified = notified.and_then(|address| notify::target(&page, &address));
show(app, opening.or(notified).unwrap_or(page));
});
// Told once `hmz web` stops on its own; nothing where the app stopped it.
if let Some(said) = server.exited() {
Expand Down Expand Up @@ -454,12 +466,16 @@ pub fn run() {
downloads: Mutex::default(),
page: Mutex::default(),
opening: Mutex::default(),
notified: Mutex::default(),
})
.menu(menu::build)
.on_menu_event(menu::handle)
.invoke_handler(tauri::generate_handler![status, retry, keep, update_now])
.invoke_handler(tauri::generate_handler![
status, retry, keep, update_now, notify
])
.setup(|app| {
window(app.handle())?;
notify::init(app.handle());
start(app.handle().clone(), How::Usual);
update::init(app.handle())?;
Ok(())
Expand Down
Loading
Loading