From a6f9f83141ef81a7cd817c8b677f7be4a82a5227 Mon Sep 17 00:00:00 2001 From: Brage Fuglseth <91388039+bragefuglseth@users.noreply.github.com> Date: Mon, 23 Dec 2024 02:06:37 +0100 Subject: [PATCH] Add Discord RPC support If someone has Discord and Keypunch open at the same time, their Keypunch activity will now show up in Discord using its rich presence API. For some reason, Builder doesn't like the new folder access requirements, so I've added a new one that grants access to the specific folders needed to do this. --- Cargo.lock | 575 +++- Cargo.toml | 1 + ....bragefuglseth.Keypunch.DiscordAccess.json | 86 + data/discord-rpc-artwork.svg | 2392 +++++++++++++++++ src/application.rs | 11 +- src/discord_rpc.rs | 145 + src/main.rs | 2 + src/session_enums.rs | 69 + src/text_generation.rs | 2 +- src/widgets/window.rs | 53 +- src/widgets/window/session.rs | 36 + src/widgets/window/ui_state.rs | 42 +- 12 files changed, 3236 insertions(+), 178 deletions(-) create mode 100644 build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json create mode 100644 data/discord-rpc-artwork.svg create mode 100644 src/discord_rpc.rs create mode 100644 src/session_enums.rs diff --git a/Cargo.lock b/Cargo.lock index dd0d352..9f7524e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" @@ -41,11 +41,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + [[package]] name = "cairo-rs" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a0ea147c94108c9613235388f540e4d14c327f7081c9e471fc8ee8a2533e69" +checksum = "ae50b5510d86cf96ac2370e66d8dc960882f3df179d6a5a1e52bd94a1416c0f7" dependencies = [ "bitflags", "cairo-sys-rs", @@ -55,9 +61,9 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.20.0" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428290f914b9b86089f60f5d8a9f6e440508e1bcff23b25afd51502b0a2da88f" +checksum = "f18b6bb8e43c7eb0f2aac7976afe0c61b6f5fc2ab7bc4c139537ea56c92290df" dependencies = [ "glib-sys", "libc", @@ -66,18 +72,18 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.21" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "shlex", ] [[package]] name = "cfg-expr" -version = "0.16.0" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345c78335be0624ed29012dc10c49102196c6882c12dde65d9f35b02da2aada8" +checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" dependencies = [ "smallvec", "target-lexicon", @@ -89,6 +95,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 = "crc32fast" version = "1.4.2" @@ -98,11 +110,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -119,9 +140,32 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "discord-presence" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff5c60b76a2455bad4e7eef0f8a9eca0c450c112c64a7b38ef24f569f4f4f88c" +dependencies = [ + "byteorder", + "bytes", + "cfg-if", + "crossbeam-channel", + "named_pipe", + "num-derive", + "num-traits", + "parking_lot", + "paste", + "quork", + "serde", + "serde_json", + "thiserror 2.0.9", + "tracing", + "uuid", +] [[package]] name = "either" @@ -153,9 +197,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -163,24 +207,24 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -189,15 +233,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -206,15 +250,15 @@ dependencies = [ [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", @@ -226,9 +270,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8730751991b97419fc3f0c2dca2c9e45b48edf46e48e0f965964ecf33889812f" +checksum = "b6efc7705f7863d37b12ad6974cbb310d35d054f5108cdc1e69037742f573c4c" dependencies = [ "gdk-pixbuf-sys", "gio", @@ -238,9 +282,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffbf649fd5b1c8c0f0feeb015b7533c3ef92da2887fb95ddd338bc2b1644a7c" +checksum = "67f2587c9202bf997476bbba6aaed4f78a11538a2567df002a5f57f5331d0b5c" dependencies = [ "gio-sys", "glib-sys", @@ -251,9 +295,9 @@ dependencies = [ [[package]] name = "gdk4" -version = "0.9.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7d7237c1487ed4b300aac7744efcbf1319e12d60d7afcd6f505414bd5b5dea" +checksum = "d0196720118f880f71fe7da971eff58cc43a89c9cf73f46076b7cb1e60889b15" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -266,9 +310,9 @@ dependencies = [ [[package]] name = "gdk4-sys" -version = "0.9.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67576c8ec012156d7f680e201a807b4432a77babb3157e0555e990ab6bcd878" +checksum = "60b0e1340bd15e7a78810cf39fed9e5d85f0a8f80b1d999d384ca17dcc452b60" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -304,9 +348,9 @@ dependencies = [ [[package]] name = "gettext-rs" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6716b8a0db461a2720b850ba1623e5b69e4b1aa0224cf5e1fb23a0fe49e65c" +checksum = "a44e92f7dc08430aca7ed55de161253a22276dfd69c5526e5c5e95d1f7cf338a" dependencies = [ "gettext-sys", "locale_config", @@ -324,9 +368,9 @@ dependencies = [ [[package]] name = "gio" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcacaa37401cad0a95aadd266bc39c72a131d454fc012f6dfd217f891d76cc52" +checksum = "a517657589a174be9f60c667f1fec8b7ac82ed5db4ebf56cf073a3b5955d8e2e" dependencies = [ "futures-channel", "futures-core", @@ -341,22 +385,22 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.20.1" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5237611e97e9b86ab5768adc3eef853ae713ea797aa3835404acdfacffc9fb38" +checksum = "8446d9b475730ebef81802c1738d972db42fde1c5a36a627ebc4d665fc87db04" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "glib" -version = "0.20.3" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95648aac01b75503000bb3bcaa5ec7a7a2dd61e43636b8b1814854de94dd80e4" +checksum = "f969edf089188d821a30cde713b6f9eb08b20c63fc2e584aba2892a7984a8cc0" dependencies = [ "bitflags", "futures-channel", @@ -375,9 +419,9 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.20.3" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302f1d633c9cdef4350330e7b68fd8016e2834bb106c93fdf9789fcde753c1ab" +checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" dependencies = [ "heck", "proc-macro-crate", @@ -388,9 +432,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.20.2" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92eee4531c1c9abba945d19378b205031b5890e1f99c319ba0503b6e0c06a163" +checksum = "b360ff0f90d71de99095f79c526a5888c9c92fc9ee1b19da06c6f5e75f0c2a53" dependencies = [ "libc", "system-deps", @@ -398,9 +442,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3d1dcd8a1eb2e7c22be3d5e792b14b186f3524f79b25631730f9a8c169d49a" +checksum = "67a56235e971a63bfd75abb13ef70064e1346388723422a68580d8a6fbac6423" dependencies = [ "glib-sys", "libc", @@ -409,9 +453,9 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80aac87f74e81c0e13433e892a047237abdc37945c86887f5eed905038356e69" +checksum = "f39d3bcd2e24fd9c2874a56f277b72c03e728de9bdc95a8d4ef4c962f10ced98" dependencies = [ "glib", "graphene-sys", @@ -420,9 +464,9 @@ dependencies = [ [[package]] name = "graphene-sys" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2f91ecd32989efad60326cc20a8fb252bd2852239a08e4e70cde8c100de9ca" +checksum = "11a68d39515bf340e879b72cecd4a25c1332557757ada6e8aba8654b4b81d23a" dependencies = [ "glib-sys", "libc", @@ -432,9 +476,9 @@ dependencies = [ [[package]] name = "gsk4" -version = "0.9.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3cf2091e1af185b347b3450817d93dea6fe435df7abd4c2cd7fb5bcb4cfda8" +checksum = "32b9188db0a6219e708b6b6e7225718e459def664023dbddb8395ca1486d8102" dependencies = [ "cairo-rs", "gdk4", @@ -447,9 +491,9 @@ dependencies = [ [[package]] name = "gsk4-sys" -version = "0.9.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa69614a26d8760c186c3690f1b0fbb917572ca23ef83137445770ceddf8cde" +checksum = "bca10fc65d68528a548efa3d8747934adcbe7058b73695c9a7f43a25352fce14" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -463,9 +507,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fe572bf318e5dbc6f5a2f8a25d853f1ae3f42768c0b08af6ca20a18f4057e1" +checksum = "b697ff938136625f6acf75f01951220f47a45adcf0060ee55b4671cf734dac44" dependencies = [ "cairo-rs", "field-offset", @@ -484,9 +528,9 @@ dependencies = [ [[package]] name = "gtk4-macros" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e7b362c8fccd2712297903717d65d30defdab2b509bc9d209cbe5ffb9fabaf" +checksum = "0ed1786c4703dd196baf7e103525ce0cf579b3a63a0570fe653b7ee6bac33999" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -496,9 +540,9 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.9.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1114a207af8ada02cf4658a76692f4190f06f093380d5be07e3ca8b43aa7c666" +checksum = "3af4b680cee5d2f786a2f91f1c77e95ecf2254522f0ca4edf3a2dce6cb35cecf" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -542,9 +586,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -558,7 +602,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f249c6dcfe2e8403f0e309da6f6b552dcfb607b094b5038db0709f8010fa4ea0" dependencies = [ - "gettext-rs 0.7.1", + "gettext-rs 0.7.2", "quote", ] @@ -583,9 +627,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -593,14 +637,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "keypunch" version = "0.1.0" dependencies = [ + "discord-presence", "gettext-rs 0.6.0", "gtk4", "gvdb-macros", @@ -623,9 +668,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libadwaita" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ff9c222b5c783729de45185f07b2fec2d43a7f9c63961e777d3667e20443878" +checksum = "8611ee9fb85e7606c362b513afcaf5b59853f79e4d98caaaf581d99465014247" dependencies = [ "gdk4", "gio", @@ -638,9 +683,9 @@ dependencies = [ [[package]] name = "libadwaita-sys" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c44d8bdbad31d6639e1f20cc9c1424f1a8e02d751fc28d44659bf743fb9eca6" +checksum = "b099a223560118d4d4fa04b6d23f3ea5b7171fe1d83dfb7e6b45b54cdfc83af9" dependencies = [ "gdk4-sys", "gio-sys", @@ -654,9 +699,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "litrs" @@ -680,6 +725,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -706,13 +761,54 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] +[[package]] +name = "named_pipe" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9c443cce91fc3e12f017290db75dde490d685cdaaf508d7159d7cf41f0eb2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "objc" version = "0.2.7" @@ -742,11 +838,17 @@ dependencies = [ "objc", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "pango" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5764e5a174a5a0ec054fe5962ce6d4fc7052e2d0dcc23bbc77202b40a4a403d3" +checksum = "9e89bd74250a03a05cec047b43465469102af803be2bf5e5a1088f8b8455e087" dependencies = [ "gio", "glib", @@ -756,9 +858,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.20.1" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd317e1de76b14b3d3efe05518c08b360327f1ab7fec150473a89ffcad4b072d" +checksum = "71787e0019b499a5eda889279e4adb455a4f3fdd6870cd5ab7f4a5aa25df6699" dependencies = [ "glib-sys", "gobject-sys", @@ -766,11 +868,40 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -780,9 +911,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "ppv-lite86" @@ -802,25 +933,74 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" -version = "0.36.1" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", "serde", ] +[[package]] +name = "quork" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b223192745155c4f425d5c0ac0f5e18ae8a58721ebccb5f9709d18009af108ee" +dependencies = [ + "cc", + "cfg-if", + "nix", + "quork-proc", + "thiserror 1.0.69", + "windows", +] + +[[package]] +name = "quork-proc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5deb881b55a330d22f00f08963b89b240553c2d88841fa35f100858e552eb73" +dependencies = [ + "proc-macro-crate", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.37" @@ -880,11 +1060,20 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -894,9 +1083,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -905,9 +1094,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc_version" @@ -920,9 +1109,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -939,26 +1128,32 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -967,9 +1162,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -979,9 +1174,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1034,9 +1229,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", @@ -1045,9 +1240,9 @@ dependencies = [ [[package]] name = "system-deps" -version = "7.0.2" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "070a0a5e7da2d24be457809c4b3baa57a835fd2829ad8b86f9a049052fe71031" +checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" dependencies = [ "cfg-expr", "heck", @@ -1064,9 +1259,49 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "temp-dir" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f227968ec00f0e5322f9b8173c7a0cbcff6181a0a5b28e9892491c286277231" +checksum = "bc1ee6eef34f12f765cb94725905c6312b6610ab2b0940889cfe58dae7bc3c72" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl 2.0.9", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "toml" @@ -1091,9 +1326,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.21" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -1102,11 +1337,42 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" @@ -1120,6 +1386,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", +] + [[package]] name = "version-compare" version = "0.2.0" @@ -1164,7 +1439,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1174,10 +1449,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ "windows-targets", ] @@ -1257,9 +1576,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 52ce02f..51113b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +discord-presence = "1.4.1" gettext-rs = { version = "0.6", features = ["gettext-system"] } gvdb-macros = "0.1.12" i18n-format = "0.2.0" diff --git a/build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json b/build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json new file mode 100644 index 0000000..1b7d83a --- /dev/null +++ b/build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json @@ -0,0 +1,86 @@ +{ + "id" : "dev.bragefuglseth.Keypunch.Devel", + "runtime" : "org.gnome.Platform", + "runtime-version" : "master", + "sdk" : "org.gnome.Sdk", + "sdk-extensions" : [ + { + "id" : "org.freedesktop.Sdk.Extension.rust-stable", + "version" : "24.08" + } + ], + "command" : "keypunch-wrapper.sh", + "finish-args" : [ + "--share=network", + "--share=ipc", + "--socket=fallback-x11", + "--device=dri", + "--socket=wayland", + "--filesystem=xdg-run/app/com.discordapp.Discord:create", + "--env=RUST_BACKTRACE=1" + ], + "build-options" : { + "append-path" : "/usr/lib/sdk/rust-stable/bin", + "build-args" : [ + "--share=network" + ], + "env" : { + "RUST_BACKTRACE" : "1", + "RUST_LOG" : "keypunch=debug" + } + }, + "cleanup" : [ + "/include", + "/lib/pkgconfig", + "/man", + "/share/doc", + "/share/gtk-doc", + "/share/man", + "/share/pkgconfig", + "*.la", + "*.a" + ], + "modules" : [ + { + "name": "blueprint-compiler", + "buildsystem": "meson", + "cleanup": ["*"], + "sources": [ + { + "type": "git", + "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler", + "tag": "v0.14.0" + } + ] + }, + { + "name" : "keypunch-wrapper", + "buildsystem" : "simple", + "build-commands" : [ + "install -Dm755 keypunch-wrapper.sh /app/bin/keypunch-wrapper.sh" + ], + "sources" : [ + { + "type" : "script", + "dest-filename" : "keypunch-wrapper.sh", + "commands" : [ + "for i in {0..9}; do\ntest -S $XDG_RUNTIME_DIR/discord-ipc-$i || ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-$i;\ndone", + "keypunch" + ] + } + ] + }, + { + "name" : "keypunch", + "builddir" : true, + "buildsystem" : "meson", + "run-tests" : true, + "sources" : [ + { + "type" : "dir", + "path" : ".." + } + ] + } + ] +} diff --git a/data/discord-rpc-artwork.svg b/data/discord-rpc-artwork.svg new file mode 100644 index 0000000..5ba944f --- /dev/null +++ b/data/discord-rpc-artwork.svg @@ -0,0 +1,2392 @@ + + + +20+10+30+40+50+60+70+80+90+100+110+120+130+140+150+160+170+180+190+200+0+ diff --git a/src/application.rs b/src/application.rs index 8357e9e..7ebf413 100644 --- a/src/application.rs +++ b/src/application.rs @@ -18,6 +18,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +use crate::discord_rpc::RpcWrapper; use adw::subclass::prelude::*; use gtk::prelude::*; use gtk::{gio, glib}; @@ -27,8 +28,10 @@ use crate::widgets::KpWindow; mod imp { use super::*; - #[derive(Debug, Default)] - pub struct KpApplication {} + #[derive(Default)] + pub struct KpApplication { + pub discord_rpc: RpcWrapper, + } #[glib::object_subclass] impl ObjectSubclass for KpApplication { @@ -95,4 +98,8 @@ impl KpApplication { self.add_action_entries(actions); } + + pub fn discord_rpc(&self) -> &RpcWrapper { + &self.imp().discord_rpc + } } diff --git a/src/discord_rpc.rs b/src/discord_rpc.rs new file mode 100644 index 0000000..a894d25 --- /dev/null +++ b/src/discord_rpc.rs @@ -0,0 +1,145 @@ +use crate::session_enums::*; +use discord_presence::models::rich_presence::Activity; +use discord_presence::Client; +use std::sync::mpsc; +use std::sync::mpsc::Sender; +use std::thread; +use std::time::SystemTime; + +const DISCORD_CLIENT_ID: u64 = 1320106636743802923; + +enum RpcMessage { + SendStored, + Change(SessionType, SessionDuration, PresenceState), + UpdateStats(f64, f64), +} + +pub struct RpcWrapper { + sender: Sender, +} + +impl Default for RpcWrapper { + fn default() -> Self { + let (sender, receiver) = mpsc::channel(); + + let sender_clone = sender.clone(); + + thread::spawn(move || { + let start_time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .map(|d| d.as_millis() as u64); + + let mut stored_activity = Activity::new(); + let mut stored_stats: Option<(f64, f64)> = None; // WPM & accuracy + + let mut client = Client::new(DISCORD_CLIENT_ID); + + client + .on_connected(move |_ctx| { + sender_clone + .send(RpcMessage::SendStored) + .expect("channel exists until app shuts down"); + }) + .persist(); + + client.start(); + + for msg in receiver.iter() { + if let RpcMessage::Change(session_type, duration, state) = msg { + let details_string = match session_type { + SessionType::Simple => format!("Simple, {}", duration.english_string()), + SessionType::Advanced => format!("Advanced, {}", duration.english_string()), + SessionType::Custom => "Custom text".to_string(), + }; + + stored_activity = Activity::new() + .state(state.english_string()) + .details(details_string); + } else if let RpcMessage::UpdateStats(wpm, accuracy) = msg { + stored_stats = Some((wpm, accuracy)); + } + + if let Some(time) = start_time { + stored_activity = stored_activity.timestamps(|t| t.start(time)); + } + + if let Some((wpm, accuracy)) = stored_stats { + let display_accuracy = (accuracy * 100.).floor() as usize; + + stored_activity = stored_activity.assets(|a| { + a.large_image("main") + .large_text("Keypunch") + .small_image(wpm_to_image(wpm)) + .small_text(format!( + "{:.0} WPM, {:.0}% correctness", + wpm.floor(), display_accuracy + )) + }); + } else { + stored_activity = + stored_activity.assets(|a| a.large_image("main").large_text("Keypunch")); + }; + + let _ = client.set_activity(|mut a| { + a.clone_from(&stored_activity); + a + }); + } + }); + + RpcWrapper { sender } + } +} + +impl RpcWrapper { + pub fn set_activity( + &self, + session_type: SessionType, + duration: SessionDuration, + state: PresenceState, + ) { + self.sender + .send(RpcMessage::Change(session_type, duration, state)) + .expect("channel exists until app shuts down"); + } + + pub fn set_stats(&self, wpm: f64, accuracy: f64) { + self.sender + .send(RpcMessage::UpdateStats(wpm, accuracy)) + .expect("channel exists until app shuts down"); + } +} + +fn wpm_to_image(wpm: f64) -> &'static str { + const WPM_IMAGES: &'static [(f64, &'static str)] = &[ + (10., "0-wpm"), + (20., "10-wpm"), + (30., "20-wpm"), + (40., "30-wpm"), + (50., "40-wpm"), + (60., "50-wpm"), + (70., "60-wpm"), + (80., "70-wpm"), + (90., "80-wpm"), + (100., "90-wpm"), + (110., "100-wpm"), + (120., "110-wpm"), + (130., "120-wpm"), + (140., "130-wpm"), + (150., "140-wpm"), + (160., "150-wpm"), + (170., "160-wpm"), + (180., "170-wpm"), + (190., "180-wpm"), + (200., "190-wpm"), + ]; + + for (threshold, image) in WPM_IMAGES { + if wpm < *threshold { + return image; + } + } + + "200-wpm" +} diff --git a/src/main.rs b/src/main.rs index 5a96b19..6645e18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,8 @@ mod application; mod config; +mod discord_rpc; +mod session_enums; mod text_generation; mod text_utils; mod widgets; diff --git a/src/session_enums.rs b/src/session_enums.rs new file mode 100644 index 0000000..46e4862 --- /dev/null +++ b/src/session_enums.rs @@ -0,0 +1,69 @@ +use gettextrs::gettext; +use strum_macros::{Display as EnumDisplay, EnumIter, EnumString}; + +#[derive(Clone, Copy, Default, PartialEq, EnumString, EnumDisplay, EnumIter)] +pub enum SessionType { + #[default] + Simple, + Advanced, + Custom, +} + +impl SessionType { + pub fn ui_string(&self) -> String { + match self { + SessionType::Simple => gettext("Simple"), + SessionType::Advanced => gettext("Advanced"), + SessionType::Custom => gettext("Custom"), + } + } +} + +#[derive(Copy, Clone, Default, PartialEq, EnumString, EnumDisplay, EnumIter)] +pub enum SessionDuration { + #[default] + Sec15, + Sec30, + Min1, + Min5, + Min10, +} + +impl SessionDuration { + pub fn ui_string(&self) -> String { + match self { + SessionDuration::Sec15 => gettext("15 seconds"), + SessionDuration::Sec30 => gettext("30 seconds"), + SessionDuration::Min1 => gettext("1 minute"), + SessionDuration::Min5 => gettext("5 minutes"), + SessionDuration::Min10 => gettext("10 minutes"), + } + } + + pub fn english_string(&self) -> &str { + match self { + SessionDuration::Sec15 => "15 seconds", + SessionDuration::Sec30 => "30 seconds", + SessionDuration::Min1 => "1 minute", + SessionDuration::Min5 => "5 minutes", + SessionDuration::Min10 => "10 minutes", + } + } +} + +#[derive(Copy, Clone)] +pub enum PresenceState { + Ready, + Typing, + Results, +} + +impl PresenceState { + pub fn english_string(&self) -> &str { + match self { + PresenceState::Ready => "Ready to start", + PresenceState::Typing => "Typing", + PresenceState::Results => "Viewing results", + } + } +} diff --git a/src/text_generation.rs b/src/text_generation.rs index e7ae0a8..3893516 100644 --- a/src/text_generation.rs +++ b/src/text_generation.rs @@ -264,7 +264,7 @@ pub fn advanced(language: Language) -> String { " ", GENERIC_PUNCTUATION, WESTERN_ARABIC_NUMERALS, - ) + ), } } diff --git a/src/widgets/window.rs b/src/widgets/window.rs index 91e697e..5247a61 100644 --- a/src/widgets/window.rs +++ b/src/widgets/window.rs @@ -25,6 +25,7 @@ mod settings; mod ui_state; use crate::config::APP_ID; +use crate::session_enums::*; use crate::text_generation::Language; use crate::widgets::{KpResultsView, KpTextView}; use adw::prelude::*; @@ -33,47 +34,6 @@ use gettextrs::gettext; use gtk::{gio, glib}; use std::cell::{Cell, OnceCell, RefCell}; use std::time::{Duration, Instant}; -use strum_macros::{Display as EnumDisplay, EnumIter, EnumString}; - -#[derive(Clone, Copy, Default, PartialEq, EnumString, EnumDisplay, EnumIter)] -pub enum SessionType { - #[default] - Simple, - Advanced, - Custom, -} - -impl SessionType { - pub fn ui_string(&self) -> String { - match self { - SessionType::Simple => gettext("Simple"), - SessionType::Advanced => gettext("Advanced"), - SessionType::Custom => gettext("Custom"), - } - } -} - -#[derive(Copy, Clone, Default, PartialEq, EnumString, EnumDisplay, EnumIter)] -pub enum SessionDuration { - #[default] - Sec15, - Sec30, - Min1, - Min5, - Min10, -} - -impl SessionDuration { - pub fn ui_string(&self) -> String { - match self { - SessionDuration::Sec15 => gettext("15 seconds"), - SessionDuration::Sec30 => gettext("30 seconds"), - SessionDuration::Min1 => gettext("1 minute"), - SessionDuration::Min5 => gettext("5 minutes"), - SessionDuration::Min10 => gettext("10 minutes"), - } - } -} mod imp { use super::*; @@ -186,8 +146,6 @@ mod imp { self.setup_continue_button(); self.setup_ui_hiding(); self.show_cursor(); - - self.ready(); } } impl WidgetImpl for KpWindow {} @@ -264,9 +222,12 @@ glib::wrapper! { impl KpWindow { pub fn new>(application: &P) -> Self { - glib::Object::builder() + let obj: KpWindow = glib::Object::builder() .property("application", application) - .build() + .build(); + + obj.imp().ready(); + + obj } } - diff --git a/src/widgets/window/session.rs b/src/widgets/window/session.rs index 0fb04bf..0013eac 100644 --- a/src/widgets/window/session.rs +++ b/src/widgets/window/session.rs @@ -1,4 +1,5 @@ use super::*; +use crate::application::KpApplication; use crate::text_generation; use crate::text_utils::{calculate_accuracy, calculate_wpm, process_custom_text, GraphemeState}; use crate::widgets::{KpCustomTextDialog, KpTextLanguageDialog}; @@ -150,6 +151,19 @@ impl imp::KpWindow { self.text_view.set_original_text(&new_original); self.secondary_config_stack .set_visible_child(&config_widget); + + // Discord IPC + self.obj() + .application() + .expect("ready() isn't called before window has been paired with application") + .downcast_ref::() + .unwrap() + .discord_rpc() + .set_activity( + self.session_type.get(), + self.duration.get(), + PresenceState::Ready, + ); } pub(super) fn update_time(&self) { @@ -161,6 +175,19 @@ impl imp::KpWindow { self.settings() .set_string("session-duration", &selected.to_string()) .unwrap(); + + // Discord IPC + self.obj() + .application() + .expect("ready() isn't called before window has been paired with application") + .downcast_ref::() + .unwrap() + .discord_rpc() + .set_activity( + self.session_type.get(), + self.duration.get(), + PresenceState::Ready, + ); } pub(super) fn show_text_language_dialog(&self) { @@ -473,6 +500,15 @@ impl imp::KpWindow { } ), ); + + // Discord IPC + self.obj() + .application() + .expect("ready() isn't called before window has been paired with application") + .downcast_ref::() + .unwrap() + .discord_rpc() + .set_stats(wpm, accuracy); } } diff --git a/src/widgets/window/ui_state.rs b/src/widgets/window/ui_state.rs index 0212609..9d4a255 100644 --- a/src/widgets/window/ui_state.rs +++ b/src/widgets/window/ui_state.rs @@ -1,4 +1,5 @@ use super::*; +use crate::application::KpApplication; impl imp::KpWindow { pub(super) fn setup_stop_button(&self) { @@ -105,6 +106,19 @@ impl imp::KpWindow { self.obj().action_set_enabled("win.cancel-session", false); self.obj().remove_css_class("hide-controls"); + // Discord IPC + self.obj() + .application() + .expect("ready() isn't called before window has been paired with application") + .downcast_ref::() + .unwrap() + .discord_rpc() + .set_activity( + self.session_type.get(), + self.duration.get(), + PresenceState::Ready, + ); + self.end_existing_inhibit(); } @@ -133,7 +147,7 @@ impl imp::KpWindow { imp.stop_button.set_opacity(1.); } } - ) + ), ); match self.session_type.get() { @@ -146,6 +160,19 @@ impl imp::KpWindow { self.obj().action_set_enabled("win.cancel-session", true); self.obj().add_css_class("hide-controls"); + // Discord IPC + self.obj() + .application() + .expect("ready() isn't called before window has been paired with application") + .downcast_ref::() + .unwrap() + .discord_rpc() + .set_activity( + self.session_type.get(), + self.duration.get(), + PresenceState::Typing, + ); + // Translators: This is shown as a warning by GNOME Shell before logging out or shutting off the system in the middle of a typing session, alongside Keypunch's name and icon self.inhibit_session(&gettext("Ongoing typing session")) } @@ -167,6 +194,19 @@ impl imp::KpWindow { self.obj().action_set_enabled("win.cancel-session", false); self.end_existing_inhibit(); + + // Discord IPC + self.obj() + .application() + .expect("ready() isn't called before window has been paired with application") + .downcast_ref::() + .unwrap() + .discord_rpc() + .set_activity( + self.session_type.get(), + self.duration.get(), + PresenceState::Results, + ); } pub(super) fn hide_cursor(&self) {