diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..aecf592 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustc-wrapper = "sccache" diff --git a/.gitignore b/.gitignore index 9e6fbd7..50fdfaa 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,4 @@ dist-ssr *.sln *.sw? -src-tauri/resources \ No newline at end of file +src-tauri/resources/models \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 7efa88e..64ec2cf 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 3858ee6..d4f3972 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,15 @@ "@tauri-apps/plugin-clipboard-manager": "~2", "@tauri-apps/plugin-global-shortcut": "~2", "@tauri-apps/plugin-opener": "^2", + "@tauri-apps/plugin-store": "~2", "@tauri-apps/plugin-stronghold": "~2", "@tauri-apps/plugin-upload": "~2", + "keycode": "^2.2.1", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwindcss": "^4.0.2", - "tauri-plugin-macos-permissions-api": "^2.0.4" + "tauri-plugin-macos-permissions-api": "^2.0.4", + "zod": "^3.24.4" }, "devDependencies": { "@types/react": "^18.3.1", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c6037cb..af0061c 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -17,59 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -94,12 +41,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "alsa" version = "0.9.1" @@ -193,15 +134,6 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arboard" version = "3.4.1" @@ -212,26 +144,14 @@ dependencies = [ "core-graphics 0.23.2", "image", "log", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "parking_lot", "windows-sys 0.48.0", "x11rb", ] -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "async-broadcast" version = "0.7.2" @@ -358,28 +278,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] - [[package]] name = "async-task" version = "4.7.1" @@ -458,18 +356,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -482,21 +368,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bindgen" version = "0.69.5" @@ -553,26 +424,6 @@ dependencies = [ "serde", ] -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "blake2b_simd" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq 0.3.1", -] - [[package]] name = "block" version = "0.1.6" @@ -588,22 +439,13 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "block2" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2", + "objc2 0.5.2", ] [[package]] @@ -799,30 +641,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - [[package]] name = "chrono" version = "0.4.39" @@ -836,17 +654,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - [[package]] name = "clang-sys" version = "1.8.1" @@ -961,24 +768,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - [[package]] name = "convert_case" version = "0.4.0" @@ -1082,15 +871,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] - [[package]] name = "coreaudio-rs" version = "0.11.3" @@ -1173,18 +953,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -1232,42 +1000,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] - [[package]] name = "darling" version = "0.20.10" @@ -1303,12 +1035,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "dary_heap" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728" - [[package]] name = "dasp_frame" version = "0.11.0" @@ -1324,16 +1050,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "zeroize", -] - [[package]] name = "deranged" version = "0.3.11" @@ -1344,17 +1060,6 @@ dependencies = [ "serde", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] - [[package]] name = "derive_more" version = "0.99.18" @@ -1375,9 +1080,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", - "subtle", ] [[package]] @@ -1407,16 +1110,6 @@ dependencies = [ "dirs-sys 0.5.0", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.3.7" @@ -1452,23 +1145,22 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.8.0", + "objc2 0.6.1", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1551,69 +1243,12 @@ dependencies = [ "smallvec", ] -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-zebra" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" -dependencies = [ - "curve25519-dalek", - "ed25519", - "hashbrown 0.14.5", - "hex", - "rand_core 0.6.4", - "sha2", - "zeroize", -] - [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "embed-resource" version = "2.5.1" @@ -1634,15 +1269,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "endi" version = "1.1.0" @@ -1801,29 +1427,13 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - [[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset 0.9.1", + "memoffset", "rustc_version", ] @@ -1922,21 +1532,6 @@ dependencies = [ "new_debug_unreachable", ] -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -1944,7 +1539,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -2012,7 +1606,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -2140,7 +1733,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -2189,16 +1781,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - [[package]] name = "gimli" version = "0.31.1" @@ -2292,17 +1874,17 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "global-hotkey" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00d88f1be7bf4cd2e61623ce08e84be2dfa4eab458e5d632d3dab95f16c1f64" +checksum = "41fbb3a4e56c901ee66c190fdb3fa08344e6d09593cc6c61f8eb9add7144b271" dependencies = [ "crossbeam-channel", "keyboard-types", - "objc2", - "objc2-app-kit", + "objc2 0.6.1", + "objc2-app-kit 0.3.1", "once_cell", "serde", - "thiserror 1.0.69", + "thiserror 2.0.11", "windows-sys 0.59.0", "x11-dl", ] @@ -2318,17 +1900,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "gtk" version = "0.18.2" @@ -2381,25 +1952,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.7.1", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.4.1" @@ -2418,10 +1970,9 @@ dependencies = [ "cpal", "env_logger", "log", + "once_cell", "rdev", - "rig-core", "rubato", - "samplerate", "serde", "serde_json", "tauri", @@ -2432,8 +1983,7 @@ dependencies = [ "tauri-plugin-macos-permissions", "tauri-plugin-opener", "tauri-plugin-single-instance", - "tauri-plugin-stronghold", - "tauri-plugin-upload", + "tauri-plugin-store", "tokio", "vad-rs", "whisper-rs", @@ -2445,16 +1995,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - [[package]] name = "hashbrown" version = "0.15.2" @@ -2485,24 +2025,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "home" version = "0.5.11" @@ -2526,17 +2048,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.14", -] - [[package]] name = "http" version = "1.2.0" @@ -2548,17 +2059,6 @@ dependencies = [ "itoa 1.0.14", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2566,7 +2066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http", ] [[package]] @@ -2577,8 +2077,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -2588,42 +2088,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa 1.0.14", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.6.0" @@ -2633,8 +2103,8 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "httparse", "itoa 1.0.14", "pin-project-lite", @@ -2650,8 +2120,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.2.0", - "hyper 1.6.0", + "http", + "hyper", "hyper-util", "rustls", "rustls-pki-types", @@ -2661,19 +2131,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper 0.14.32", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "hyper-util" version = "0.1.10" @@ -2683,9 +2140,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", - "http-body 1.0.1", - "hyper 1.6.0", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -2941,68 +2398,6 @@ dependencies = [ "libc", ] -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "iota-crypto" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a38db844c910d78825e173c083f2ef416b69cb091bba8ac1055763c6db065b" -dependencies = [ - "aead", - "aes", - "aes-gcm", - "autocfg", - "base64 0.21.7", - "blake2", - "chacha20poly1305", - "cipher", - "curve25519-dalek", - "digest", - "ed25519-zebra", - "generic-array", - "getrandom 0.2.15", - "hkdf", - "hmac", - "iterator-sorted", - "k256", - "pbkdf2", - "rand 0.8.5", - "scrypt", - "serde", - "sha2", - "tiny-keccak", - "unicode-normalization", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "iota_stronghold" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c0d301c7edbc31494d183b7d24c1bb51d3fb10fce2f3793df1baf45b6988e10" -dependencies = [ - "bincode", - "hkdf", - "iota-crypto", - "rust-argon2 1.0.0", - "serde", - "stronghold-derive", - "stronghold-utils", - "stronghold_engine", - "thiserror 1.0.69", - "zeroize", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -3034,12 +2429,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "iterator-sorted" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d101775d2bc8f99f4ac18bf29b9ed70c0dd138b9a1e88d7b80179470cbbe8bd2" - [[package]] name = "itertools" version = "0.12.1" @@ -3162,19 +2551,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "k256" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", -] - [[package]] name = "keyboard-types" version = "0.7.0" @@ -3241,30 +2617,6 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" -[[package]] -name = "libflate" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e" -dependencies = [ - "adler32", - "core2", - "crc32fast", - "dary_heap", - "libflate_lz77", -] - -[[package]] -name = "libflate_lz77" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" -dependencies = [ - "core2", - "hashbrown 0.14.5", - "rle-decode-fast", -] - [[package]] name = "libloading" version = "0.7.4" @@ -3305,23 +2657,6 @@ dependencies = [ "cmake", ] -[[package]] -name = "libsodium-sys-stable" -version = "1.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b023d38f2afdfe36f81e15a9d7232097701d7b107e3a93ba903083985e235239" -dependencies = [ - "cc", - "libc", - "libflate", - "minisign-verify", - "pkg-config", - "tar", - "ureq", - "vcpkg", - "zip", -] - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3344,12 +2679,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.25" @@ -3426,15 +2755,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -3456,12 +2776,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "minisign-verify" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3" - [[package]] name = "miniz_oxide" version = "0.8.3" @@ -3505,9 +2819,9 @@ dependencies = [ "dpi", "gtk", "keyboard-types", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "once_cell", "png", "serde", @@ -3515,23 +2829,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "native-tls" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ndarray" version = "0.16.1" @@ -3606,18 +2903,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.6.5", -] - [[package]] name = "nix" version = "0.29.0" @@ -3628,7 +2913,7 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", - "memoffset 0.9.1", + "memoffset", ] [[package]] @@ -3740,6 +3025,15 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-app-kit" version = "0.2.2" @@ -3749,13 +3043,24 @@ dependencies = [ "bitflags 2.8.0", "block2", "libc", - "objc2", + "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-quartz-core", ] +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags 2.8.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", +] + [[package]] name = "objc2-cloud-kit" version = "0.2.2" @@ -3764,9 +3069,9 @@ checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3776,8 +3081,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3788,8 +3093,19 @@ checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.8.0", + "dispatch2", + "objc2 0.6.1", ] [[package]] @@ -3799,8 +3115,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] @@ -3811,9 +3127,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ "block2", - "objc2", + "objc2 0.5.2", "objc2-contacts", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3831,7 +3147,18 @@ dependencies = [ "bitflags 2.8.0", "block2", "libc", - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.8.0", + "objc2 0.6.1", + "objc2-core-foundation", ] [[package]] @@ -3841,9 +3168,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3854,8 +3181,8 @@ checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3866,8 +3193,8 @@ checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] @@ -3877,8 +3204,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3889,12 +3216,12 @@ checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-link-presentation", "objc2-quartz-core", "objc2-symbols", @@ -3909,8 +3236,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3921,9 +3248,9 @@ checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3934,9 +3261,9 @@ checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" dependencies = [ "bitflags 2.8.0", "block2", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3977,12 +3304,6 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "open" version = "5.3.2" @@ -3995,65 +3316,12 @@ dependencies = [ "pathdiff", ] -[[package]] -name = "openssl" -version = "0.10.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" -dependencies = [ - "bitflags 2.8.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", -] - [[package]] name = "ordered-stream" version = "0.2.0" @@ -4143,28 +3411,12 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pathdiff" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -4328,16 +3580,6 @@ dependencies = [ "futures-io", ] -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.31" @@ -4385,29 +3627,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - [[package]] name = "portable-atomic" version = "1.11.0" @@ -4717,17 +3936,6 @@ dependencies = [ "x11", ] -[[package]] -name = "read-progress-stream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6435842fc2fea44b528719eb8c32203bbc1bb2f5b619fbe0c0a3d8350fd8d2a8" -dependencies = [ - "bytes", - "futures", - "pin-project-lite", -] - [[package]] name = "realfft" version = "3.4.0" @@ -4797,48 +4005,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "winreg 0.50.0", -] - [[package]] name = "reqwest" version = "0.12.12" @@ -4849,10 +4015,10 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.6.0", + "hyper", "hyper-rustls", "hyper-util", "ipnet", @@ -4864,12 +4030,12 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile 2.2.0", + "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-util", @@ -4884,35 +4050,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "rig-core" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aaf53f8631db9cc12287b5595b14964ae36a213f0d247055efcd26714f2da2b" -dependencies = [ - "async-stream", - "bytes", - "futures", - "glob", - "ordered-float", - "reqwest 0.11.27", - "schemars", - "serde", - "serde_json", - "thiserror 1.0.69", - "tracing", -] - [[package]] name = "ring" version = "0.17.8" @@ -4934,12 +4071,6 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53" -[[package]] -name = "rle-decode-fast" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" - [[package]] name = "rubato" version = "0.16.1" @@ -4952,29 +4083,6 @@ dependencies = [ "realfft", ] -[[package]] -name = "rust-argon2" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" -dependencies = [ - "base64 0.13.1", - "blake2b_simd", - "constant_time_eq 0.1.5", - "crossbeam-utils", -] - -[[package]] -name = "rust-argon2" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9848531d60c9cbbcf9d166c885316c24bc0e2a9d3eba0956bb6cbbd79bc6e8" -dependencies = [ - "base64 0.21.7", - "blake2b_simd", - "constant_time_eq 0.3.1", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -5045,15 +4153,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -5095,15 +4194,6 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - [[package]] name = "same-file" version = "1.0.6" @@ -5122,15 +4212,6 @@ dependencies = [ "libsamplerate-sys", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "schemars" version = "0.8.21" @@ -5164,54 +4245,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "pbkdf2", - "salsa20", - "sha2", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "selectors" version = "0.22.0" @@ -5415,16 +4448,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - [[package]] name = "simd-adler32" version = "0.3.7" @@ -5491,8 +4514,8 @@ dependencies = [ "foreign-types 0.5.0", "js-sys", "log", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-quartz-core", "raw-window-handle", "redox_syscall", @@ -5533,16 +4556,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -5587,64 +4600,6 @@ dependencies = [ "quote", ] -[[package]] -name = "stronghold-derive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2835db23c4724c05a2f85b81c4681f4aa8ea158edc8a7f4ad791c916fb766c2e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "stronghold-runtime" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18db7cc51450cefdab5f4990e128dd02c98da6d2992b93ffef8992ac0d2f3ddf" -dependencies = [ - "dirs 4.0.0", - "iota-crypto", - "libc", - "libsodium-sys-stable", - "log", - "nix 0.24.3", - "rand 0.8.5", - "serde", - "thiserror 1.0.69", - "windows 0.36.1", - "zeroize", -] - -[[package]] -name = "stronghold-utils" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8300214898af5e153e7f66e49dbd1c6a21585f2d592d9f24f58b969792475ed6" -dependencies = [ - "rand 0.8.5", - "stronghold-derive", -] - -[[package]] -name = "stronghold_engine" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd7371c42e557dd71a7f860bb2ec6b6fdb32f97a97987ccc2435fdd1f3a8615" -dependencies = [ - "anyhow", - "dirs-next", - "hex", - "iota-crypto", - "once_cell", - "paste", - "serde", - "stronghold-runtime", - "thiserror 1.0.69", - "zeroize", -] - [[package]] name = "strsim" version = "0.11.1" @@ -5709,12 +4664,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5735,27 +4684,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "system-deps" version = "6.2.2" @@ -5851,19 +4779,20 @@ dependencies = [ "glob", "gtk", "heck 0.5.0", - "http 1.2.0", + "http", + "image", "jni", "libc", "log", "mime", "muda", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "percent-encoding", "plist", "raw-window-handle", - "reqwest 0.12.12", + "reqwest", "serde", "serde_json", "serde_repr", @@ -6030,8 +4959,8 @@ checksum = "635ed7c580dc3cdc61c94097d38ef517d749ffc0141c806d904e68e4b0cf1c2a" dependencies = [ "dunce", "glob", - "objc2-app-kit", - "objc2-foundation", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "open", "schemars", "serde", @@ -6060,43 +4989,19 @@ dependencies = [ ] [[package]] -name = "tauri-plugin-stronghold" +name = "tauri-plugin-store" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6670fe0540223d2f6ecc3d71b8e2c513675aac3f0bb5a8a8efc8be5eb81e7b8c" +checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505" dependencies = [ - "hex", - "iota-crypto", - "iota_stronghold", - "log", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "rust-argon2 2.1.0", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.11", - "zeroize", -] - -[[package]] -name = "tauri-plugin-upload" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90ac6d3a783d4406caeae8c75aa05e96346474765517fddfd1dc313ff91aa89" -dependencies = [ - "futures-util", - "log", - "read-progress-stream", - "reqwest 0.12.12", + "dunce", "serde", "serde_json", "tauri", "tauri-plugin", "thiserror 2.0.11", "tokio", - "tokio-util", + "tracing", ] [[package]] @@ -6107,7 +5012,7 @@ checksum = "2274ef891ccc0a8d318deffa9d70053f947664d12d58b9c0d1ae5e89237e01f7" dependencies = [ "dpi", "gtk", - "http 1.2.0", + "http", "jni", "raw-window-handle", "serde", @@ -6125,12 +5030,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3707b40711d3b9f6519150869e358ffbde7c57567fb9b5a8b51150606939b2a0" dependencies = [ "gtk", - "http 1.2.0", + "http", "jni", "log", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "percent-encoding", "raw-window-handle", "softbuffer", @@ -6156,7 +5061,7 @@ dependencies = [ "dunce", "glob", "html5ever", - "http 1.2.0", + "http", "infer", "json-patch", "kuchikiki", @@ -6304,15 +5209,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinystr" version = "0.7.6" @@ -6350,17 +5246,19 @@ dependencies = [ "mio 1.0.3", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.52.0", ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-macros" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ - "native-tls", - "tokio", + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] @@ -6465,7 +5363,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -6535,9 +5433,9 @@ dependencies = [ "dirs 5.0.1", "libappindicator", "muda", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "once_cell", "png", "serde", @@ -6569,7 +5467,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ - "memoffset 0.9.1", + "memoffset", "tempfile", "winapi", ] @@ -6621,31 +5519,12 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - [[package]] name = "untrusted" version = "0.9.0" @@ -6740,12 +5619,6 @@ dependencies = [ "samplerate", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version-compare" version = "0.2.0" @@ -7094,27 +5967,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150" dependencies = [ - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "raw-window-handle", "windows-sys 0.59.0", "windows-version", ] -[[package]] -name = "windows" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53b97a83176b369b0eb2fd8158d4ae215357d02df9d40c1e1bf1879c5482c80" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows" version = "0.54.0" @@ -7359,12 +6219,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -7389,12 +6243,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -7431,12 +6279,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -7461,12 +6303,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -7515,12 +6351,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -7581,16 +6411,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "winreg" version = "0.52.0" @@ -7637,15 +6457,15 @@ dependencies = [ "gdkx11", "gtk", "html5ever", - "http 1.2.0", + "http", "javascriptcore-rs", "jni", "kuchikiki", "libc", "ndk 0.9.0", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "objc2-ui-kit", "objc2-web-kit", "once_cell", @@ -7703,17 +6523,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core 0.6.4", - "zeroize", -] - [[package]] name = "xattr" version = "1.4.0" @@ -7780,7 +6589,7 @@ dependencies = [ "futures-core", "futures-util", "hex", - "nix 0.29.0", + "nix", "ordered-stream", "serde", "serde_repr", @@ -7869,21 +6678,6 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "serde", - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] [[package]] name = "zerovec" @@ -7907,35 +6701,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "zip" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744" -dependencies = [ - "arbitrary", - "crc32fast", - "crossbeam-utils", - "flate2", - "indexmap 2.7.1", - "memchr", - "zopfli", -] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "once_cell", - "simd-adler32", -] - [[package]] name = "zvariant" version = "5.2.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 363dd21..35d40d9 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -5,6 +5,9 @@ description = "A Tauri App" authors = ["you"] edition = "2021" +[profile.dev] +incremental = true # Compile your binary in smaller steps. + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] @@ -18,7 +21,8 @@ crate-type = ["staticlib", "cdylib", "rlib"] tauri-build = { version = "2", features = [] } [dependencies] -tauri = { version = "2", features = [] } +once_cell = "1" +tauri = { version = "2", features = ["tray-icon", 'image-png'] } tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" @@ -29,14 +33,11 @@ cpal = "0.15.3" whisper-rs = { version = "0.13.2", features = ["whisper-cpp-log"] } anyhow = "1.0.95" rubato = "0.16.1" -samplerate = "0.2.4" -rig-core = "0.8.0" env_logger = "0.11.6" log = "0.4.25" tokio = "1.43.0" vad-rs = "0.1.5" -tauri-plugin-upload = "2" -tauri-plugin-stronghold = "2" +tauri-plugin-store = "2" [target.'cfg(target_os = "macos")'.dependencies] whisper-rs = { version = "0.13.2", features = ["metal"] } diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 379b810..5b8acce 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -6,9 +6,11 @@ "permissions": [ "core:default", "opener:default", + "store:default", "global-shortcut:allow-is-registered", "global-shortcut:allow-register", "global-shortcut:allow-unregister", + "global-shortcut:allow-unregister-all", "macos-permissions:default" ] } diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png index 0199b1b..6547a69 100644 Binary files a/src-tauri/icons/128x128.png and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png index e81bece..02dcd00 100644 Binary files a/src-tauri/icons/128x128@2x.png and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png index f246cbf..181fe83 100644 Binary files a/src-tauri/icons/32x32.png and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/64x64.png b/src-tauri/icons/64x64.png new file mode 100644 index 0000000..e468459 Binary files /dev/null and b/src-tauri/icons/64x64.png differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png index 0ca4f27..34ec15c 100644 Binary files a/src-tauri/icons/Square107x107Logo.png and b/src-tauri/icons/Square107x107Logo.png differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png index b81f820..f7b95ea 100644 Binary files a/src-tauri/icons/Square142x142Logo.png and b/src-tauri/icons/Square142x142Logo.png differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png index 624c7bf..6d5c06b 100644 Binary files a/src-tauri/icons/Square150x150Logo.png and b/src-tauri/icons/Square150x150Logo.png differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png index c021d2b..1ee6d50 100644 Binary files a/src-tauri/icons/Square284x284Logo.png and b/src-tauri/icons/Square284x284Logo.png differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png index 6219700..59ed9ca 100644 Binary files a/src-tauri/icons/Square30x30Logo.png and b/src-tauri/icons/Square30x30Logo.png differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png index f9bc048..12e12ed 100644 Binary files a/src-tauri/icons/Square310x310Logo.png and b/src-tauri/icons/Square310x310Logo.png differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png index d5fbfb2..b539c54 100644 Binary files a/src-tauri/icons/Square44x44Logo.png and b/src-tauri/icons/Square44x44Logo.png differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png index 63440d7..1f0f5bb 100644 Binary files a/src-tauri/icons/Square71x71Logo.png and b/src-tauri/icons/Square71x71Logo.png differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png index f3f705a..af73f9a 100644 Binary files a/src-tauri/icons/Square89x89Logo.png and b/src-tauri/icons/Square89x89Logo.png differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png index 4556388..9a9f483 100644 Binary files a/src-tauri/icons/StoreLogo.png and b/src-tauri/icons/StoreLogo.png differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..bf59e1e Binary files /dev/null and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..87766d4 Binary files /dev/null and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..bf59e1e Binary files /dev/null and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..8abd652 Binary files /dev/null and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..9597ae8 Binary files /dev/null and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..8abd652 Binary files /dev/null and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..49cacd5 Binary files /dev/null and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..a05f16c Binary files /dev/null and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..49cacd5 Binary files /dev/null and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..595f19c Binary files /dev/null and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..26983c4 Binary files /dev/null and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..595f19c Binary files /dev/null and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..5526873 Binary files /dev/null and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..a66141a Binary files /dev/null and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..5526873 Binary files /dev/null and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns index 5e7ed61..71e6035 100644 Binary files a/src-tauri/icons/icon.icns and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico index b3636e4..ccd1743 100644 Binary files a/src-tauri/icons/icon.ico and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png index fc64c2c..6e5da07 100644 Binary files a/src-tauri/icons/icon.png and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@1x.png b/src-tauri/icons/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000..0d21a15 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-20x20@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000..91aba3c Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x.png b/src-tauri/icons/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000..91aba3c Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-20x20@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-20x20@3x.png b/src-tauri/icons/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000..75a3a54 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-20x20@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@1x.png b/src-tauri/icons/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000..78d8055 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-29x29@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000..8029ecd Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x.png b/src-tauri/icons/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000..8029ecd Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-29x29@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-29x29@3x.png b/src-tauri/icons/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000..e18d46f Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-29x29@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@1x.png b/src-tauri/icons/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000..91aba3c Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-40x40@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000..68f773f Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x.png b/src-tauri/icons/ios/AppIcon-40x40@2x.png new file mode 100644 index 0000000..68f773f Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-40x40@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-40x40@3x.png b/src-tauri/icons/ios/AppIcon-40x40@3x.png new file mode 100644 index 0000000..afcaed5 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-40x40@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-512@2x.png b/src-tauri/icons/ios/AppIcon-512@2x.png new file mode 100644 index 0000000..8ac533e Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-512@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-60x60@2x.png b/src-tauri/icons/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000..afcaed5 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-60x60@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-60x60@3x.png b/src-tauri/icons/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000..f614d00 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-60x60@3x.png differ diff --git a/src-tauri/icons/ios/AppIcon-76x76@1x.png b/src-tauri/icons/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000..5fd0658 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-76x76@1x.png differ diff --git a/src-tauri/icons/ios/AppIcon-76x76@2x.png b/src-tauri/icons/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000..dc2bbe7 Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-76x76@2x.png differ diff --git a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000..8db3d2f Binary files /dev/null and b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/src-tauri/icons/logo.png b/src-tauri/icons/logo.png new file mode 100644 index 0000000..0cdfec7 Binary files /dev/null and b/src-tauri/icons/logo.png differ diff --git a/src-tauri/resources/tray_idle.png b/src-tauri/resources/tray_idle.png new file mode 100644 index 0000000..49bc715 Binary files /dev/null and b/src-tauri/resources/tray_idle.png differ diff --git a/src-tauri/resources/tray_recording.png b/src-tauri/resources/tray_recording.png new file mode 100644 index 0000000..4d12930 Binary files /dev/null and b/src-tauri/resources/tray_recording.png differ diff --git a/src-tauri/src/actions.rs b/src-tauri/src/actions.rs new file mode 100644 index 0000000..932d1bb --- /dev/null +++ b/src-tauri/src/actions.rs @@ -0,0 +1,86 @@ +use crate::managers::audio::AudioRecordingManager; +use crate::managers::transcription::TranscriptionManager; +use crate::utils; +use crate::utils::change_tray_icon; +use crate::utils::TrayIconState; +use once_cell::sync::Lazy; +use std::collections::HashMap; +use std::sync::Arc; +use tauri::AppHandle; +use tauri::Manager; + +// Action Handler Types +pub type PressAction = fn(app: &AppHandle, shortcut_str: &str); +pub type ReleaseAction = fn(app: &AppHandle, shortcut_str: &str); + +// TODO refactor to start and stop +pub struct ActionSet { + pub press: PressAction, + pub release: ReleaseAction, +} + +// Handler Functions +fn transcribe_pressed_action(app: &AppHandle, _shortcut_str: &str) { + change_tray_icon(app, TrayIconState::Recording); + + let rm = app.state::>(); + rm.try_start_recording("transcribe"); +} + +fn transcribe_released_action(app: &AppHandle, _shortcut_str: &str) { + let ah = app.clone(); + let rm = Arc::clone(&app.state::>()); + let tm = Arc::clone(&app.state::>()); + + change_tray_icon(app, TrayIconState::Idle); + + tauri::async_runtime::spawn(async move { + if let Some(samples) = rm.stop_recording("transcribe") { + match tm.transcribe(samples) { + Ok(transcription) => { + println!("Global Shortcut Transcription: {}", transcription); + if transcription != "" { + utils::paste(transcription, ah); + } + } + Err(err) => println!("Global Shortcut Transcription error: {}", err), + } + } + }); +} + +fn test_binding_pressed_action(app: &AppHandle, shortcut_str: &str) { + println!( + "Shortcut ID 'test': Pressed - {} (App: {})", + shortcut_str, + app.package_info().name + ); +} + +fn test_binding_released_action(app: &AppHandle, shortcut_str: &str) { + println!( + "Shortcut ID 'test': Released - {} (App: {})", + shortcut_str, + app.package_info().name + ); +} + +// Static Action Map +pub static ACTION_MAP: Lazy> = Lazy::new(|| { + let mut map = HashMap::new(); + map.insert( + "transcribe".to_string(), + ActionSet { + press: transcribe_pressed_action, + release: transcribe_released_action, + }, + ); + map.insert( + "test".to_string(), + ActionSet { + press: test_binding_pressed_action, + release: test_binding_released_action, + }, + ); + map +}); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 26cb0ad..b8b961a 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,238 +1,32 @@ +mod actions; mod managers; +mod settings; +mod shortcut; +mod utils; -use log::info; use managers::audio::AudioRecordingManager; -use managers::keybinding::KeyBindingManager; use managers::transcription::TranscriptionManager; -use rdev::{simulate, EventType, Key, SimulateError}; -use rig::{completion::Prompt, providers::anthropic}; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; -use std::{thread, time}; +use tauri::image::Image; +use tauri::menu::{Menu, MenuItem}; +use tauri::tray::TrayIconBuilder; use tauri::Manager; use tauri_plugin_autostart::MacosLauncher; -use tauri_plugin_clipboard_manager::ClipboardExt; -fn try_send_event(event: &EventType) { - if let Err(SimulateError) = simulate(event) { - println!("We could not send {:?}", event); - } +#[derive(Default)] +struct ShortcutToggleStates { + // Map: shortcut_binding_id -> is_active + active_toggles: HashMap, } -fn send(event: EventType) { - try_send_event(&event); - thread::sleep(time::Duration::from_millis(60)); -} - -fn send_paste() { - // Determine the modifier key based on the OS - #[cfg(target_os = "macos")] - let modifier_key = Key::MetaLeft; // Command key on macOS - #[cfg(not(target_os = "macos"))] - let modifier_key = Key::ControlLeft; // Control key on other systems - - // Press both keys - send(EventType::KeyPress(modifier_key)); - send(EventType::KeyPress(Key::KeyV)); - - // Release both keys - send(EventType::KeyRelease(Key::KeyV)); - send(EventType::KeyRelease(modifier_key)); -} - -fn send_copy() { - // Determine the modifier key based on the OS - #[cfg(target_os = "macos")] - let modifier_key = Key::MetaLeft; // Command key on macOS - #[cfg(not(target_os = "macos"))] - let modifier_key = Key::ControlLeft; // Control key on other systems - - // Press both keys - send(EventType::KeyPress(modifier_key)); - send(EventType::KeyPress(Key::KeyC)); - - // Release both keys - send(EventType::KeyRelease(Key::KeyC)); - send(EventType::KeyRelease(modifier_key)); -} - -fn paste(text: String, app_handle: tauri::AppHandle) { - let clipboard = app_handle.clipboard(); - - // get the current clipboard content - let clipboard_content = clipboard.read_text().unwrap_or_default(); - - clipboard.write_text(&text).unwrap(); - send_paste(); - - // restore the clipboard - clipboard.write_text(&clipboard_content).unwrap(); -} - -fn get_highlighted_text(app_handle: tauri::AppHandle) -> String { - let clipboard = app_handle.clipboard(); - - // save the clipboard content - let clipboard_content = clipboard.read_text().unwrap_or_default(); - - // empty the clipboard - clipboard.write_text("").unwrap(); - - // issue 'copy' - send_copy(); - - // get the highlighted text - let highlighted_text = clipboard.read_text().unwrap_or_default(); - - // restore the clipboard content - clipboard.write_text(&clipboard_content).unwrap(); - - highlighted_text -} - -const INSTRUCT_SYS: &str = r#" -You are a helpful assistant. You will receive voice transcriptions -from a user that may include both a command/question and some -minimal context to help you respond appropriately. - -For example, the user might say: -- A direct question with no context: "What is the capital of France?" -- A command with context: "get commit message I fixed the bug in the login system" -"#; - -const CODE_SYS: &str = r#" -You are a code-only assistant. I will provide you with selected text or clipboard content along with instructions. If I request code, output only the exact code implementation. If I request a terminal command, provide only the valid command syntax. Never use markdown, explanations, or additional text. - - When I share selected text or clipboard content, use that as context for generating your response. The output should be ready to copy and paste directly, with no formatting or commentary. For terminal commands, ensure they are valid for the specified environment. Note for terminal commands, I typically use lowercase instead of uppercase. You may also be given them directly, but need to translate them into a way that can actually be executed in the terminal because the transcription you are given might be poor. - - Output only: - - Raw code implementation when code is requested - - Terminal command syntax when a command is requested - - No markdown, no backticks, no explanations - - No additional text or descriptions -"#; - -fn register_bindings(manager: &mut KeyBindingManager) { - manager.register( - "ctrl-meta".to_string(), - vec![Key::ControlRight, Key::MetaRight], - |ctx| { - info!("Ctrl+Meta pressed!"); - ctx.recording_manager.try_start_recording("ctrl-meta"); - None - }, - |ctx| { - info!("release being called from ctrl-meta"); - let ctx = ctx.clone(); - Some(tauri::async_runtime::spawn(async move { - if let Some(samples) = ctx.recording_manager.stop_recording("ctrl-meta") { - match ctx.transcription_manager.transcribe(samples) { - Ok(transcription) => { - println!("Transcription: {}", transcription); - paste(transcription, ctx.app_handle.clone()); - } - Err(err) => println!("Transcription error: {}", err), - } - } - })) - }, - ); - - // Register LLM Call after Transcription - // manager.register( - // "shift-alt".to_string(), - // vec![Key::ShiftLeft, Key::Alt], - // |ctx| { - // info!("Shift+Alt pressed!"); - // ctx.recording_manager.try_start_recording("shift-alt"); - // None - // }, - // |ctx| { - // info!("release being called from shift-alt"); - // let ctx = ctx.clone(); - // Some(tauri::async_runtime::spawn(async move { - // if let Some(samples) = ctx.recording_manager.stop_recording("shift-alt") { - // if let Ok(transcription) = ctx.transcription_manager.transcribe(samples) { - // println!("Transcription: {}", transcription); - - // let instruct = ctx - // .anthropic - // .agent(anthropic::CLAUDE_3_5_SONNET) - // .preamble(INSTRUCT_SYS) - // .temperature(0.5) - // .build(); - - // let highlighted_text = get_highlighted_text(ctx.app_handle.clone()); - // println!("Highlighted Text: {}", highlighted_text); - // let prompt = format!("{}\n\ncontext:{}\n", transcription, highlighted_text); - - // match instruct.prompt(prompt).await { - // Ok(response) => { - // println!("Sonnet response: {}", response); - // paste(response, ctx.app_handle.clone()); - // } - // Err(err) => println!("Sonnet error: {}", err), - // } - // } - // } - // })) - // }, - // ); - - // manager.register( - // "ctrl-alt-meta".to_string(), - // vec![Key::ControlLeft, Key::Alt, Key::MetaLeft], - // |ctx| { - // info!("Ctrl+Alt+Meta pressed!"); - // ctx.recording_manager.try_start_recording("ctrl-alt-meta"); - // None - // }, - // |ctx| { - // info!("release being called from ctrl-alt-meta"); - // let ctx = ctx.clone(); - // Some(tauri::async_runtime::spawn(async move { - // if let Some(samples) = ctx.recording_manager.stop_recording("ctrl-alt-meta") { - // let samples: Vec = samples; // explicit type annotation - // match ctx.transcription_manager.transcribe(samples) { - // Ok(transcription) => { - // println!("Transcription: {}", transcription); - - // let code = ctx - // .anthropic - // .agent(anthropic::CLAUDE_3_5_SONNET) - // .preamble(CODE_SYS) - // .temperature(0.5) - // .build(); - - // let highlighted_text = get_highlighted_text(ctx.app_handle.clone()); - // let prompt = - // format!("{}\n\ncontext:{}\n", transcription, highlighted_text); - - // match code.prompt(prompt).await { - // Ok(response) => { - // println!("Sonnet response: {}", response); - // paste(response, ctx.app_handle.clone()); - // } - // Err(err) => println!("Sonnet error: {}", err), - // } - // } - // Err(err) => println!("Transcription error: {}", err), - // } - // } else { - // println!("No samples recorded"); - // } - // })) - // }, - // ); -} +type ManagedToggleState = Mutex; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { env_logger::init(); tauri::Builder::default() - .plugin(tauri_plugin_stronghold::Builder::new(|pass| todo!()).build()) - .plugin(tauri_plugin_upload::init()) - .plugin(tauri_plugin_global_shortcut::Builder::new().build()) .plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_autostart::init( MacosLauncher::LaunchAgent, @@ -240,63 +34,90 @@ pub fn run() { )) .plugin(tauri_plugin_macos_permissions::init()) .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_store::Builder::default().build()) + .plugin(tauri_plugin_global_shortcut::Builder::new().build()) + .manage(Mutex::new(ShortcutToggleStates::default())) .setup(move |app| { - let app_handle = app.handle().clone(); - - let vad_path = app.path().resolve( - "resources/silero_vad_v4.onnx", - tauri::path::BaseDirectory::Resource, - )?; - - let whisper_path = app.path().resolve( - "resources/ggml-small.bin", - tauri::path::BaseDirectory::Resource, - )?; + let settings_i = MenuItem::with_id(app, "settings", "Settings", true, None::<&str>)?; + let quit_i = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?; + let menu = Menu::with_items(app, &[&settings_i, &quit_i])?; + let tray = TrayIconBuilder::new() + .icon(Image::from_path(app.path().resolve( + "resources/tray_idle.png", + tauri::path::BaseDirectory::Resource, + )?)?) + .menu(&menu) + .show_menu_on_left_click(true) + .on_menu_event(|app, event| match event.id.as_ref() { + "settings" => { + if let Some(settings_window) = app.get_webview_window("main") { + // First, ensure the window is visible + if let Err(e) = settings_window.show() { + eprintln!("Failed to show window: {}", e); + } + // Then, bring it to the front and give it focus + if let Err(e) = settings_window.set_focus() { + eprintln!("Failed to focus window: {}", e); + } + // Optional: On macOS, ensure the app becomes active if it was an accessory + #[cfg(target_os = "macos")] + { + if let Err(e) = + app.set_activation_policy(tauri::ActivationPolicy::Regular) + { + eprintln!("Failed to set activation policy to Regular: {}", e); + } + } + } else { + eprintln!("Main window not found"); + } + } + "quit" => { + app.exit(0); + } + _ => {} + }) + .build(app)?; + app.manage(tray); let recording_manager = Arc::new( - AudioRecordingManager::new(&vad_path) - .expect("Failed to initialize recording manager"), + AudioRecordingManager::new(app).expect("Failed to initialize recording manager"), ); let transcription_manager = Arc::new( - TranscriptionManager::new( - whisper_path - .to_str() - .expect("Path contains invalid UTF-8 Chars"), - ) - .expect("Failed to initialize transcription manager"), + TranscriptionManager::new(&app) + .expect("Failed to initialize transcription manager"), ); - let manager = Arc::new(Mutex::new(KeyBindingManager::new( - recording_manager.clone(), - transcription_manager.clone(), - // claude_client.clone(), - app_handle.clone(), - ))); + // Add managers to Tauri's managed state + app.manage(recording_manager.clone()); + app.manage(transcription_manager.clone()); - { - let mut manager = manager.lock().unwrap(); - register_bindings(&mut manager); - } + shortcut::init_shortcuts(app); - let manager_clone = manager.clone(); - tauri::async_runtime::spawn(async move { - rdev::listen(move |event| { - if let Ok(manager) = manager_clone.lock() { - manager.handle_event(&event); - } - }) - .unwrap(); - }); Ok(()) }) - .on_window_event(|app, event| match event { + .on_window_event(|window, event| match event { tauri::WindowEvent::CloseRequested { api, .. } => { - app.hide().unwrap(); + #[cfg(target_os = "macos")] + let res = window + .app_handle() + .set_activation_policy(tauri::ActivationPolicy::Accessory); + if let Err(e) = res { + println!("Failed to set activation policy: {}", e); + } + api.prevent_close(); + + // TODO may be different on windows, this works for macos + tauri::AppHandle::hide(window.app_handle()).unwrap(); } _ => {} }) - .invoke_handler(tauri::generate_handler![]) + .invoke_handler(tauri::generate_handler![ + shortcut::change_binding, + shortcut::reset_binding, + shortcut::change_ptt_setting + ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/src/managers/audio.rs b/src-tauri/src/managers/audio.rs index a204868..e27d00f 100644 --- a/src-tauri/src/managers/audio.rs +++ b/src-tauri/src/managers/audio.rs @@ -1,9 +1,10 @@ use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use cpal::SampleFormat; use rubato::{FftFixedIn, Resampler}; -use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::vec::Vec; -use vad_rs::{Vad, VadStatus}; +use tauri::{App, Manager}; +use vad_rs::Vad; #[derive(Clone, Debug)] pub enum RecordingState { @@ -16,8 +17,40 @@ pub struct AudioRecordingManager { buffer: Arc>>, } +trait SampleToF32 { + fn to_f32(&self) -> f32; +} + +impl SampleToF32 for i8 { + fn to_f32(&self) -> f32 { + *self as f32 / 128.0 + } +} + +impl SampleToF32 for i16 { + fn to_f32(&self) -> f32 { + *self as f32 / 32768.0 + } +} + +impl SampleToF32 for i32 { + fn to_f32(&self) -> f32 { + *self as f32 / 2147483648.0 + } +} + +impl SampleToF32 for f32 { + fn to_f32(&self) -> f32 { + *self + } +} + impl AudioRecordingManager { - pub fn new(vad_path: &PathBuf) -> Result { + pub fn new(app: &App) -> Result { + let vad_path = app.path().resolve( + "resources/models/silero_vad_v4.onnx", + tauri::path::BaseDirectory::Resource, + )?; let host = cpal::default_host(); let device = host .default_input_device() @@ -48,64 +81,140 @@ impl AudioRecordingManager { let vad_buffer = Arc::new(Mutex::new(Vec::new())); let vad_buffer_clone = Arc::clone(&vad_buffer); - std::thread::spawn(move || { - let stream = match config.sample_format() { - cpal::SampleFormat::F32 => device.build_input_stream( - &config.into(), - move |data: &[f32], _: &cpal::InputCallbackInfo| { - let state_guard = state_clone.lock().unwrap(); - if let RecordingState::Recording { .. } = *state_guard { - let mut temp_buffer = temp_buffer_clone.lock().unwrap(); - temp_buffer.extend_from_slice(data); + // Generic function to process audio data + fn process_audio( + data: &[T], + state_clone: Arc>, + temp_buffer_clone: Arc>>, + resampler_clone: Arc>>, + vad_buffer_clone: Arc>>, + buffer_clone: Arc>>, + vad_clone: Arc>, + ) { + let state_guard = state_clone.lock().unwrap(); + if let RecordingState::Recording { .. } = *state_guard { + let mut temp_buffer = temp_buffer_clone.lock().unwrap(); - // Process when we have enough samples - while temp_buffer.len() >= 1024 { - // Take the first 1024 samples for processing - let chunk: Vec = temp_buffer.drain(..1024).collect(); + // Convert incoming data to f32 + let f32_data: Vec = data.iter().map(|sample| sample.to_f32()).collect(); + temp_buffer.extend_from_slice(&f32_data); - // Convert input data to the format expected by Rubato - let input_frames = vec![chunk]; + // Process when we have enough samples + while temp_buffer.len() >= 1024 { + // Take the first 1024 samples for processing + let chunk: Vec = temp_buffer.drain(..1024).collect(); - // Process the audio chunk through the resampler - let mut resampler = resampler_clone.lock().unwrap(); - if let Ok(resampled) = resampler.process(&input_frames, None) { - // Add resampled data to VAD buffer - let mut vad_buffer = vad_buffer_clone.lock().unwrap(); - vad_buffer.extend_from_slice(&resampled[0]); + // Convert input data to the format expected by Rubato + let input_frames = vec![chunk]; - // Process 30ms chunks (480 samples) for VAD - while vad_buffer.len() >= 480 { - let chunk = vad_buffer.drain(..480).collect::>(); + // Process the audio chunk through the resampler + let mut resampler = resampler_clone.lock().unwrap(); + if let Ok(resampled) = resampler.process(&input_frames, None) { + // Add resampled data to VAD buffer + let mut vad_buffer = vad_buffer_clone.lock().unwrap(); + vad_buffer.extend_from_slice(&resampled[0]); - // Use VAD to detect speech - if let Ok(mut vad) = vad_clone.lock() { - // println!("VAD lock acquired"); - match vad.compute(&chunk) { - Ok(mut result) => { - if result.prob > 0.15 { - let mut buffer = - buffer_clone.lock().unwrap(); - buffer.extend_from_slice(&chunk); - } - } - Err(error) => { - eprintln!("Error computing VAD: {:?}", error) - } - } + // Process 30ms chunks (480 samples) for VAD + while vad_buffer.len() >= 480 { + let chunk = vad_buffer.drain(..480).collect::>(); + + // Use VAD to detect speech + if let Ok(mut vad) = vad_clone.lock() { + match vad.compute(&chunk) { + Ok(result) => { + if result.prob > 0.15 { + let mut buffer = buffer_clone.lock().unwrap(); + buffer.extend_from_slice(&chunk); } } + Err(error) => { + eprintln!("Error computing VAD: {:?}", error) + } } } } + } + } + } + } + + std::thread::spawn(move || { + let err_fn = |err| eprintln!("Error in stream: {}", err); + + // Build the appropriate stream based on the sample format + let stream = match config.sample_format() { + SampleFormat::I8 => device.build_input_stream( + &config.into(), + move |data: &[i8], _| { + process_audio( + data, + Arc::clone(&state_clone), + Arc::clone(&temp_buffer_clone), + Arc::clone(&resampler_clone), + Arc::clone(&vad_buffer_clone), + Arc::clone(&buffer_clone), + Arc::clone(&vad_clone), + ) }, - |err| eprintln!("Error in stream: {}", err), + err_fn, None, ), - sample_format => panic!("Unsupported sample format: {:?}", sample_format), + SampleFormat::I16 => device.build_input_stream( + &config.into(), + move |data: &[i16], _| { + process_audio( + data, + Arc::clone(&state_clone), + Arc::clone(&temp_buffer_clone), + Arc::clone(&resampler_clone), + Arc::clone(&vad_buffer_clone), + Arc::clone(&buffer_clone), + Arc::clone(&vad_clone), + ) + }, + err_fn, + None, + ), + SampleFormat::I32 => device.build_input_stream( + &config.into(), + move |data: &[i32], _| { + process_audio( + data, + Arc::clone(&state_clone), + Arc::clone(&temp_buffer_clone), + Arc::clone(&resampler_clone), + Arc::clone(&vad_buffer_clone), + Arc::clone(&buffer_clone), + Arc::clone(&vad_clone), + ) + }, + err_fn, + None, + ), + SampleFormat::F32 => device.build_input_stream( + &config.into(), + move |data: &[f32], _| { + process_audio( + data, + Arc::clone(&state_clone), + Arc::clone(&temp_buffer_clone), + Arc::clone(&resampler_clone), + Arc::clone(&vad_buffer_clone), + Arc::clone(&buffer_clone), + Arc::clone(&vad_clone), + ) + }, + err_fn, + None, + ), + sample_format => { + // Use anyhow to return a proper error instead of panicking + panic!("Unsupported sample format: {:?}", sample_format); + } } - .unwrap(); + .expect("Failed to build input stream"); - stream.play().unwrap(); + stream.play().expect("Failed to play stream"); std::thread::park(); }); diff --git a/src-tauri/src/managers/keybinding.rs b/src-tauri/src/managers/keybinding.rs deleted file mode 100644 index b2475bd..0000000 --- a/src-tauri/src/managers/keybinding.rs +++ /dev/null @@ -1,131 +0,0 @@ -use super::audio::AudioRecordingManager; -use super::transcription::TranscriptionManager; -use rdev::{EventType, Key}; -use rig::providers::anthropic; -use std::collections::HashSet; -use std::sync::{Arc, Mutex}; - -type KeySet = HashSet; - -#[derive(Clone)] -pub struct BindingContext { - pub recording_manager: Arc, - pub transcription_manager: Arc, - // pub anthropic: Arc, - pub app_handle: tauri::AppHandle, -} - -pub struct KeyBinding { - id: String, - keys: KeySet, - on_press: Box< - dyn Fn(&BindingContext) -> Option> + Send + 'static, - >, - on_release: Box< - dyn Fn(&BindingContext) -> Option> + Send + 'static, - >, -} - -impl KeyBinding { - fn new(id: String, keys: Vec, on_press: F, on_release: G) -> Self - where - F: Fn(&BindingContext) -> Option> + Send + 'static, - G: Fn(&BindingContext) -> Option> + Send + 'static, - { - Self { - id, - keys: keys.into_iter().collect(), - on_press: Box::new(on_press), - on_release: Box::new(on_release), - } - } -} - -pub struct KeyBindingManager { - bindings: Vec, - global_pressed: Arc>>, - active_bindings: Arc>>, - context: BindingContext, -} - -impl KeyBindingManager { - pub fn new( - recording_manager: Arc, - transcription_manager: Arc, - // anthropic: Arc, - app_handle: tauri::AppHandle, - ) -> Self { - Self { - bindings: Vec::new(), - global_pressed: Arc::new(Mutex::new(HashSet::new())), - active_bindings: Arc::new(Mutex::new(HashSet::new())), - context: BindingContext { - recording_manager, - transcription_manager, - // anthropic, - app_handle, - }, - } - } - - pub fn register(&mut self, id: String, keys: Vec, on_press: F, on_release: G) - where - F: Fn(&BindingContext) -> Option> + Send + 'static, - G: Fn(&BindingContext) -> Option> + Send + 'static, - { - self.bindings - .push(KeyBinding::new(id, keys, on_press, on_release)); - } - - pub fn handle_event(&self, event: &rdev::Event) { - if let EventType::KeyPress(key) | EventType::KeyRelease(key) = event.event_type { - let mut is_press = matches!(event.event_type, EventType::KeyPress(_)); - - // Update global pressed keys - let mut pressed = self.global_pressed.lock().unwrap(); - - // If we get a release event for a key that wasn't pressed, - // treat it as a press event instead - if !is_press && !pressed.contains(&key) { - is_press = true; - } - - if is_press { - pressed.insert(key); - } else { - pressed.remove(&key); - } - let pressed_snapshot = pressed.clone(); - drop(pressed); - - // Check binding states - let mut active = self.active_bindings.lock().unwrap(); - for binding in &self.bindings { - let is_active = active.contains(&binding.id); - let all_required_pressed = binding.keys.is_subset(&pressed_snapshot); - let any_required_key = binding.keys.contains(&key); - - // Only process if this event is for a key we care about - if any_required_key { - match (all_required_pressed, is_active) { - (true, false) => { - (binding.on_press)(&self.context); - active.insert(binding.id.clone()); - } - (false, true) => { - // Only trigger release if none of the required keys are pressed - let any_binding_key_pressed = - binding.keys.iter().any(|k| pressed_snapshot.contains(k)); - - if !any_binding_key_pressed { - (binding.on_release)(&self.context); - active.remove(&binding.id); - } - } - _ => {} - } - } - } - } - } -} diff --git a/src-tauri/src/managers/mod.rs b/src-tauri/src/managers/mod.rs index 8a31278..a61d9ac 100644 --- a/src-tauri/src/managers/mod.rs +++ b/src-tauri/src/managers/mod.rs @@ -1,3 +1,2 @@ pub mod audio; -pub mod keybinding; pub mod transcription; diff --git a/src-tauri/src/managers/transcription.rs b/src-tauri/src/managers/transcription.rs index cc9d3fd..83555fe 100644 --- a/src-tauri/src/managers/transcription.rs +++ b/src-tauri/src/managers/transcription.rs @@ -1,5 +1,6 @@ use anyhow::Result; use std::sync::Mutex; +use tauri::{App, Manager}; use whisper_rs::install_whisper_log_trampoline; use whisper_rs::{ FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters, WhisperState, @@ -11,12 +12,19 @@ pub struct TranscriptionManager { } impl TranscriptionManager { - pub fn new(whisper_path: &str) -> Result { + pub fn new(app: &App) -> Result { + let whisper_path = app.path().resolve( + "resources/models/ggml-small.bin", + tauri::path::BaseDirectory::Resource, + )?; + let path = whisper_path + .to_str() + .expect("Path contains invalid UTF-8 Chars"); + install_whisper_log_trampoline(); // Load the model - let context = - WhisperContext::new_with_params(whisper_path, WhisperContextParameters::default()) - .map_err(|e| anyhow::anyhow!("Failed to load whisper model: {}", e))?; + let context = WhisperContext::new_with_params(path, WhisperContextParameters::default()) + .map_err(|e| anyhow::anyhow!("Failed to load whisper model: {}", e))?; // Create state let state = context.create_state().expect("failed to create state"); @@ -46,6 +54,7 @@ impl TranscriptionManager { params.set_print_progress(false); params.set_print_realtime(false); params.set_print_timestamps(false); + params.set_suppress_blank(true); params.set_suppress_non_speech_tokens(true); state diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs new file mode 100644 index 0000000..021c9be --- /dev/null +++ b/src-tauri/src/settings.rs @@ -0,0 +1,121 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use tauri::{App, AppHandle}; +use tauri_plugin_store::StoreExt; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ShortcutBinding { + pub id: String, + pub name: String, + pub description: String, + pub default_binding: String, + pub current_binding: String, +} + +/* still handy for composing the initial JSON in the store ------------- */ +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AppSettings { + pub bindings: HashMap, + pub push_to_talk: bool, +} + +pub const SETTINGS_STORE_PATH: &str = "settings_store.json"; + +pub fn get_default_settings() -> AppSettings { + let mut bindings = HashMap::new(); + bindings.insert( + "transcribe".to_string(), + ShortcutBinding { + id: "transcribe".to_string(), + name: "Transcribe".to_string(), + description: "Converts your speech into text.".to_string(), + default_binding: "alt+space".to_string(), + current_binding: "alt+space".to_string(), + }, + ); + // bindings.insert( + // "test".to_string(), + // ShortcutBinding { + // id: "test".to_string(), + // name: "Test".to_string(), + // description: "This is a test binding.".to_string(), + // default_binding: "ctrl+d".to_string(), + // current_binding: "ctrl+d".to_string(), + // }, + // ); + + AppSettings { + bindings, + push_to_talk: true, + } +} + +pub fn load_or_create_app_settings(app: &App) -> AppSettings { + // Initialize store + let store = app + .store(SETTINGS_STORE_PATH) + .expect("Failed to initialize store"); + + let settings = if let Some(settings_value) = store.get("settings") { + // Parse the entire settings object + match serde_json::from_value::(settings_value) { + Ok(settings) => { + println!("Found existing settings: {:?}", settings); + + settings + } + Err(e) => { + println!("Failed to parse settings: {}", e); + // Fall back to default settings if parsing fails + let default_settings = get_default_settings(); + + // Store the default settings + store.set("settings", serde_json::to_value(&default_settings).unwrap()); + + default_settings + } + } + } else { + // Create default settings + let default_settings = get_default_settings(); + + // Store the settings + store.set("settings", serde_json::to_value(&default_settings).unwrap()); + + default_settings + }; + + settings +} + +pub fn get_settings(app: &AppHandle) -> AppSettings { + let store = app + .store(SETTINGS_STORE_PATH) + .expect("Failed to initialize store"); + + let settings = serde_json::from_value::(store.get("settings").unwrap()).unwrap(); + + settings +} + +pub fn write_settings(app: &AppHandle, settings: AppSettings) { + let store = app + .store(SETTINGS_STORE_PATH) + .expect("Failed to initialize store"); + + store.set("settings", serde_json::to_value(&settings).unwrap()); +} + +pub fn get_bindings(app: &AppHandle) -> HashMap { + let settings = get_settings(app); + + settings.bindings +} + +pub fn get_stored_binding(app: &AppHandle, id: &str) -> ShortcutBinding { + let bindings = get_bindings(app); + + let binding = bindings.get(id).unwrap().clone(); + + binding +} diff --git a/src-tauri/src/shortcut.rs b/src-tauri/src/shortcut.rs new file mode 100644 index 0000000..5785563 --- /dev/null +++ b/src-tauri/src/shortcut.rs @@ -0,0 +1,170 @@ +use serde::Serialize; +use tauri::{App, AppHandle, Manager}; +use tauri_plugin_global_shortcut::GlobalShortcutExt; +use tauri_plugin_global_shortcut::{Shortcut, ShortcutState}; + +use crate::actions::ACTION_MAP; +use crate::settings::ShortcutBinding; +use crate::settings::{self, get_settings}; +use crate::ManagedToggleState; + +pub fn init_shortcuts(app: &App) { + let settings = settings::load_or_create_app_settings(app); + + // Register shortcuts with the bindings from settings + for (_id, binding) in settings.bindings { + // Pass app.handle() which is &AppHandle + if let Err(e) = _register_shortcut(app.handle(), binding) { + eprintln!("Failed to register shortcut {}: {}", _id, e); + } + } +} + +#[derive(Serialize)] +pub struct BindingResponse { + success: bool, + binding: Option, + error: Option, +} + +#[tauri::command] +pub fn change_binding( + app: AppHandle, + id: String, + binding: String, +) -> Result { + let mut settings = settings::get_settings(&app); + + // Get the binding to modify + let binding_to_modify = match settings.bindings.get(&id) { + Some(binding) => binding.clone(), + None => { + return Ok(BindingResponse { + success: false, + binding: None, + error: Some(format!("Binding with id '{}' not found", id)), + }) + } + }; + + // Unregister the existing binding + if let Err(e) = _unregister_shortcut(&app, binding_to_modify.clone()) { + return Ok(BindingResponse { + success: false, + binding: None, + error: Some(format!("Failed to unregister shortcut: {}", e)), + }); + } + + // Create an updated binding + let mut updated_binding = binding_to_modify; + updated_binding.current_binding = binding; + + // Register the new binding + if let Err(e) = _register_shortcut(&app, updated_binding.clone()) { + return Ok(BindingResponse { + success: false, + binding: None, + error: Some(format!("Failed to register shortcut: {}", e)), + }); + } + + // Update the binding in the settings + settings.bindings.insert(id, updated_binding.clone()); + + // Save the settings + settings::write_settings(&app, settings); + + // Return the updated binding + Ok(BindingResponse { + success: true, + binding: Some(updated_binding), + error: None, + }) +} + +#[tauri::command] +pub fn reset_binding(app: AppHandle, id: String) -> Result { + let binding = settings::get_stored_binding(&app, &id); + + return change_binding(app, id, binding.default_binding); +} + +#[tauri::command] +pub fn change_ptt_setting(app: AppHandle, enabled: bool) -> Result<(), String> { + let mut settings = settings::get_settings(&app); + + // TODO if the setting is currently false, we probably want to + // cancel any ongoing recordings or actions + settings.push_to_talk = enabled; + + settings::write_settings(&app, settings); + + Ok(()) +} + +fn _register_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<(), String> { + // Parse shortcut and return error if it fails + let shortcut = match binding.current_binding.parse::() { + Ok(s) => s, + Err(e) => return Err(format!("Failed to parse shortcut: {}", e)), + }; + + // Clone binding.id for use in the closure + let binding_id_for_closure = binding.id.clone(); + + app.global_shortcut() + .on_shortcut(shortcut, move |ah, scut, event| { + if scut == &shortcut { + let shortcut_string = scut.into_string(); + let settings = get_settings(ah); + + if let Some(action_set) = ACTION_MAP.get(&binding_id_for_closure) { + if settings.push_to_talk { + if event.state == ShortcutState::Pressed { + (action_set.press)(ah, &shortcut_string); + } else if event.state == ShortcutState::Released { + (action_set.release)(ah, &shortcut_string); + } + } else { + if event.state == ShortcutState::Pressed { + let toggle_state_manager = ah.state::(); + + let mut states = toggle_state_manager.lock().expect("Failed to lock toggle state manager"); + + let is_currently_active = states.active_toggles.entry(binding_id_for_closure.clone()).or_insert(false); + + if *is_currently_active { + (action_set.release)(ah, &shortcut_string); + *is_currently_active = false; // Update state to inactive + } else { + (action_set.press)(ah, &shortcut_string); + *is_currently_active = true; // Update state to active + } + } + } + } else { + println!( + "Warning: No action defined in ACTION_MAP for shortcut ID '{}'. Shortcut: '{}', State: {:?}", + binding_id_for_closure, shortcut_string, event.state + ); + } + } + }) + .map_err(|e| format!("Couldn't register shortcut: {}", e))?; + + Ok(()) +} + +fn _unregister_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<(), String> { + let shortcut = match binding.current_binding.parse::() { + Ok(s) => s, + Err(e) => return Err(format!("Failed to parse shortcut: {}", e)), + }; + + app.global_shortcut() + .unregister(shortcut) + .map_err(|e| format!("Failed to unregister shortcut: {}", e))?; + + Ok(()) +} diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs new file mode 100644 index 0000000..f533628 --- /dev/null +++ b/src-tauri/src/utils.rs @@ -0,0 +1,71 @@ +use rdev::{simulate, EventType, Key, SimulateError}; +use std::thread; +use std::time; +use tauri::image::Image; +use tauri::tray::TrayIcon; +use tauri::AppHandle; +use tauri::Manager; +use tauri_plugin_clipboard_manager::ClipboardExt; + +fn try_send_event(event: &EventType) { + if let Err(SimulateError) = simulate(event) { + println!("We could not send {:?}", event); + } +} + +fn send_with_delay(event: EventType, delay_ms: u64) { + try_send_event(&event); + thread::sleep(time::Duration::from_millis(delay_ms)); +} + +fn send_paste() { + // Determine the modifier key based on the OS + #[cfg(target_os = "macos")] + let modifier_key = Key::MetaLeft; // Command key on macOS + #[cfg(not(target_os = "macos"))] + let modifier_key = Key::ControlLeft; // Control key on other systems + + // Press both keys + send_with_delay(EventType::KeyPress(modifier_key), 100); + send_with_delay(EventType::KeyPress(Key::KeyV), 100); + + // Release both keys + send_with_delay(EventType::KeyRelease(Key::KeyV), 100); + send_with_delay(EventType::KeyRelease(modifier_key), 0); +} + +pub fn paste(text: String, app_handle: AppHandle) { + let clipboard = app_handle.clipboard(); + + // get the current clipboard content + let clipboard_content = clipboard.read_text().unwrap_or_default(); + + clipboard.write_text(&text).unwrap(); + send_paste(); + + // restore the clipboard + clipboard.write_text(&clipboard_content).unwrap(); +} + +pub enum TrayIconState { + Idle, + Recording, +} + +pub fn change_tray_icon(app: &AppHandle, icon: TrayIconState) { + let tray = app.state::(); + + let icon_path = match icon { + TrayIconState::Idle => "resources/tray_idle.png", + TrayIconState::Recording => "resources/tray_recording.png", + }; + + let _ = tray.set_icon(Some( + Image::from_path( + app.path() + .resolve(icon_path, tauri::path::BaseDirectory::Resource) + .expect("failed to resolve"), + ) + .expect("failed to set icon"), + )); +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 7e64d28..1248a4b 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -13,8 +13,9 @@ "windows": [ { "title": "Handy", - "width": 800, - "height": 600 + "width": 540, + "height": 400, + "resizable": false } ], "security": { @@ -24,13 +25,15 @@ "bundle": { "active": true, "targets": "all", - "resources": ["resources/*"], + "resources": ["resources/**/*"], "icon": [ "icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", - "icons/icon.ico" + "icons/icon.ico", + "icons/tray_32x32.png", + "icons/tray_64x64.png" ], "macOS": { "files": {}, diff --git a/src/App.css b/src/App.css index 7909a38..8ba9c84 100644 --- a/src/App.css +++ b/src/App.css @@ -1,27 +1,37 @@ @import "tailwindcss"; -@font-face { - src: url("/src/assets/fonts/ShortStack-Regular.ttf"); - font-family: 'Short Stack'; - font-weight: 400; - font-style: normal; - font-display: swap; +@theme { + --color-text: #0f0f0f; + --color-background: #fbfbfb; + --color-logo-primary: #FAA2CA; + --color-logo-stroke: #382731; + --color-text-stroke: #f6f6f6; + --color-mid-gray: #808080; } :root { - font-family: 'Short Stack', sans-serif; + /* Typography */ font-size: 16px; line-height: 24px; font-weight: 400; - color: #0f0f0f; - background-color: #DACEBA; + /* Colors - Light Theme */ + /* --color-text: #0f0f0f; + --color-background: #fbfbfb; + --color-logo-primary: #FAA2CA; + --color-logo-stroke: #382731; + --color-text-stroke: #f6f6f6; */ + /* Typography settings */ font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-text-size-adjust: 100%; + + /* Apply colors */ + color: var(--color-text); + background-color: var(--color-background); } .container { @@ -35,13 +45,26 @@ @media (prefers-color-scheme: dark) { :root { - color: #f6f6f6; - background-color: #3E394B; + /* Colors - Dark Theme */ + --color-text: #fbfbfb; + --color-background: #2c2b29; + --color-logo-primary: #F28CBB; + --color-logo-stroke: #FAD1ED; } } @layer utilities { .text-stroke { - -webkit-text-stroke: 2px #f6f6f6; + -webkit-text-stroke: 2px var(--color-text-stroke); } +} + +.logo-primary { + fill: var(--color-logo-primary); +} + +.logo-stroke { + fill: var(--color-logo-stroke); + stroke: var(--color-logo-stroke); + stroke-width: 1; } \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 6526cc0..0bc85c1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,39 +1,13 @@ -import { useEffect, useState } from "react"; import "./App.css"; import { Settings } from "./components/settings/Settings"; -import { - checkAccessibilityPermissions, - requestAccessibilityPermissions, -} from "tauri-plugin-macos-permissions-api"; +import HandyTextLogo from "./components/icons/HandyTextLogo"; +import AccessibilityPermissions from "./components/AccessibilityPermissions"; function App() { - const [hasAccessibility, setHasAccessibility] = useState(false); - - useEffect(() => { - checkAccessibilityPermissions().then((hasPermissions) => { - if (!hasPermissions) { - requestAccessibilityPermissions().then((permissions) => { - setHasAccessibility(permissions); - }); - return; - } - setHasAccessibility(hasPermissions); - }); - }, []); - return ( -
- {!hasAccessibility && ( -
-
-
-

- Accessibility permissions are required for keyboard shortcuts. -

-
-
-
- )} +
+ +
); diff --git a/src/components/AccessibilityPermissions.tsx b/src/components/AccessibilityPermissions.tsx new file mode 100644 index 0000000..151a959 --- /dev/null +++ b/src/components/AccessibilityPermissions.tsx @@ -0,0 +1,97 @@ +import { useEffect, useState } from "react"; +import { + checkAccessibilityPermissions, + requestAccessibilityPermissions, +} from "tauri-plugin-macos-permissions-api"; + +// Define permission state type +type PermissionState = "request" | "verify" | "granted"; + +// Define button configuration type +interface ButtonConfig { + text: string; + className: string; +} + +const AccessibilityPermissions: React.FC = () => { + const [hasAccessibility, setHasAccessibility] = useState(false); + const [permissionState, setPermissionState] = + useState("request"); + + // Check permissions without requesting + const checkPermissions = async (): Promise => { + const hasPermissions: boolean = await checkAccessibilityPermissions(); + setHasAccessibility(hasPermissions); + setPermissionState(hasPermissions ? "granted" : "verify"); + return hasPermissions; + }; + + // Handle the unified button action based on current state + const handleButtonClick = async (): Promise => { + if (permissionState === "request") { + try { + await requestAccessibilityPermissions(); + // After system prompt, transition to verification state + setPermissionState("verify"); + } catch (error) { + console.error("Error requesting permissions:", error); + setPermissionState("verify"); + } + } else if (permissionState === "verify") { + // State is "verify" - check if permission was granted + await checkPermissions(); + } + }; + + // On app boot - check permissions + useEffect(() => { + const initialSetup = async (): Promise => { + const hasPermissions: boolean = await checkAccessibilityPermissions(); + setHasAccessibility(hasPermissions); + setPermissionState(hasPermissions ? "granted" : "request"); + }; + + initialSetup(); + }, []); + + if (hasAccessibility) { + return null; + } + + // Configure button text and style based on state + const buttonConfig: Record = { + request: { + text: "Grant", + className: + "px-2 py-1 text-sm font-semibold bg-mid-gray/10 border border-mid-gray/80 hover:bg-logo-primary/10 rounded cursor-pointer hover:border-logo-primary", + }, + verify: { + text: "Verify", + className: + "bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-1 px-3 rounded text-sm flex items-center justify-center cursor-pointer", + }, + granted: null, + }; + + const config = buttonConfig[permissionState] as ButtonConfig; + + return ( +
+
+
+

+ Please grant accessibility permissions for Handy +

+
+ +
+
+ ); +}; + +export default AccessibilityPermissions; diff --git a/src/components/icons/HandyTextLogo.tsx b/src/components/icons/HandyTextLogo.tsx new file mode 100644 index 0000000..fc41bd5 --- /dev/null +++ b/src/components/icons/HandyTextLogo.tsx @@ -0,0 +1,88 @@ +import React from "react"; + +const HandyTextLogo = ({ + width, + height, +}: { + width?: number; + height?: number; +}) => { + return ( + + + + + + + + + + + + + + ); +}; + +export default HandyTextLogo; diff --git a/src/components/icons/ResetIcon.tsx b/src/components/icons/ResetIcon.tsx new file mode 100644 index 0000000..4136118 --- /dev/null +++ b/src/components/icons/ResetIcon.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +const ResetIcon = ({ className = "" }: { className?: string }) => { + return ( + + + + ); +}; + +export default ResetIcon; diff --git a/src/components/settings/KeyboardShortcuts.tsx b/src/components/settings/KeyboardShortcuts.tsx index cd97527..dc36d03 100644 --- a/src/components/settings/KeyboardShortcuts.tsx +++ b/src/components/settings/KeyboardShortcuts.tsx @@ -1,73 +1,225 @@ -import React from "react"; - -interface Shortcut { - id: string; - name: string; - description: string; - keys: string[]; -} +import React, { useEffect, useState, useRef } from "react"; +import { load } from "@tauri-apps/plugin-store"; +import { + BindingResponseSchema, + SettingsSchema, + ShortcutBindingSchema, + ShortcutBindingsMap, +} from "../../lib/types"; +import { invoke } from "@tauri-apps/api/core"; +import keycode from "keycode"; +import ResetIcon from "../icons/ResetIcon"; export const KeyboardShortcuts: React.FC = () => { - // These would normally come from the backend configuration - const shortcuts: Shortcut[] = [ - { - id: "transcribe", - name: "Transcribe", - description: "Convert speech to text", - keys: ["⌃", "⌘"], - }, - // { - // id: 'instruct', - // name: 'AI Chat', - // description: 'Start a conversation with AI', - // keys: ['⇧', '⌥'], - // }, - // { - // id: 'code', - // name: 'Generate Code', - // description: 'Generate code from voice input', - // keys: ['⌃', '⌥', '⌘'], - // }, - ]; + const [bindings, setBindings] = React.useState({}); + const [pttEnabled, setPttEnabled] = React.useState(false); + const [keyPressed, setKeyPressed] = useState([]); + const [recordedKeys, setRecordedKeys] = useState([]); + const [editingShortcutId, setEditingShortcutId] = useState( + null + ); + const [originalBinding, setOriginalBinding] = useState(""); + const shortcutRefs = useRef>(new Map()); + + useEffect(() => { + load("settings_store.json", { autoSave: false }).then((r) => { + console.log("loaded store", r); + + r.get("settings").then((s) => { + const settings = SettingsSchema.parse(s); + setBindings(settings.bindings); + setPttEnabled(settings.push_to_talk); + }); + }); + }, []); + + useEffect(() => { + // Only add event listeners when we're in editing mode + if (editingShortcutId === null) return; + + console.log("keyPressed", keyPressed); + + // Keyboard event listeners + const handleKeyDown = (e: KeyboardEvent) => { + e.preventDefault(); + + const key = keycode(e).toLowerCase(); + console.log("You pressed", key); + + if (!keyPressed.includes(key)) { + setKeyPressed((prev) => [...prev, key]); + // Also add to recorded keys if not already there + if (!recordedKeys.includes(key)) { + setRecordedKeys((prev) => [...prev, key]); + } + } + }; + + const handleKeyUp = (e: KeyboardEvent) => { + e.preventDefault(); + + const key = keycode(e).toLowerCase(); + + // Remove from currently pressed keys + setKeyPressed((prev) => prev.filter((k) => k !== key)); + + // If no keys are pressed anymore, commit the shortcut + if (keyPressed.length === 1 && keyPressed[0] === key) { + // Create the shortcut string from all recorded keys + const newShortcut = recordedKeys.join("+"); + + if (editingShortcutId && bindings[editingShortcutId]) { + const updatedBinding = { + ...bindings[editingShortcutId], + current_binding: newShortcut, + }; + + setBindings((prev) => ({ + ...prev, + [editingShortcutId]: updatedBinding, + })); + + invoke("change_binding", { + id: editingShortcutId, + binding: newShortcut, + }); + + // Exit editing mode and reset states + setEditingShortcutId(null); + setKeyPressed([]); + setRecordedKeys([]); + setOriginalBinding(""); + } + } + }; + + // Add click outside handler + const handleClickOutside = (e: MouseEvent) => { + const activeElement = shortcutRefs.current.get(editingShortcutId); + if (activeElement && !activeElement.contains(e.target as Node)) { + // Cancel shortcut recording and restore original value + if (editingShortcutId && bindings[editingShortcutId]) { + setBindings((prev) => ({ + ...prev, + [editingShortcutId]: { + ...prev[editingShortcutId], + current_binding: originalBinding, + }, + })); + + // Reset states + setEditingShortcutId(null); + setKeyPressed([]); + setRecordedKeys([]); + setOriginalBinding(""); + } + } + }; + + window.addEventListener("keydown", handleKeyDown); + window.addEventListener("keyup", handleKeyUp); + window.addEventListener("mousedown", handleClickOutside); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + window.removeEventListener("keyup", handleKeyUp); + window.removeEventListener("mousedown", handleClickOutside); + }; + }, [keyPressed, recordedKeys, editingShortcutId, bindings, originalBinding]); + + // Start recording a new shortcut + const startRecording = (id: string) => { + // Store the original binding to restore if canceled + setOriginalBinding(bindings[id]?.current_binding || ""); + setEditingShortcutId(id); + setKeyPressed([]); + setRecordedKeys([]); + }; + + // Format the current shortcut keys being recorded + const formatCurrentKeys = () => { + return recordedKeys.length > 0 ? recordedKeys.join("+") : "Press keys..."; + }; + + // Store references to shortcut elements + const setShortcutRef = (id: string, ref: HTMLDivElement | null) => { + shortcutRefs.current.set(id, ref); + }; return (
- {shortcuts.map((shortcut) => ( +
+
+

Push To Talk

+

Hold to record, release to stop

+
+ +
+ {Object.entries(bindings).map(([id, binding]) => (
-

- {shortcut.name} -

-

{shortcut.description}

+

{binding.name}

+

{binding.description}

- {shortcut.keys.map((key, index) => ( - - - {key} - - {index < shortcut.keys.length - 1 && ( - + - )} - - ))} + {editingShortcutId === id ? ( +
setShortcutRef(id, ref)} + className="px-2 py-1 text-sm font-semibold border border-logo-primary bg-logo-primary/30 rounded min-w-[100px] text-center" + > + {formatCurrentKeys()} +
+ ) : ( +
startRecording(id)} + > + {binding.current_binding} +
+ )} +
))} - -
-
-
-

- Note: Keyboard shortcuts are currently managed by the system. - Custom configuration will be available in a future update. -

-
-
-
); }; diff --git a/src/components/settings/Settings.tsx b/src/components/settings/Settings.tsx index 215fc0d..735d4e9 100644 --- a/src/components/settings/Settings.tsx +++ b/src/components/settings/Settings.tsx @@ -4,25 +4,10 @@ import { KeyboardShortcuts } from "./KeyboardShortcuts"; export const Settings: React.FC = () => { return ( -
-
-

Settings

- - {/* AI Configuration Section */} -
-

- AI Configuration -

- {/* */} -
- - {/* Keyboard Shortcuts Section */} -
-

- Keyboard Shortcuts -

- -
+
+
+ {/*

Keyboard Shortcuts

*/} +
); diff --git a/src/lib/types.ts b/src/lib/types.ts new file mode 100644 index 0000000..08b810f --- /dev/null +++ b/src/lib/types.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; + +export const ShortcutBindingSchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string(), + default_binding: z.string(), + current_binding: z.string(), +}); + +export const ShortcutBindingsMapSchema = z.record( + z.string(), + ShortcutBindingSchema +); + +export const SettingsSchema = z.object({ + bindings: ShortcutBindingsMapSchema, + push_to_talk: z.boolean(), +}); + +export const BindingResponseSchema = z.object({ + success: z.boolean(), + binding: ShortcutBindingSchema.nullable(), + error: z.string().nullable(), +}); + +export type BindingResponse = z.infer; +export type ShortcutBinding = z.infer; +export type ShortcutBindingsMap = z.infer; +export type Settings = z.infer; diff --git a/tailwind.config.js b/tailwind.config.js index 89a305e..ed1cda1 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -5,7 +5,15 @@ export default { "./src/**/*.{js,ts,jsx,tsx}", ], theme: { - extend: {}, + extend: { + colors: { + text: 'var(--color-text)', + background: 'var(--color-background)', + 'logo-primary': 'var(--color-logo-primary)', + 'logo-stroke': 'var(--color-logo-stroke)', + 'text-stroke': 'var(--color-text-stroke)', + }, + }, }, plugins: [], } \ No newline at end of file