Compare commits

...
Author SHA1 Message Date
Brandon Thomas 2bc364ec83 enqueue events 2025-05-05 23:05:54 -04:00
Brandon Thomas 6e285f0e6c correct behavior 2025-05-05 22:47:34 -04:00
Brandon Thomas c182dd3fc0 play sound on enqueue 2025-05-05 22:30:06 -04:00
Brandon Thomas 45685500b5 set all options 2025-05-05 22:26:45 -04:00
Brandon Thomas 70c5687810 json pretty print 2025-05-05 21:44:21 -04:00
Brandon Thomas 4a970f1975 fix types 2025-05-05 21:29:44 -04:00
Brandon Thomas 0791f57e2d reset to default 2025-05-05 21:27:31 -04:00
Brandon Thomas 05d9143d7e cleanup types 2025-05-05 21:25:08 -04:00
Brandon Thomas 6c02c75c6e typesafe 2025-05-05 21:14:51 -04:00
Brandon Thomas e54a1cd219 set directory 2025-05-05 21:02:31 -04:00
Brandon Thomas 3537eb5b51 nest the types for better frontend usage 2025-05-05 20:57:18 -04:00
Brandon Thomas b232079c9c choose directory improvements 2025-05-05 20:41:16 -04:00
Brandon Thomas 162b136dca directory handling 2025-05-05 20:21:35 -04:00
Brandon Thomas 5942ae729e file picker plugin on rust and javascript side 2025-05-05 19:10:01 -04:00
Brandon Thomas 001fe39563 wip 2025-05-05 19:05:26 -04:00
Brandon Thomas 2d6d08f7b5 API calls, end-to-end settings 2025-05-05 18:43:06 -04:00
Brandon Thomas 5d4600e283 add deps 2025-05-05 17:45:06 -04:00
Brandon Thomas 4dbb10ebe9 add tauri api 2025-05-05 13:31:40 -04:00
Brandon Thomas f95ffbd7a5 tauri api lib 2025-05-05 13:29:47 -04:00
Brandon Thomas 22c08ac8cb create modal library 2025-05-05 13:29:15 -04:00
39 changed files with 1392 additions and 155 deletions
Generated
+594 -63
View File
@@ -839,6 +839,7 @@ dependencies = [
"subprocess_common",
"tauri",
"tauri-build",
"tauri-plugin-dialog",
"tauri-plugin-http",
"tauri-plugin-log",
"tauri-plugin-upload",
@@ -856,6 +857,27 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
[[package]]
name = "ashpd"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9"
dependencies = [
"enumflags2",
"futures-channel",
"futures-util",
"rand 0.8.5",
"raw-window-handle",
"serde",
"serde_repr",
"tokio",
"url",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"zbus",
]
[[package]]
name = "assert_float_eq"
version = "1.1.4"
@@ -871,6 +893,18 @@ dependencies = [
"num-traits",
]
[[package]]
name = "async-broadcast"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
dependencies = [
"event-listener 5.2.0",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-channel"
version = "1.9.0"
@@ -878,10 +912,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
dependencies = [
"concurrent-queue",
"event-listener",
"event-listener 2.5.3",
"futures-core",
]
[[package]]
name = "async-channel"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a"
dependencies = [
"concurrent-queue",
"event-listener 5.2.0",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-compression"
version = "0.4.5"
@@ -898,6 +945,84 @@ dependencies = [
"zstd-safe 7.1.0",
]
[[package]]
name = "async-io"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
dependencies = [
"async-lock",
"cfg-if 1.0.0",
"concurrent-queue",
"futures-io",
"futures-lite 2.6.0",
"parking",
"polling",
"rustix 0.38.44",
"slab",
"tracing",
"windows-sys 0.59.0",
]
[[package]]
name = "async-lock"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
dependencies = [
"event-listener 5.2.0",
"event-listener-strategy",
"pin-project-lite",
]
[[package]]
name = "async-process"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
dependencies = [
"async-channel 2.3.0",
"async-io",
"async-lock",
"async-signal",
"async-task",
"blocking",
"cfg-if 1.0.0",
"event-listener 5.2.0",
"futures-lite 2.6.0",
"rustix 0.38.44",
"tracing",
]
[[package]]
name = "async-recursion"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
]
[[package]]
name = "async-signal"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
dependencies = [
"async-io",
"async-lock",
"atomic-waker",
"cfg-if 1.0.0",
"futures-core",
"futures-io",
"rustix 0.38.44",
"signal-hook-registry",
"slab",
"windows-sys 0.59.0",
]
[[package]]
name = "async-stream"
version = "0.3.5"
@@ -944,6 +1069,12 @@ dependencies = [
"tokio",
]
[[package]]
name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
version = "0.1.80"
@@ -1012,7 +1143,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c232177ba50b16fe7a4588495bd474a62a9e45a8e4ca6fd7d0b7ac29d164631e"
dependencies = [
"nix",
"nix 0.26.4",
"rand 0.8.5",
]
@@ -1409,6 +1540,19 @@ dependencies = [
"objc2 0.6.1",
]
[[package]]
name = "blocking"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
dependencies = [
"async-channel 2.3.0",
"async-task",
"futures-io",
"futures-lite 2.6.0",
"piper",
]
[[package]]
name = "blowfish"
version = "0.9.1"
@@ -1439,7 +1583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc"
dependencies = [
"borsh-derive",
"cfg_aliases",
"cfg_aliases 0.2.1",
]
[[package]]
@@ -1997,6 +2141,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
@@ -3037,6 +3187,17 @@ dependencies = [
"serde",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
@@ -3356,6 +3517,15 @@ dependencies = [
"syn 2.0.87",
]
[[package]]
name = "dlib"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
dependencies = [
"libloading 0.8.6",
]
[[package]]
name = "dlopen2"
version = "0.7.0"
@@ -3415,6 +3585,12 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
[[package]]
name = "downcast-rs"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "download-job"
version = "0.0.1"
@@ -3786,6 +3962,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "endi"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
[[package]]
name = "enterpolation"
version = "0.2.1"
@@ -3810,6 +3992,27 @@ dependencies = [
"syn 2.0.87",
]
[[package]]
name = "enumflags2"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
]
[[package]]
name = "enums"
version = "0.0.1"
@@ -3956,6 +4159,27 @@ version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "event-listener"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
dependencies = [
"event-listener 5.2.0",
"pin-project-lite",
]
[[package]]
name = "exr"
version = "1.73.0"
@@ -4305,6 +4529,19 @@ dependencies = [
"waker-fn",
]
[[package]]
name = "futures-lite"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532"
dependencies = [
"fastrand 2.3.0",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
[[package]]
name = "futures-macro"
version = "0.3.30"
@@ -5299,9 +5536,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
dependencies = [
"anyhow",
"async-channel",
"async-channel 1.9.0",
"base64 0.13.1",
"futures-lite",
"futures-lite 1.13.0",
"http 0.2.11",
"infer 0.2.3",
"pin-project-lite",
@@ -7194,7 +7431,7 @@ dependencies = [
"gtk",
"keyboard-types",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
"once_cell",
@@ -7382,6 +7619,19 @@ dependencies = [
"pin-utils",
]
[[package]]
name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.5.0",
"cfg-if 1.0.0",
"cfg_aliases 0.1.1",
"libc",
"memoffset 0.9.0",
]
[[package]]
name = "nodrop"
version = "0.1.14"
@@ -7623,6 +7873,22 @@ dependencies = [
"objc2-exception-helper",
]
[[package]]
name = "objc2-app-kit"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
dependencies = [
"bitflags 2.5.0",
"block2 0.5.1",
"libc",
"objc2 0.5.2",
"objc2-core-data 0.2.2",
"objc2-core-image 0.2.2",
"objc2-foundation 0.2.2",
"objc2-quartz-core 0.2.2",
]
[[package]]
name = "objc2-app-kit"
version = "0.3.1"
@@ -7634,10 +7900,10 @@ dependencies = [
"libc",
"objc2 0.6.1",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-data 0.3.1",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-core-image",
"objc2-core-image 0.3.1",
"objc2-foundation 0.3.1",
"objc2-quartz-core 0.3.1",
]
@@ -7653,6 +7919,18 @@ dependencies = [
"objc2-foundation 0.3.1",
]
[[package]]
name = "objc2-core-data"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [
"bitflags 2.5.0",
"block2 0.5.1",
"objc2 0.5.2",
"objc2-foundation 0.2.2",
]
[[package]]
name = "objc2-core-data"
version = "0.3.1"
@@ -7688,6 +7966,18 @@ dependencies = [
"objc2-io-surface",
]
[[package]]
name = "objc2-core-image"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
dependencies = [
"block2 0.5.1",
"objc2 0.5.2",
"objc2-foundation 0.2.2",
"objc2-metal",
]
[[package]]
name = "objc2-core-image"
version = "0.3.1"
@@ -7721,6 +8011,7 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags 2.5.0",
"block2 0.5.1",
"dispatch",
"libc",
"objc2 0.5.2",
]
@@ -7806,7 +8097,7 @@ dependencies = [
"bitflags 2.5.0",
"block2 0.6.1",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
]
@@ -8117,6 +8408,16 @@ dependencies = [
"hashbrown 0.14.5",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "ort"
version = "1.16.3"
@@ -8127,7 +8428,6 @@ dependencies = [
"half",
"lazy_static",
"libc",
"libloading 0.7.4",
"ndarray",
"tar",
"thiserror 1.0.63",
@@ -8570,6 +8870,17 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "piper"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
"atomic-waker",
"fastrand 2.3.0",
"futures-io",
]
[[package]]
name = "pkcs1"
version = "0.7.5"
@@ -8623,6 +8934,21 @@ dependencies = [
"miniz_oxide 0.8.4",
]
[[package]]
name = "polling"
version = "3.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
dependencies = [
"cfg-if 1.0.0",
"concurrent-queue",
"hermit-abi 0.4.0",
"pin-project-lite",
"rustix 0.38.44",
"tracing",
"windows-sys 0.59.0",
]
[[package]]
name = "portable-atomic"
version = "1.10.0"
@@ -9090,6 +9416,15 @@ dependencies = [
"serde",
]
[[package]]
name = "quick-xml"
version = "0.37.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
dependencies = [
"memchr",
]
[[package]]
name = "quinn"
version = "0.11.5"
@@ -9774,6 +10109,29 @@ dependencies = [
"subtle",
]
[[package]]
name = "rfd"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e"
dependencies = [
"ashpd",
"block2 0.5.1",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"log",
"objc2 0.5.2",
"objc2-app-kit 0.2.2",
"objc2-foundation 0.2.2",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows-sys 0.48.0",
]
[[package]]
name = "rgb"
version = "0.8.50"
@@ -10017,15 +10375,15 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.34"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.5.0",
"errno",
"libc",
"linux-raw-sys 0.4.14",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -10239,6 +10597,12 @@ dependencies = [
"syn 2.0.87",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -10922,7 +11286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
dependencies = [
"bytemuck",
"cfg_aliases",
"cfg_aliases 0.2.1",
"core-graphics",
"foreign-types 0.5.0",
"js-sys",
@@ -11049,7 +11413,7 @@ dependencies = [
"crossbeam-queue",
"dotenvy",
"either",
"event-listener",
"event-listener 2.5.3",
"futures-channel",
"futures-core",
"futures-intrusive",
@@ -12057,7 +12421,7 @@ dependencies = [
"ndk-context",
"ndk-sys 0.6.0+11769913",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-foundation 0.3.1",
"once_cell",
"parking_lot 0.12.2",
@@ -12129,7 +12493,7 @@ dependencies = [
"mime",
"muda",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-foundation 0.3.1",
"percent-encoding",
"plist",
@@ -12236,6 +12600,24 @@ dependencies = [
"walkdir",
]
[[package]]
name = "tauri-plugin-dialog"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcaf6e5d6062423a0f711a23c2a573ccba222b6a16a9322d8499928f27e41376"
dependencies = [
"log",
"raw-window-handle",
"rfd",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"tauri-plugin-fs",
"thiserror 2.0.12",
"url",
]
[[package]]
name = "tauri-plugin-fs"
version = "2.2.1"
@@ -12323,47 +12705,6 @@ dependencies = [
"tokio-util",
]
[[package]]
name = "tauri-realtime"
version = "0.1.0"
dependencies = [
"anyhow",
"assertor",
"base64 0.22.1",
"bytes 1.10.0",
"chrono",
"const_format",
"crockford",
"cudarc",
"directories 6.0.0",
"dirs 6.0.0",
"filesys",
"futures 0.3.29",
"half",
"image",
"libloading 0.8.6",
"log",
"memory_caching",
"ml_models",
"ml_weights_registry",
"once_cell",
"ort",
"primitives",
"rand 0.8.5",
"reqwest 0.12.15",
"serde",
"serde_json",
"serde_yaml",
"serial_test",
"tauri",
"tauri-build",
"tauri-plugin-log",
"tempdir",
"tempfile",
"tokio",
"tokio-util",
]
[[package]]
name = "tauri-runtime"
version = "2.5.1"
@@ -12395,7 +12736,7 @@ dependencies = [
"jni",
"log",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-foundation 0.3.1",
"once_cell",
"percent-encoding",
@@ -12802,6 +13143,7 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
"tracing",
"windows-sys 0.52.0",
]
@@ -13230,7 +13572,7 @@ dependencies = [
"libappindicator",
"muda",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation 0.3.1",
@@ -13363,6 +13705,17 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "uds_windows"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
dependencies = [
"memoffset 0.9.0",
"tempfile",
"winapi 0.3.9",
]
[[package]]
name = "ug"
version = "0.1.0"
@@ -14019,6 +14372,66 @@ dependencies = [
"web-sys",
]
[[package]]
name = "wayland-backend"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121"
dependencies = [
"cc",
"downcast-rs",
"rustix 0.38.44",
"scoped-tls",
"smallvec 1.13.2",
"wayland-sys",
]
[[package]]
name = "wayland-client"
version = "0.31.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61"
dependencies = [
"bitflags 2.5.0",
"rustix 0.38.44",
"wayland-backend",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols"
version = "0.32.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a"
dependencies = [
"bitflags 2.5.0",
"wayland-backend",
"wayland-client",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.31.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484"
dependencies = [
"proc-macro2",
"quick-xml 0.37.5",
"quote",
]
[[package]]
name = "wayland-sys"
version = "0.31.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615"
dependencies = [
"dlib",
"log",
"pkg-config",
]
[[package]]
name = "web-sys"
version = "0.3.65"
@@ -14230,7 +14643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
dependencies = [
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
"raw-window-handle",
@@ -14919,7 +15332,7 @@ dependencies = [
"libc",
"ndk 0.9.0",
"objc2 0.6.1",
"objc2-app-kit",
"objc2-app-kit 0.3.1",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
"objc2-ui-kit",
@@ -14989,7 +15402,17 @@ checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
dependencies = [
"libc",
"linux-raw-sys 0.4.14",
"rustix 0.38.34",
"rustix 0.38.44",
]
[[package]]
name = "xdg-home"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
@@ -15016,6 +15439,65 @@ dependencies = [
"synstructure",
]
[[package]]
name = "zbus"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ff46f2a25abd690ed072054733e0bc3157e3d4c45f41bd183dce09c2ff8ab9"
dependencies = [
"async-broadcast",
"async-process",
"async-recursion",
"async-trait",
"derivative",
"enumflags2",
"event-listener 5.2.0",
"futures-core",
"futures-sink",
"futures-util",
"hex",
"nix 0.28.0",
"ordered-stream",
"rand 0.8.5",
"serde",
"serde_repr",
"sha1 0.10.6",
"static_assertions",
"tokio",
"tracing",
"uds_windows",
"windows-sys 0.52.0",
"xdg-home",
"zbus_macros",
"zbus_names",
"zvariant",
]
[[package]]
name = "zbus_macros"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e0e3852c93dcdb49c9462afe67a2a468f7bd464150d866e861eaf06208633e0"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"regex",
"syn 1.0.109",
"zvariant_utils 1.1.0",
]
[[package]]
name = "zbus_names"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
dependencies = [
"serde",
"static_assertions",
"zvariant",
]
[[package]]
name = "zerocopy"
version = "0.7.33"
@@ -15268,3 +15750,52 @@ checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
dependencies = [
"zune-core",
]
[[package]]
name = "zvariant"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
dependencies = [
"endi",
"enumflags2",
"serde",
"static_assertions",
"url",
"zvariant_derive",
]
[[package]]
name = "zvariant_derive"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.87",
"zvariant_utils 2.1.0",
]
[[package]]
name = "zvariant_utils"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "zvariant_utils"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
]
-1
View File
@@ -25,7 +25,6 @@ members = [
# Desktop apps
"crates/desktop/artcraft",
"crates/desktop/tauri-realtime",
# Shared libraries
"crates/lib/actix_cors_configs",
+1
View File
@@ -67,6 +67,7 @@ tauri-plugin-http = { path = "../../vendor/tauri-plugin-http" }
# NB: The version of the `discord-rich-presence` crate (0.2.5) last published has non-Send/Sync error
# types and can't do threading. We need to wait for a new version to unpin from Git.
discord-rich-presence = { git = "https://github.com/vionya/discord-rich-presence" }
tauri-plugin-dialog = "2"
[dev-dependencies]
libloading = "0.8.6"
@@ -25,6 +25,7 @@
"url": "https://private.tauri.app"
}
]
}
},
"dialog:default"
]
}
@@ -14,8 +14,18 @@ pub struct GetAppPreferencesResponse {
pub struct AppPreferencesPayload {
/// The downloads directory to use when a user downloads a file.
pub preferred_download_directory: PreferredDownloadDirectory,
/// Play sounds on events.
pub play_sounds: bool,
/// Key pointing to file; defined in the frontend code.
pub generation_success_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_failure_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_enqueue_sound: Option<String>,
}
@@ -42,5 +52,8 @@ async fn get_prefs(app_prefs: &AppPreferencesManager) -> AnyhowResult<AppPrefere
Ok(AppPreferencesPayload {
preferred_download_directory: prefs.preferred_download_directory,
play_sounds: prefs.play_sounds,
generation_success_sound: prefs.generation_success_sound,
generation_failure_sound: prefs.generation_failure_sound,
generation_enqueue_sound: prefs.generation_enqueue_sound,
})
}
@@ -1,8 +1,10 @@
use crate::state::app_preferences::app_preferences_manager::AppPreferencesManager;
use crate::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
use crate::state::data_dir::app_data_root::AppDataRoot;
use anyhow::anyhow;
use errors::AnyhowResult;
use log::{error, info};
use openai_sora_client::sora_error::SoraError::AnyhowError;
use serde_derive::{Deserialize, Serialize};
use tauri::{AppHandle, State};
@@ -11,7 +13,15 @@ use tauri::{AppHandle, State};
pub struct UpdateAppPreferencesRequest {
pub preference: PreferenceName,
/// We'll decode this with respect to the preference value.
pub value: String,
pub value: Option<ValueType>,
}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub enum ValueType {
Bool(bool),
String(String),
DownloadDirectory(PreferredDownloadDirectory),
}
#[derive(Deserialize)]
@@ -19,6 +29,9 @@ pub struct UpdateAppPreferencesRequest {
pub enum PreferenceName {
PreferredDownloadDirectory,
PlaySounds,
GenerationSuccessSound,
GenerationFailureSound,
GenerationEnqueueSound,
}
#[derive(Serialize)]
@@ -26,7 +39,6 @@ pub struct UpdateAppPreferencesResponse {
pub success: bool,
}
#[tauri::command]
pub async fn update_app_preferences_command(
request: UpdateAppPreferencesRequest,
@@ -54,12 +66,39 @@ async fn update_prefs(
) -> AnyhowResult<()> {
let mut prefs = app_prefs.get_clone()?;
info!("Value is: {:?}", request.value);
match request.preference {
PreferenceName::PreferredDownloadDirectory => {
prefs.preferred_download_directory = request.value.parse::<PreferredDownloadDirectory>()?;
match request.value {
Some(ValueType::DownloadDirectory(dir)) =>
prefs.preferred_download_directory = dir,
_ =>
return Err(anyhow!("Invalid value: {:?}", request.value)),
}
}
PreferenceName::PlaySounds => {
prefs.play_sounds = request.value.parse::<bool>()?;
match request.value {
Some(ValueType::Bool(val)) =>
prefs.play_sounds = val,
_ =>
return Err(anyhow!("Invalid value: {:?}", request.value)),
}
}
PreferenceName::GenerationSuccessSound => {
prefs.generation_success_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
PreferenceName::GenerationFailureSound => {
prefs.generation_failure_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
PreferenceName::GenerationEnqueueSound => {
prefs.generation_enqueue_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
}
@@ -68,3 +107,10 @@ async fn update_prefs(
Ok(())
}
fn string_value(value: &ValueType) -> AnyhowResult<String> {
match value {
ValueType::String(val) => Ok(val.to_string()),
_ => Err(anyhow!("Invalid value type: {:?}", value)),
}
}
@@ -21,13 +21,23 @@ use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages};
use openai_sora_client::requests::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
use openai_sora_client::requests::upload::upload_media_from_bytes::sora_media_upload_from_bytes;
use openai_sora_client::requests::upload::upload_media_from_file::sora_media_upload_from_file;
use serde_derive::Deserialize;
use serde_derive::{Deserialize, Serialize};
use std::fs::read_to_string;
use std::io::Cursor;
use storyteller_client::media_files::get_media_file::get_media_file;
use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, Manager, State};
use tauri::{AppHandle, Emitter, Manager, State};
use tokens::tokens::media_files::MediaFileToken;
use crate::threads::sora_task_polling_thread::SoraImageGenerationComplete;
#[derive(Debug, Clone, Serialize)]
pub struct SoraImageEnqueueFailure {
// TODO: Reason.
}
#[derive(Debug, Clone, Serialize)]
pub struct SoraImageEnqueueSuccess {
}
#[derive(Deserialize)]
pub struct SoraImageRemixCommand {
@@ -48,7 +58,7 @@ pub struct SoraImageRemixCommand {
#[tauri::command]
pub async fn sora_image_remix_command(
_app: AppHandle,
app: AppHandle,
request: SoraImageRemixCommand,
app_data_root: State<'_, AppDataRoot>,
sora_creds_manager: State<'_, SoraCredentialManager>,
@@ -60,12 +70,23 @@ pub async fn sora_image_remix_command(
// TODO(bt,2025-04-24): Better error messages to caller
generate_image(request, &app_data_root, &sora_creds_manager, &sora_task_queue)
.await
.map_err(|err| {
error!("error: {:?}", err);
"there was an error".to_string()
})?;
let result = generate_image(request, &app_data_root, &sora_creds_manager, &sora_task_queue).await;
if let Err(err) = result {
error!("error: {:?}", err);
let result = app.emit("sora-image-enqueue-failure", SoraImageEnqueueFailure{});
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
}
return Err("there was an error".to_string());
}
let result = app.emit("sora-image-enqueue-success", SoraImageEnqueueSuccess{});
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
}
Ok("success".to_string())
}
+5 -1
View File
@@ -7,11 +7,12 @@ pub mod utils;
use tauri::Manager;
use crate::commands::flip_image::flip_image;
use crate::commands::app_preferences::get_app_preferences_command::get_app_preferences_command;
use crate::commands::app_preferences::update_app_preference_command::update_app_preferences_command;
use crate::commands::platform_info_command::platform_info_command;
use crate::commands::sora::open_sora_login_command::open_sora_login_command;
use crate::commands::sora::sora_image_generation_command::sora_image_generation_command;
use crate::commands::sora::sora_image_remix_command::sora_image_remix_command;
use crate::commands::app_preferences::get_app_preferences_command::get_app_preferences_command;
use crate::state::data_dir::app_data_root::AppDataRoot;
use crate::state::main_window_size::MainWindowSize;
use crate::state::sora::sora_credential_manager::SoraCredentialManager;
@@ -25,6 +26,7 @@ use crate::utils::webview_unsafe::webview_unsafe_for_app;
use crate::state::app_preferences::app_preferences_manager::load_app_preferences_or_default;
use tauri_plugin_http;
use tauri_plugin_dialog;
use tauri_plugin_log::Target;
use tauri_plugin_log::TargetKind;
@@ -54,6 +56,7 @@ pub fn run() {
println!("Initializing backend runtime...");
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_upload::init())
.plugin(tauri_plugin_log::Builder::new()
@@ -119,6 +122,7 @@ pub fn run() {
.invoke_handler(tauri::generate_handler![
flip_image,
get_app_preferences_command,
update_app_preferences_command,
open_sora_login_command,
platform_info_command,
sora_image_generation_command,
@@ -1,5 +1,5 @@
use crate::state::app_preferences::app_preferences_serializable::AppPreferencesSerializable;
use crate::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
use crate::state::app_preferences::preferred_download_directory::{PreferredDownloadDirectory, SystemDownloadDirectory};
use crate::state::data_dir::app_data_root::AppDataRoot;
#[derive(Clone)]
@@ -9,13 +9,26 @@ pub struct AppPreferences {
/// Play sounds on events.
pub play_sounds: bool,
/// Key pointing to file; defined in the frontend code.
pub generation_success_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_failure_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_enqueue_sound: Option<String>,
}
impl Default for AppPreferences {
fn default() -> Self {
Self {
preferred_download_directory: PreferredDownloadDirectory::SystemDefault,
preferred_download_directory: PreferredDownloadDirectory::System(SystemDownloadDirectory::Downloads),
play_sounds: true,
// NB: These are defined in the frontend.
generation_success_sound: Some("flower".to_string()),
generation_failure_sound: Some("crumble".to_string()),
generation_enqueue_sound: Some("done".to_string()),
}
}
}
@@ -42,9 +55,6 @@ impl AppPreferences {
}
pub fn to_serializable(&self) -> AppPreferencesSerializable {
AppPreferencesSerializable {
preferred_download_directory: Some(self.preferred_download_directory.clone()),
play_sounds: Some(self.play_sounds),
}
AppPreferencesSerializable::from_preferences(self)
}
}
@@ -4,13 +4,28 @@ use crate::state::data_dir::app_data_root::AppDataRoot;
use errors::AnyhowResult;
use serde_derive::{Deserialize, Serialize};
/// Vector clock versioning string rather than semver.
const CURRENT_VERSION: &str = "1";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppPreferencesSerializable {
/// Versioning string.
pub version: String,
/// The downloads directory to use when a user downloads a file.
pub preferred_download_directory: Option<PreferredDownloadDirectory>,
/// Play sounds on events.
pub play_sounds: Option<bool>,
/// Key pointing to file; defined in the frontend code.
pub generation_success_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_failure_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_enqueue_sound: Option<String>,
}
impl AppPreferencesSerializable {
@@ -25,11 +40,15 @@ impl AppPreferencesSerializable {
Ok(Some(data))
}
pub fn save_to_file(&self, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
let filename = app_data_root.settings_dir().get_app_preferences_path();
let json = serde_json::to_string(self)?;
std::fs::write(filename, json)?;
Ok(())
pub fn from_preferences(preferences: &AppPreferences) -> Self {
Self {
version: CURRENT_VERSION.to_string(),
preferred_download_directory: Some(preferences.preferred_download_directory.clone()),
play_sounds: Some(preferences.play_sounds),
generation_success_sound: preferences.generation_success_sound.clone(),
generation_failure_sound: preferences.generation_failure_sound.clone(),
generation_enqueue_sound: preferences.generation_enqueue_sound.clone(),
}
}
pub fn to_preferences(&self) -> AppPreferences {
@@ -43,6 +62,10 @@ impl AppPreferencesSerializable {
preferences.play_sounds = play_sounds;
}
preferences.generation_success_sound = self.generation_success_sound.clone();
preferences.generation_failure_sound = self.generation_failure_sound.clone();
preferences.generation_enqueue_sound = self.generation_enqueue_sound.clone();
preferences
}
}
@@ -6,28 +6,34 @@ use std::str::FromStr;
const SYSTEM_DEFAULT_SENTINEL_VALUE: &str = "system_default";
/// NB: The reason these are not flat is so that they serialize/deserialize nicely to/from JSON.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum PreferredDownloadDirectory {
/// The system-default downloads directory, which varies by OS.
/// NB: Serializes as `"system_default"` in JSON.
SystemDefault,
System(SystemDownloadDirectory),
/// A user-defined path
/// NB: Serializes as `{"custom": "/path/to/dir"}` in JSON.
Custom(PathBuf),
}
impl FromStr for PreferredDownloadDirectory {
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum SystemDownloadDirectory {
Downloads,
Documents,
}
impl FromStr for SystemDownloadDirectory {
type Err = AnyhowError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == SYSTEM_DEFAULT_SENTINEL_VALUE || s == "\"system_default\"" {
Ok(PreferredDownloadDirectory::SystemDefault)
} else {
// TODO: If it gets serialized as JSON, we may need to remove the `{"custom": ...` wrapping layer.
let path = PathBuf::from(s);
Ok(PreferredDownloadDirectory::Custom(path))
match (s) {
"downloads" => Ok(SystemDownloadDirectory::Downloads),
"documents" => Ok(SystemDownloadDirectory::Documents),
_ => Err(AnyhowError::msg(format!("Invalid system download directory: {}", s))),
}
}
}
@@ -35,17 +41,25 @@ impl FromStr for PreferredDownloadDirectory {
impl Display for PreferredDownloadDirectory {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PreferredDownloadDirectory::SystemDefault => write!(f, "{}", SYSTEM_DEFAULT_SENTINEL_VALUE),
PreferredDownloadDirectory::System(system) => system.fmt(f),
PreferredDownloadDirectory::Custom(path) => write!(f, "{}", path.to_string_lossy()),
}
}
}
impl Display for SystemDownloadDirectory {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SystemDownloadDirectory::Downloads => write!(f, "downloads"),
SystemDownloadDirectory::Documents => write!(f, "documents"),
}
}
}
#[cfg(test)]
mod tests {
use crate::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
use std::path::PathBuf;
use crate::state::app_preferences::preferred_download_directory::SystemDownloadDirectory;
use std::str::FromStr;
mod json {
@@ -53,9 +67,9 @@ mod tests {
#[test]
fn to_json_system_default() {
let val = PreferredDownloadDirectory::SystemDefault;
let val = PreferredDownloadDirectory::System(SystemDownloadDirectory::Documents);
let val = serde_json::to_string(&val).unwrap();
assert_eq!(&val, "\"system_default\"");
assert_eq!(&val, "{\"system\":\"documents\"}");
}
#[test]
@@ -65,36 +79,4 @@ mod tests {
assert_eq!(&val, "{\"custom\":\"/tmp\"}");
}
}
mod string {
use super::*;
#[test]
fn to_string_system_default() {
let val = PreferredDownloadDirectory::SystemDefault;
let val = val.to_string();
assert_eq!(&val, "system_default");
}
#[test]
fn to_string_custom() {
let val = PreferredDownloadDirectory::Custom("/tmp/foo".into());
let val = val.to_string();
assert_eq!(&val, "/tmp/foo");
}
}
#[test]
fn from_string_system_default() {
let val = "system_default";
let val = PreferredDownloadDirectory::from_str(val).unwrap();
assert_eq!(val, PreferredDownloadDirectory::SystemDefault);
}
#[test]
fn from_string_custom() {
let val = "/tmp/foo";
let val = PreferredDownloadDirectory::from_str(val).unwrap();
assert_eq!(val, PreferredDownloadDirectory::Custom(PathBuf::from("/tmp/foo")));
}
}
@@ -1,6 +1,7 @@
use crate::state::app_preferences::app_preferences::AppPreferences;
use crate::state::data_dir::trait_data_subdir::DataSubdir;
use errors::AnyhowResult;
use serde::Serialize;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::{Path, PathBuf};
@@ -33,8 +34,12 @@ impl AppSettingsDir {
pub fn write_app_preferences(&self, prefs: &AppPreferences) -> AnyhowResult<()> {
let serializable = prefs.to_serializable();
let serializable = serde_json::to_string(&serializable)?;
let formatter = serde_json::ser::PrettyFormatter::with_indent(b" ");
let mut buf = Vec::new();
let mut ser = serde_json::Serializer::with_formatter(&mut buf, formatter);
serializable.serialize(&mut ser)?;
let filename = self.get_app_preferences_path();
let mut file = OpenOptions::new()
@@ -43,7 +48,7 @@ impl AppSettingsDir {
.truncate(true)
.open(filename)?;
file.write_all(serializable.as_bytes())?;
file.write_all(&buf)?;
file.flush()?;
Ok(())
@@ -1,14 +1,15 @@
import { SoundRegistry, SoundEffect } from "@storyteller/soundboard";
// TODO: This is maintained in two places. Here and MiscSettingsPane.
export const InstallSounds = () => {
const r = SoundRegistry.getInstance();
if (r.hasSound("fail")) {
if (r.hasSound("crumble")) {
return;
}
r.setSoundOnce("success", new SoundEffect("resources/sound/smrpg_flower.wav"));
r.setSoundOnce("bingo", new SoundEffect("resources/sound/smrpg_correct.wav"));
r.setSoundOnce("flower", new SoundEffect("resources/sound/smrpg_flower.wav"));
r.setSoundOnce("correct", new SoundEffect("resources/sound/smrpg_correct.wav"));
r.setSoundOnce("next", new SoundEffect("resources/sound/oot_dialogue_next.wav", { defaultVolume: 1.0 }));
r.setSoundOnce("done", new SoundEffect("resources/sound/oot_dialogue_done.wav", { defaultVolume: 1.0 }));
r.setSoundOnce("fail", new SoundEffect("resources/sound/smrpg_drybones_crumble.wav", { defaultVolume: 0.5 }));
r.setSoundOnce("crumble", new SoundEffect("resources/sound/smrpg_drybones_crumble.wav", { defaultVolume: 0.5 }));
(window as any).sounds = r;
}
@@ -13,5 +13,8 @@
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"dependencies": {
"@tauri-apps/plugin-dialog": "^2.2.1"
}
}
@@ -0,0 +1,234 @@
import { useEffect, useState } from "react";
import { SoundRegistry, SoundEffect } from "@storyteller/soundboard";
import { Button } from "@storyteller/ui-button";
import { Input } from "@storyteller/ui-input";
import { AppPreferencesPayload, CustomDirectory, GetAppPreferences, SystemDirectory } from "@storyteller/tauri-api";
import { PreferenceName, UpdateAppPreferences } from "libs/tauri-api/src/lib/settings/UpdateAppPreference";
import { open } from '@tauri-apps/plugin-dialog';
import { Select, SelectValue } from "libs/components/select/src/lib/select";
// TODO: This is maintained in two places. Here and InstallSounds.
const SOUND_OPTIONS = [
{ value: "none", label: "None (Silent)" },
{ value: "flower", label: "Flower" },
{ value: "correct", label: "Correct" },
{ value: "next", label: "Next" },
{ value: "done", label: "Done" },
{ value: "crumble", label: "Crumble" },
];
interface MiscSettingsPaneProps {
}
export const MiscSettingsPane = (args: MiscSettingsPaneProps) => {
const [preferences, setPreferences] = useState<AppPreferencesPayload|undefined>(undefined);
useEffect(() => {
const fetchData = async () => {
const prefs = await GetAppPreferences();
console.log("prefs", prefs)
setPreferences(prefs.preferences);
}
fetchData();
}, []);
// NB: This might be a complex type.
const outerDownloadObject = preferences?.preferred_download_directory || {};
const downloadDirectory = ("custom" in outerDownloadObject) ? outerDownloadObject.custom as string : "";
const currentDownloadLabel = ("system" in outerDownloadObject) ? "System Download Directory" : downloadDirectory;
const playSounds = preferences?.play_sounds || false;
const successSound = orNone(preferences?.generation_success_sound); // ? preferences?.generation_success_sound : "none";
const failureSound = orNone(preferences?.generation_failure_sound); // ? preferences?.generation_failure_sound : "none";
const enqueueSound = orNone(preferences?.generation_enqueue_sound); // ? preferences?.generation_enqueue_sound : "none";
const reloadPreferences = async () => {
const prefs = await GetAppPreferences();
console.log("prefs", prefs)
setPreferences(prefs.preferences);
}
const setPlaySounds = async (checked: boolean) => {
//const value = checked ? "true" : "false";
await UpdateAppPreferences({
preference: PreferenceName.PlaySounds,
value: checked,
});
await reloadPreferences();
}
const openDirectoryPicker = async () => {
let directory = await open({
multiple: false,
directory: true,
defaultPath: downloadDirectory || undefined,
});
if (directory === null) {
return; // User dismissed the dialog choice
}
await UpdateAppPreferences({
preference: PreferenceName.PreferredDownloadDirectory,
value: {
custom: directory
} as CustomDirectory,
});
await reloadPreferences();
}
const clearDirectory = async () => {
await UpdateAppPreferences({
preference: PreferenceName.PreferredDownloadDirectory,
value: {
system: "downloads"
} as SystemDirectory,
});
await reloadPreferences();
}
const setSuccessSound = async (val: string) => {
let sendVal = val === "none" ? undefined : val;
await UpdateAppPreferences({
preference: PreferenceName.GenerationSuccessSound,
value: sendVal,
});
SoundRegistry.getInstance().playSound(val);
await reloadPreferences();
}
const setFailureSound = async (val: string) => {
let sendVal = val === "none" ? undefined : val;
await UpdateAppPreferences({
preference: PreferenceName.GenerationFailureSound,
value: sendVal,
});
SoundRegistry.getInstance().playSound(val);
await reloadPreferences();
}
const setEnqueueSound = async (val: string) => {
let sendVal = val === "none" ? undefined : val;
await UpdateAppPreferences({
preference: PreferenceName.GenerationEnqueueSound,
value: sendVal,
});
SoundRegistry.getInstance().playSound(val);
await reloadPreferences();
}
const playSound = (val?: string) => {
if (val !== undefined && val !== "none") {
SoundRegistry.getInstance().playSound(val);
}
}
return (<>
<div className="space-y-4">
<div>
<label htmlFor="download-path" className="mb-2 block">
Default Download Directory
</label>
This is where downloads are placed after downloading.
The current path is <pre>{currentDownloadLabel}</pre>
<Button
variant="primary"
className="py-1"
onClick={openDirectoryPicker}
>
Choose Directory
</Button>
<Button
variant="secondary"
className="py-1"
onClick={clearDirectory}
>
Use Default
</Button>
</div>
<div>
<label htmlFor="play-sounds" className="mb-2 block">
Play Notification Sounds for Events?
</label>
<Input
id="play-sounds"
type="checkbox"
checked={playSounds}
onChange={(e) => setPlaySounds((e.target as any).checked)}
/>
</div>
<div>
<label htmlFor="success-sound" className="mb-2 block">
Success Sound
</label>
<Select
id="success-sound"
value={successSound}
onChange={(val: SelectValue) =>
setSuccessSound(val as string)
}
options={SOUND_OPTIONS}
/>
<Button
variant="secondary"
className="py-1"
onClick={() => playSound(successSound)}
>
Play
</Button>
</div>
<div>
<label htmlFor="failure-sound" className="mb-2 block">
Failure Sound
</label>
<Select
id="failure-sound"
value={failureSound}
onChange={(val: SelectValue) =>
setFailureSound(val as string)
}
options={SOUND_OPTIONS}
/>
<Button
variant="secondary"
className="py-1"
onClick={() => playSound(failureSound)}
>
Play
</Button>
</div>
<div>
<label htmlFor="enqueue-sound" className="mb-2 block">
Enqueue Sound
</label>
<Select
id="enqueue-sound"
value={enqueueSound}
onChange={(val: SelectValue) =>
setEnqueueSound(val as string)
}
options={SOUND_OPTIONS}
/>
<Button
variant="secondary"
className="py-1"
onClick={() => playSound(enqueueSound)}
>
Play
</Button>
</div>
</div>
</>)
}
const orNone = (val: string | undefined | null) : string => {
if (!!!val) {
return "none";
}
return val;
}
@@ -11,6 +11,7 @@ import {
import { twMerge } from "tailwind-merge";
import { Input } from "@storyteller/ui-input";
import { Select, SelectValue } from "@storyteller/ui-select";
import { MiscSettingsPane } from "./MiscSettingsPane";
interface SettingsModalProps {
isOpen: boolean;
@@ -23,7 +24,7 @@ interface AccountInfo {
credits: number;
}
type SettingsSection = "accounts" | "video" | "image" | "misc";
type SettingsSection = "misc" | "accounts" | "video" | "image";
export const SettingsModal = ({ isOpen, onClose }: SettingsModalProps) => {
const [accountInfo] = useState<AccountInfo>({
@@ -33,17 +34,18 @@ export const SettingsModal = ({ isOpen, onClose }: SettingsModalProps) => {
});
const [selectedSection, setSelectedSection] =
useState<SettingsSection>("accounts");
useState<SettingsSection>("misc");
const [palApiKey, setPalApiKey] = useState("");
const [klingApiKey, setKlingApiKey] = useState("");
const [defaultVideoModel, setDefaultVideoModel] = useState("veo");
const [humanVideoProvider, setHumanVideoProvider] = useState("artcraft");
const sections = [
{ id: "misc" as const, label: "Misc", icon: faCog },
{ id: "accounts" as const, label: "Accounts", icon: faUser },
{ id: "video" as const, label: "Video", icon: faVideo },
{ id: "image" as const, label: "Image", icon: faImage },
{ id: "misc" as const, label: "Misc", icon: faCog },
];
const renderContent = () => {
@@ -157,15 +159,13 @@ export const SettingsModal = ({ isOpen, onClose }: SettingsModalProps) => {
case "image":
return (
<div>
<button className="text-blue-600">Various Image Settings...</button>
<button className="text-blue-600">Various Image Settings (TODO)...</button>
</div>
);
case "misc":
return (
<div>
<button className="text-blue-600">Other Settings...</button>
</div>
<MiscSettingsPane />
);
}
};
@@ -14,6 +14,18 @@
{
"path": "../modal"
},
{
"path": "../../api"
},
{
"path": "../../tauri-api"
},
{
"path": "../../tauri-utils"
},
{
"path": "../../soundboard"
},
{
"path": "./tsconfig.lib.json"
},
@@ -54,6 +54,18 @@
},
{
"path": "../modal/tsconfig.lib.json"
}
},
{
"path": "../../api/tsconfig.lib.json"
},
{
"path": "../../tauri-api/tsconfig.lib.json"
},
{
"path": "../../tauri-utils/tsconfig.lib.json"
},
{
"path": "../../soundboard/tsconfig.lib.json"
},
]
}
+12
View File
@@ -0,0 +1,12 @@
{
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}
+36
View File
@@ -0,0 +1,36 @@
{
"extends": [
"plugin:@nx/react",
"../../.eslintrc.json"
],
"ignorePatterns": [
"!**/*",
"**/vite.config.*.timestamp*",
"**/vitest.config.*.timestamp*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}
+7
View File
@@ -0,0 +1,7 @@
# @frontend/tauri-api
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test @frontend/tauri-api` to execute the unit tests via [Vitest](https://vitest.dev/).
+20
View File
@@ -0,0 +1,20 @@
{
"name": "@storyteller/tauri-api",
"version": "0.0.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"development": "./src/index.ts",
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"dependencies": {
"@tauri-apps/api": "^2.5.0"
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from './lib/settings/GetAppPreferences.js';
@@ -0,0 +1,36 @@
import { invoke } from "@tauri-apps/api/core";
export interface GetAppPreferencesResult {
preferences: AppPreferencesPayload,
}
export interface AppPreferencesPayload {
// Preferred download directory
preferred_download_directory: PreferredDownloadDirectory,
// Play sounds on events.
play_sounds: boolean,
// Sound names to play.
// These are keys, not filenames, and are defined by the frontend.
generation_success_sound?: string,
generation_failure_sound?: string,
generation_enqueue_sound?: string,
}
export type PreferredDownloadDirectory = SystemDirectory | CustomDirectory;
export interface SystemDirectory {
// If the directory is a system directory.
system: string,
}
export interface CustomDirectory {
// If the directory is a custom user directory.
custom: string,
}
export const GetAppPreferences = async () : Promise<GetAppPreferencesResult> => {
let result = await invoke("get_app_preferences_command");
return (result as GetAppPreferencesResult);
}
@@ -0,0 +1,30 @@
import { invoke } from "@tauri-apps/api/core";
import { PreferredDownloadDirectory } from "./GetAppPreferences";
export interface UpdateAppPreferencesRequest {
preference: PreferenceName,
value: undefined | string | boolean | PreferredDownloadDirectory,
}
export enum PreferenceName {
PreferredDownloadDirectory = "preferred_download_directory",
PlaySounds = "play_sounds",
GenerationSuccessSound = "generation_success_sound",
GenerationFailureSound = "generation_failure_sound",
GenerationEnqueueSound = "generation_enqueue_sound",
}
export interface UpdateAppPreferencesResult {
success: boolean
}
export const UpdateAppPreferences = async (request: UpdateAppPreferencesRequest) : Promise<UpdateAppPreferencesResult> => {
let result = await invoke("update_app_preferences_command", {
request: {
preference: request.preference,
value: request.value,
}
});
return (result as UpdateAppPreferencesResult);
}
+1
View File
@@ -0,0 +1 @@
// This file should be used to export ONLY server-code from the library.
@@ -0,0 +1,3 @@
import { installGlobals } from '@remix-run/node';
import "@testing-library/jest-dom/matchers";
installGlobals();
+13
View File
@@ -0,0 +1,13 @@
{
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"extends": "../../tsconfig.base.json"
}
+48
View File
@@ -0,0 +1,48 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts",
"vite/client"
],
"rootDir": "src",
"jsx": "react-jsx",
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
},
"exclude": [
"out-tsc",
"dist",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"eslint.config.js",
"eslint.config.cjs",
"eslint.config.mjs"
],
"include": [
"src/**/*.js",
"src/**/*.jsx",
"src/**/*.ts",
"src/**/*.tsx"
]
}
@@ -0,0 +1,34 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./out-tsc/vitest",
"types": [
"vitest/globals",
"vitest/importMeta",
"vite/client",
"node",
"vitest"
],
"jsx": "react-jsx"
},
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
+49
View File
@@ -0,0 +1,49 @@
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import dts from 'vite-plugin-dts';
import * as path from 'path';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/libs/tauri-api',
plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })],
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
outDir: './dist',
emptyOutDir: true,
reportCompressedSize: true,
commonjsOptions: {
transformMixedEsModules: true,
},
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: '@frontend/tauri-api',
fileName: 'index',
// Change this to the formats you want to support.
// Don't forget to update your package.json as well.
formats: ['es' as const]
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: ['react','react-dom','react/jsx-runtime']
},
},
test: {setupFiles: ['./src/test-setup.ts'],
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: './test-output/vitest/coverage',
provider: 'v8' as const,
}
},
}));
+3
View File
@@ -13,5 +13,8 @@
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"dependencies": {
"@tauri-apps/plugin-http": "^2.4.3"
}
}
@@ -0,0 +1,2 @@
export const TEST = 1;
@@ -0,0 +1,2 @@
export * from './GetAppPreferences';
@@ -1,2 +1,3 @@
export * from './api';
export { FetchProxy } from './FetchProxy';
export { IsDesktopApp } from './IsDesktopApp';
export { FetchProxy } from './FetchProxy';
+31 -5
View File
@@ -2225,7 +2225,10 @@
},
"libs/components/settings-modal": {
"name": "@storyteller/ui-settings-modal",
"version": "0.0.1"
"version": "0.0.1",
"dependencies": {
"@tauri-apps/plugin-dialog": "^2.2.1"
}
},
"libs/components/tab-selector": {
"name": "@storyteller/ui-tab-selector",
@@ -2253,9 +2256,19 @@
"@types/howler": "^2.2.12"
}
},
"libs/tauri-api": {
"name": "@storyteller/tauri-api",
"version": "0.0.1",
"dependencies": {
"@tauri-apps/api": "^2.5.0"
}
},
"libs/tauri-utils": {
"name": "@storyteller/tauri-utils",
"version": "0.0.1"
"version": "0.0.1",
"dependencies": {
"@tauri-apps/plugin-http": "^2.4.3"
}
},
"node_modules/@adobe/css-tools": {
"version": "4.4.2",
@@ -10267,6 +10280,10 @@
"resolved": "libs/soundboard",
"link": true
},
"node_modules/@storyteller/tauri-api": {
"resolved": "libs/tauri-api",
"link": true
},
"node_modules/@storyteller/tauri-utils": {
"resolved": "libs/tauri-utils",
"link": true
@@ -10924,9 +10941,9 @@
}
},
"node_modules/@tauri-apps/api": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.4.1.tgz",
"integrity": "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.5.0.tgz",
"integrity": "sha512-Ldux4ip+HGAcPUmuLT8EIkk6yafl5vK0P0c0byzAKzxJh7vxelVtdPONjfgTm96PbN24yjZNESY8CKo8qniluA==",
"license": "Apache-2.0 OR MIT",
"funding": {
"type": "opencollective",
@@ -11150,6 +11167,15 @@
"node": ">= 10"
}
},
"node_modules/@tauri-apps/plugin-dialog": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.2.1.tgz",
"integrity": "sha512-wZmCouo4PgTosh/UoejPw9DPs6RllS5Pp3fuOV2JobCu36mR5AXU2MzU9NZiVaFi/5Zfc8RN0IhcZHnksJ1o8A==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.0.0"
}
},
"node_modules/@tauri-apps/plugin-http": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.4.3.tgz",
+3
View File
@@ -62,6 +62,9 @@
},
{
"path": "./libs/soundboard"
},
{
"path": "./libs/tauri-api"
}
]
}
+10
View File
@@ -5,6 +5,7 @@
"packages": {
"": {
"dependencies": {
"@tauri-apps/plugin-dialog": "^2.2.1",
"@tauri-apps/plugin-upload": "^2.2.1"
},
"devDependencies": {
@@ -238,6 +239,15 @@
"node": ">= 10"
}
},
"node_modules/@tauri-apps/plugin-dialog": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.2.1.tgz",
"integrity": "sha512-wZmCouo4PgTosh/UoejPw9DPs6RllS5Pp3fuOV2JobCu36mR5AXU2MzU9NZiVaFi/5Zfc8RN0IhcZHnksJ1o8A==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.0.0"
}
},
"node_modules/@tauri-apps/plugin-upload": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-upload/-/plugin-upload-2.2.1.tgz",
+1
View File
@@ -3,6 +3,7 @@
"@tauri-apps/cli": "^2.5.0"
},
"dependencies": {
"@tauri-apps/plugin-dialog": "^2.2.1",
"@tauri-apps/plugin-upload": "^2.2.1"
}
}