Compare commits
11 Commits
9407f54677
...
e507fbc292
Author | SHA1 | Date | |
---|---|---|---|
e507fbc292 | |||
b2a70e359b | |||
301944b769 | |||
0940134d9e | |||
af24a8f6d4 | |||
446e8bb2ee | |||
6211945e3d | |||
9f215bb3d1 | |||
1a84e0d6c5 | |||
bd9d8b955a | |||
58f60bf053 |
@ -1,38 +0,0 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
You are an expert AI programming assistant focused on producing clean, readable TypeScript and Rust code for modern cross-platform desktop apps.
|
||||
|
||||
Use these rules for any code under /frontend folder.
|
||||
|
||||
You always use the latest versions of Tauri, Rust, SolidJS, and you're fluent in their latest features, best practices, and patterns.
|
||||
|
||||
You give accurate, thoughtful answers and think like a real dev—step-by-step.
|
||||
|
||||
Follow the user’s specs exactly. If a specs folder exists, check it before coding.
|
||||
|
||||
Begin with a detailed pseudo-code plan and confirm it with the user before writing actual code.
|
||||
|
||||
Write correct, complete, idiomatic, secure, performant, and bug-free code.
|
||||
|
||||
Prioritize readability unless performance is explicitly required.
|
||||
|
||||
Fully implement all requested features—no TODOs, stubs, or placeholders.
|
||||
|
||||
Use TypeScript's type system thoroughly for clarity and safety.
|
||||
|
||||
Style with TailwindCSS using utility-first principles.
|
||||
|
||||
Use Kobalte components effectively, building with Solid’s reactive model in mind.
|
||||
|
||||
Offload performance-heavy logic to Rust and ensure smooth integration with Tauri.
|
||||
|
||||
Guarantee tight coordination between SolidJS, Tauri, and Rust for a polished desktop UX.
|
||||
|
||||
When needed, provide bash scripts to generate config files or folder structures.
|
||||
|
||||
Be concise—cut the fluff.
|
||||
|
||||
If there's no solid answer, say so. If you're unsure, don't guess—own it.
|
53
frontend/.idea/workspace.xml
generated
53
frontend/.idea/workspace.xml
generated
@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="NONE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="4ea94c05-c21c-40f9-ad16-43233a3011ee" name="Changes" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ClangdSettings">
|
||||
<option name="formatViaClangd" value="false" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 5
|
||||
}</component>
|
||||
<component name="ProjectId" id="2w23zazSC8gW9XDwUxbl8Fam8DV" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||
"cf.first.check.clang-format": "false",
|
||||
"cidr.known.project.marker": "true",
|
||||
"com.google.services.firebase.aqiPopupShown": "true",
|
||||
"git-widget-placeholder": "feat/android-version",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "/home/johnc/Code/haystack-app/frontend",
|
||||
"settings.editor.selected.configurable": "AndroidSdkUpdater"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="4ea94c05-c21c-40f9-ad16-43233a3011ee" name="Changes" comment="" />
|
||||
<created>1745226104717</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1745226104717</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
</project>
|
Binary file not shown.
3
frontend/src-tauri/Cargo.lock
generated
3
frontend/src-tauri/Cargo.lock
generated
@ -7,7 +7,6 @@ name = "Haystack"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"chrono",
|
||||
"cocoa",
|
||||
"notify",
|
||||
"serde",
|
||||
@ -539,10 +538,8 @@ checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
|
@ -26,9 +26,6 @@ base64 = "0.21.7"
|
||||
tokio = { version = "1.36.0", features = ["full"] }
|
||||
tauri-plugin-store = "2.0.0-beta.12"
|
||||
tauri-plugin-http = "2.0.0-beta.12"
|
||||
chrono = "0.4"
|
||||
tauri-plugin-log = "2"
|
||||
tauri-plugin-sharetarget = "0.1.6"
|
||||
tauri-plugin-fs = "2"
|
||||
tauri-plugin-dialog = "2.2.1"
|
||||
tauri-plugin-opener = "2.2.6"
|
||||
|
@ -1,8 +1,6 @@
|
||||
mod commands;
|
||||
pub mod screenshot;
|
||||
pub mod shortcut;
|
||||
mod state;
|
||||
pub mod utils;
|
||||
mod utils;
|
||||
mod window;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
@ -19,18 +17,14 @@ pub fn desktop() {
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_store::Builder::new().build())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_sharetarget::init())
|
||||
// .plugin(tauri_plugin_dialog::init())
|
||||
// .plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.manage(watcher_state)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::handle_selected_folder,
|
||||
shortcut::change_shortcut,
|
||||
shortcut::unregister_shortcut,
|
||||
shortcut::get_current_shortcut,
|
||||
shortcut::change_screenshot_shortcut,
|
||||
shortcut::unregister_screenshot_shortcut,
|
||||
shortcut::get_current_screenshot_shortcut,
|
||||
])
|
||||
.setup(|app| {
|
||||
setup_window(app)?;
|
||||
|
@ -1,46 +0,0 @@
|
||||
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use tauri::{AppHandle, Emitter, Runtime};
|
||||
|
||||
/// Takes a screenshot of a selected area and returns the image data as base64
|
||||
pub fn take_area_screenshot<R: Runtime>(app: &AppHandle<R>) -> Result<String, String> {
|
||||
// Create a temporary file path
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
|
||||
let temp_file = temp_dir.join(format!("haystack_screenshot_{}.png", timestamp));
|
||||
|
||||
// Use screencapture command with -i flag for interactive selection
|
||||
let output = Command::new("screencapture")
|
||||
.arg("-i") // interactive selection
|
||||
.arg("-x") // don't play sound
|
||||
.arg("-o") // don't show cursor
|
||||
.arg("-r") // don't add shadow
|
||||
.arg(temp_file.to_str().unwrap())
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to execute screencapture: {}", e))?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"screencapture failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
));
|
||||
}
|
||||
|
||||
// Read the captured image
|
||||
let contents =
|
||||
fs::read(&temp_file).map_err(|e| format!("Failed to read screenshot file: {}", e))?;
|
||||
|
||||
// Convert to base64
|
||||
let base64_string = BASE64.encode(&contents);
|
||||
|
||||
// Clean up the temporary file
|
||||
if let Err(e) = fs::remove_file(&temp_file) {
|
||||
println!("Warning: Failed to remove temporary screenshot file: {}", e);
|
||||
}
|
||||
|
||||
app.emit("png-processed", base64_string.clone())
|
||||
.map_err(|e| format!("Failed to emit event: {}", e))?;
|
||||
|
||||
Ok(base64_string)
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
use crate::screenshot::take_area_screenshot;
|
||||
use tauri::App;
|
||||
use tauri::AppHandle;
|
||||
use tauri::Emitter;
|
||||
@ -10,36 +9,28 @@ use tauri_plugin_global_shortcut::ShortcutState;
|
||||
use tauri_plugin_store::JsonValue;
|
||||
use tauri_plugin_store::StoreExt;
|
||||
|
||||
/// Constants for Tauri store configuration
|
||||
const HAYSTACK_TAURI_STORE: &str = "haystack_tauri_store"; // Name of the persistent store
|
||||
const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut"; // Key for storing the toggle window shortcut
|
||||
const HAYSTACK_SCREENSHOT_SHORTCUT: &str = "haystack_screenshot_shortcut"; // Key for storing the screenshot shortcut
|
||||
/// Name of the Tauri storage
|
||||
const HAYSTACK_TAURI_STORE: &str = "haystack_tauri_store";
|
||||
|
||||
/// Platform-specific default shortcuts
|
||||
/// Key for storing global shortcuts
|
||||
const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut";
|
||||
|
||||
/// Default shortcut for macOS
|
||||
#[cfg(target_os = "macos")]
|
||||
const DEFAULT_SHORTCUT: &str = "command+shift+k"; // macOS uses Command key
|
||||
#[cfg(target_os = "macos")]
|
||||
const DEFAULT_SCREENSHOT_SHORTCUT: &str = "command+shift+p"; // macOS screenshot shortcut
|
||||
const DEFAULT_SHORTCUT: &str = "command+shift+k";
|
||||
|
||||
/// Default shortcut for Windows and Linux
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
const DEFAULT_SHORTCUT: &str = "ctrl+shift+k"; // Windows/Linux use Ctrl key
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
const DEFAULT_SCREENSHOT_SHORTCUT: &str = "ctrl+shift+p"; // Windows/Linux screenshot shortcut
|
||||
const DEFAULT_SHORTCUT: &str = "ctrl+shift+k";
|
||||
|
||||
/// Initializes the global shortcut during application startup.
|
||||
/// This function:
|
||||
/// 1. Checks if a shortcut is already stored
|
||||
/// 2. Uses the stored shortcut if it exists
|
||||
/// 3. Falls back to the platform-specific default if no shortcut is stored
|
||||
/// 4. Registers the shortcut with the system
|
||||
/// Set shortcut during application startup
|
||||
pub fn enable_shortcut(app: &App) {
|
||||
// Get or create the persistent store
|
||||
let store = app
|
||||
.store(HAYSTACK_TAURI_STORE)
|
||||
.expect("Creating the store should not fail");
|
||||
|
||||
// Initialize toggle window shortcut
|
||||
let toggle_shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) {
|
||||
// Use stored shortcut if it exists
|
||||
if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) {
|
||||
let stored_shortcut_str = match stored_shortcut {
|
||||
JsonValue::String(str) => str,
|
||||
unexpected_type => panic!(
|
||||
@ -47,72 +38,45 @@ pub fn enable_shortcut(app: &App) {
|
||||
unexpected_type
|
||||
),
|
||||
};
|
||||
stored_shortcut_str
|
||||
let stored_shortcut = stored_shortcut_str
|
||||
.parse::<Shortcut>()
|
||||
.expect("Stored shortcut string should be valid")
|
||||
.expect("Stored shortcut string should be valid");
|
||||
_register_shortcut_upon_start(app, stored_shortcut); // Register stored shortcut
|
||||
} else {
|
||||
// Use default shortcut if none is stored
|
||||
store.set(
|
||||
HAYSTACK_GLOBAL_SHORTCUT,
|
||||
JsonValue::String(DEFAULT_SHORTCUT.to_string()),
|
||||
);
|
||||
DEFAULT_SHORTCUT
|
||||
let default_shortcut = DEFAULT_SHORTCUT
|
||||
.parse::<Shortcut>()
|
||||
.expect("Default shortcut should be valid")
|
||||
};
|
||||
|
||||
// Initialize screenshot shortcut
|
||||
let screenshot_shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_SCREENSHOT_SHORTCUT)
|
||||
{
|
||||
let stored_shortcut_str = match stored_shortcut {
|
||||
JsonValue::String(str) => str,
|
||||
unexpected_type => panic!(
|
||||
"Haystack shortcuts should be stored as strings, found type: {} ",
|
||||
unexpected_type
|
||||
),
|
||||
};
|
||||
stored_shortcut_str
|
||||
.parse::<Shortcut>()
|
||||
.expect("Stored shortcut string should be valid")
|
||||
} else {
|
||||
store.set(
|
||||
HAYSTACK_SCREENSHOT_SHORTCUT,
|
||||
JsonValue::String(DEFAULT_SCREENSHOT_SHORTCUT.to_string()),
|
||||
);
|
||||
DEFAULT_SCREENSHOT_SHORTCUT
|
||||
.parse::<Shortcut>()
|
||||
.expect("Default screenshot shortcut should be valid")
|
||||
};
|
||||
|
||||
// Register both shortcuts
|
||||
register_shortcut_upon_start(app, toggle_shortcut, screenshot_shortcut);
|
||||
.expect("Default shortcut should be valid");
|
||||
_register_shortcut_upon_start(app, default_shortcut); // Register default shortcut
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the currently configured shortcut as a string.
|
||||
/// This is exposed as a Tauri command for the frontend to query.
|
||||
/// Get the current stored shortcut as a string
|
||||
#[tauri::command]
|
||||
pub fn get_current_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
|
||||
Ok(get_shortcut_from_store(&app))
|
||||
let shortcut = _get_shortcut(&app);
|
||||
Ok(shortcut)
|
||||
}
|
||||
|
||||
/// Unregisters the current global shortcut from the system.
|
||||
/// This is exposed as a Tauri command for the frontend to trigger.
|
||||
/// Unregister the current shortcut in Tauri
|
||||
#[tauri::command]
|
||||
pub fn unregister_shortcut<R: Runtime>(app: AppHandle<R>) {
|
||||
let shortcut_str = get_shortcut_from_store(&app);
|
||||
let shortcut_str = _get_shortcut(&app);
|
||||
let shortcut = shortcut_str
|
||||
.parse::<Shortcut>()
|
||||
.expect("Stored shortcut string should be valid");
|
||||
|
||||
// Unregister the shortcut
|
||||
app.global_shortcut()
|
||||
.unregister(shortcut)
|
||||
.expect("Failed to unregister shortcut")
|
||||
}
|
||||
|
||||
/// Changes the global shortcut to a new key combination.
|
||||
/// This function:
|
||||
/// 1. Validates the new shortcut
|
||||
/// 2. Stores it in the persistent store
|
||||
/// 3. Registers it with the system
|
||||
/// Change the global shortcut
|
||||
#[tauri::command]
|
||||
pub fn change_shortcut<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
@ -132,40 +96,28 @@ pub fn change_shortcut<R: Runtime>(
|
||||
store.set(HAYSTACK_GLOBAL_SHORTCUT, JsonValue::String(key));
|
||||
|
||||
// Register the new shortcut
|
||||
register_shortcut(&app, shortcut);
|
||||
_register_shortcut(&app, shortcut);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handles the window visibility toggle logic when the shortcut is pressed.
|
||||
/// This function:
|
||||
/// 1. Hides the window if it's visible
|
||||
/// 2. Shows and focuses the window if it's hidden
|
||||
/// 3. Emits a 'focus-search' event when showing the window
|
||||
fn handle_window_visibility<R: Runtime>(app: &AppHandle<R>, window: &tauri::WebviewWindow<R>) {
|
||||
if window.is_visible().unwrap() {
|
||||
window.hide().unwrap();
|
||||
} else {
|
||||
window.show().unwrap();
|
||||
window.set_focus().unwrap();
|
||||
app.emit("focus-search", ()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a new shortcut with the system.
|
||||
/// This is used when changing shortcuts during runtime.
|
||||
/// The function:
|
||||
/// 1. Gets the main window
|
||||
/// 2. Sets up the shortcut handler
|
||||
/// 3. Registers the shortcut with the system
|
||||
fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
|
||||
/// Helper function to register a shortcut, primarily for updating shortcuts
|
||||
fn _register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
|
||||
let main_window = app.get_webview_window("main").unwrap();
|
||||
|
||||
// Register global shortcut and define its behavior
|
||||
app.global_shortcut()
|
||||
.on_shortcut(shortcut, move |app, scut, event| {
|
||||
if scut == &shortcut {
|
||||
if let ShortcutState::Pressed = event.state() {
|
||||
handle_window_visibility(app, &main_window);
|
||||
// Toggle window visibility
|
||||
if main_window.is_visible().unwrap() {
|
||||
main_window.hide().unwrap(); // Hide window
|
||||
} else {
|
||||
main_window.show().unwrap(); // Show window
|
||||
main_window.set_focus().unwrap(); // Focus window
|
||||
// Emit focus-search event
|
||||
app.emit("focus-search", ()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -173,49 +125,39 @@ fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Registers a shortcut during application startup.
|
||||
/// This is similar to register_shortcut but handles the initial plugin setup.
|
||||
/// The function:
|
||||
/// 1. Gets the main window
|
||||
/// 2. Sets up the global shortcut plugin
|
||||
/// 3. Registers the shortcut with the system
|
||||
fn register_shortcut_upon_start(
|
||||
app: &App,
|
||||
toggle_shortcut: Shortcut,
|
||||
screenshot_shortcut: Shortcut,
|
||||
) {
|
||||
/// Helper function to register shortcuts during application startup
|
||||
fn _register_shortcut_upon_start(app: &App, shortcut: Shortcut) {
|
||||
let window = app
|
||||
.get_webview_window("main")
|
||||
.expect("webview to be defined");
|
||||
|
||||
// Initialize global shortcut and set its handler
|
||||
app.handle()
|
||||
.plugin(
|
||||
tauri_plugin_global_shortcut::Builder::new()
|
||||
.with_handler(move |app, scut, event| {
|
||||
if scut == &toggle_shortcut {
|
||||
if scut == &shortcut {
|
||||
if let ShortcutState::Pressed = event.state() {
|
||||
handle_window_visibility(app, &window);
|
||||
}
|
||||
} else if scut == &screenshot_shortcut {
|
||||
if let ShortcutState::Pressed = event.state() {
|
||||
// TODO: Implement screenshot functionality
|
||||
println!("Screenshot shortcut pressed");
|
||||
}
|
||||
if let Err(e) = take_area_screenshot(app) {
|
||||
println!("Failed to take screenshot: {}", e);
|
||||
// Toggle window visibility
|
||||
if window.is_visible().unwrap() {
|
||||
window.hide().unwrap(); // Hide window
|
||||
} else {
|
||||
window.show().unwrap(); // Show window
|
||||
window.set_focus().unwrap(); // Focus window
|
||||
// Emit focus-search event
|
||||
app.emit("focus-search", ()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.unwrap();
|
||||
app.global_shortcut().register(toggle_shortcut).unwrap();
|
||||
app.global_shortcut().register(screenshot_shortcut).unwrap();
|
||||
app.global_shortcut().register(shortcut).unwrap(); // Register global shortcut
|
||||
}
|
||||
|
||||
/// Retrieves the currently stored shortcut from the persistent store.
|
||||
/// This is a helper function used by other functions to access the stored shortcut.
|
||||
fn get_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
|
||||
/// Retrieve the stored global shortcut as a string
|
||||
pub fn _get_shortcut<R: Runtime>(app: &AppHandle<R>) -> String {
|
||||
let store = app
|
||||
.get_store(HAYSTACK_TAURI_STORE)
|
||||
.expect("Store should already be loaded or created");
|
||||
@ -231,73 +173,3 @@ fn get_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_current_screenshot_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
|
||||
Ok(get_screenshot_shortcut_from_store(&app))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn unregister_screenshot_shortcut<R: Runtime>(app: AppHandle<R>) {
|
||||
let shortcut_str = get_screenshot_shortcut_from_store(&app);
|
||||
let shortcut = shortcut_str
|
||||
.parse::<Shortcut>()
|
||||
.expect("Stored shortcut string should be valid");
|
||||
|
||||
app.global_shortcut()
|
||||
.unregister(shortcut)
|
||||
.expect("Failed to unregister screenshot shortcut")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn change_screenshot_shortcut<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
_window: tauri::Window<R>,
|
||||
key: String,
|
||||
) -> Result<(), String> {
|
||||
let shortcut = match key.parse::<Shortcut>() {
|
||||
Ok(shortcut) => shortcut,
|
||||
Err(_) => return Err(format!("Invalid screenshot shortcut {}", key)),
|
||||
};
|
||||
|
||||
let store = app
|
||||
.get_store(HAYSTACK_TAURI_STORE)
|
||||
.expect("Store should already be loaded or created");
|
||||
store.set(HAYSTACK_SCREENSHOT_SHORTCUT, JsonValue::String(key));
|
||||
|
||||
register_screenshot_shortcut(&app, shortcut);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_screenshot_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
|
||||
app.global_shortcut()
|
||||
.on_shortcut(shortcut, move |app, scut, event| {
|
||||
if scut == &shortcut {
|
||||
if let ShortcutState::Pressed = event.state() {
|
||||
if let Err(e) = take_area_screenshot(app) {
|
||||
println!("Failed to take screenshot: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.map_err(|err| format!("Failed to register new screenshot shortcut '{}'", err))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn get_screenshot_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
|
||||
let store = app
|
||||
.get_store(HAYSTACK_TAURI_STORE)
|
||||
.expect("Store should already be loaded or created");
|
||||
|
||||
match store
|
||||
.get(HAYSTACK_SCREENSHOT_SHORTCUT)
|
||||
.expect("Screenshot shortcut should already be stored")
|
||||
{
|
||||
JsonValue::String(str) => str,
|
||||
unexpected_type => panic!(
|
||||
"Haystack shortcuts should be stored as strings, found type: {} ",
|
||||
unexpected_type
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,7 @@
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import { createEffect, createSignal } from "solid-js";
|
||||
import { createEffect } from "solid-js";
|
||||
import { sendImage } from "../network";
|
||||
|
||||
// TODO: This component should focus the window and show preview of screenshot,
|
||||
// before we send it to backend, potentially we could draw and annotate
|
||||
// OR we kill this and do stuff siltently
|
||||
// anyhow keeping it like this for now
|
||||
export function ImageViewer() {
|
||||
// const [latestImage, setLatestImage] = createSignal<string | null>(null);
|
||||
|
||||
@ -17,15 +11,10 @@ export function ImageViewer() {
|
||||
console.log("Received processed PNG", event);
|
||||
const base64Data = event.payload as string;
|
||||
|
||||
const appWindow = getCurrentWindow();
|
||||
|
||||
appWindow.show();
|
||||
appWindow.setFocus();
|
||||
|
||||
// setLatestImage(`data:image/png;base64,${base64Data}`);
|
||||
|
||||
const result = await sendImage("test-image.png", base64Data);
|
||||
|
||||
window.location.reload();
|
||||
console.log("DBG: ", result);
|
||||
});
|
||||
|
||||
@ -37,7 +26,9 @@ export function ImageViewer() {
|
||||
return null;
|
||||
|
||||
// return (
|
||||
// <div class="fixed inset-0">
|
||||
// <div>
|
||||
// <FolderPicker />
|
||||
|
||||
// {latestImage() && (
|
||||
// <div class="mt-4">
|
||||
// <h3>Latest Processed Image:</h3>
|
||||
|
Reference in New Issue
Block a user