From c909c10a2edcc562257cf188a6af3e4239e29b2f Mon Sep 17 00:00:00 2001 From: Francesco Saverio Cannizzaro Date: Sat, 14 Jan 2023 00:38:21 +0100 Subject: [PATCH 1/3] update pull-item settings ui --- property-inspector/src/actions/pull-item.tsx | 64 +++++++++----------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/property-inspector/src/actions/pull-item.tsx b/property-inspector/src/actions/pull-item.tsx index c17145e..531adf5 100644 --- a/property-inspector/src/actions/pull-item.tsx +++ b/property-inspector/src/actions/pull-item.tsx @@ -1,4 +1,5 @@ import { + Box, Button, Divider, Group, @@ -19,7 +20,7 @@ export default () => { setGlobalSettings, } = useStreamDeck(); if (!settings.altActionTrigger) { - setSettings({ altActionTrigger: "double" }); + setSettings({ altActionTrigger: "long" }); } if (!settings.altAction) { setSettings({ altAction: "equip" }); @@ -52,44 +53,33 @@ export default () => { )} - {/* alt action settings */} - {settings.item && ( - + + {/* alt action settings */} + {settings.item && ( + + + - {"Equip"} + Equip - - setSettings({ altActionTrigger }) - } - > - - Double Press - Hold - - - {/* this section will be useful when theres desire for alternate actions than equip - - setSettings({ altAction })} - data={resources.map((it) => ({ - value: it.value, - label: ( - - {it.label} - - ), - }))} - /> */} - - )} - + + (Alternative Action) + + + + setSettings({ altActionTrigger }) + } + > + + Double Press + Hold + + + + )} Date: Sat, 14 Jan 2023 00:42:57 +0100 Subject: [PATCH 2/3] update sdk + refactor --- rust/Cargo.toml | 2 +- rust/src/actions/authorization.rs | 8 ++-- rust/src/actions/farming_mode.rs | 17 ++++---- rust/src/actions/loadout.rs | 29 +++++++++----- rust/src/actions/max_power.rs | 53 +++++++++++++------------ rust/src/actions/metrics.rs | 60 +++++++++++++++++----------- rust/src/actions/open_dim.rs | 14 ++++--- rust/src/actions/postmaster.rs | 66 ++++++++++++++++--------------- rust/src/actions/pull_item.rs | 53 ++++++++++++++++--------- rust/src/actions/randomize.rs | 2 +- rust/src/actions/refresh.rs | 3 +- rust/src/actions/search.rs | 25 +++++++----- rust/src/actions/vault.rs | 42 ++++++++++---------- rust/src/dim/events_recv.rs | 55 +++++++++++++------------- rust/src/global_settings.rs | 4 +- rust/src/main.rs | 49 +++++++++++------------ rust/src/server.rs | 61 ++++++++++++++++++++++------ rust/src/shared.rs | 6 ++- rust/src/util.rs | 5 ++- 19 files changed, 323 insertions(+), 231 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ea8e466..cedb22a 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,7 +12,7 @@ futures = "0.3" futures-util = "0.3" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.21.2", features = ["full"] } -stream_deck_sdk = { version="1.0.2", features = ["download", "images"] } # path="../../../rust/sdk" +stream_deck_sdk = { version="1.0.3", features = ["download", "images"] } # path="../../../rust/sdk" warp = "0.3.3" skia-safe = "0.57.0" tokio-stream = "0.1.11" diff --git a/rust/src/actions/authorization.rs b/rust/src/actions/authorization.rs index 2ae8c5b..e272161 100644 --- a/rust/src/actions/authorization.rs +++ b/rust/src/actions/authorization.rs @@ -1,7 +1,8 @@ +use std::collections::HashMap; + use async_trait::async_trait; use serde::Serialize; -use serde_json::{Map, Value}; -use std::collections::HashMap; +use serde_json::Value; use stream_deck_sdk::action::Action; use stream_deck_sdk::events::events::SendToPluginEvent; use stream_deck_sdk::stream_deck::StreamDeck; @@ -26,7 +27,6 @@ impl Action for AuthorizationAction { async fn on_send_to_plugin(&self, e: SendToPluginEvent, sd: StreamDeck) { if e.payload.contains_key("resetAll") { let mut changes: HashMap = HashMap::default(); - changes.insert("tokens".to_string(), Value::Object(Map::new())); changes.insert("missing".to_string(), Value::Array(vec![])); sd.update_global_settings(changes, Some(true)).await; return; @@ -49,6 +49,6 @@ impl Action for AuthorizationAction { code: e.payload.get("code").unwrap().as_str().unwrap().to_string() }), )) - .await; + .await; } } diff --git a/rust/src/actions/farming_mode.rs b/rust/src/actions/farming_mode.rs index a05b2bb..3bc6ceb 100644 --- a/rust/src/actions/farming_mode.rs +++ b/rust/src/actions/farming_mode.rs @@ -32,11 +32,10 @@ impl Action for FarmingModeAction { } async fn on_appear(&self, e: AppearEvent, sd: StreamDeck) { - let settings = sd - .global_settings::() - .await - .farming_mode; - self.update(e.context, sd, settings).await; + let settings: Option = sd.global_settings().await; + let farming_mode = settings.and_then(|s| s.farming_mode); + + self.update(e.context, sd, farming_mode).await; } async fn on_key_up(&self, _e: KeyEvent, sd: StreamDeck) { @@ -46,11 +45,9 @@ impl Action for FarmingModeAction { async fn on_global_settings_changed(&self, _e: DidReceiveGlobalSettingsEvent, sd: StreamDeck) { let contexts = sd.contexts_of(self.uuid()).await; for ctx in contexts { - let settings = sd - .global_settings::() - .await - .farming_mode; - self.update(ctx.clone(), sd.clone(), settings).await; + let settings: Option = sd.global_settings().await; + let farming_mode = settings.and_then(|s| s.farming_mode); + self.update(ctx.clone(), sd.clone(), farming_mode).await; } } } diff --git a/rust/src/actions/loadout.rs b/rust/src/actions/loadout.rs index 172edf8..3c21fa2 100644 --- a/rust/src/actions/loadout.rs +++ b/rust/src/actions/loadout.rs @@ -108,23 +108,32 @@ impl Action for LoadoutAction { async fn on_appear(&self, e: AppearEvent, sd: StreamDeck) { let settings = get_settings(e.payload.settings); - self.update(e.context, settings, sd).await; + if settings.is_some() { + self.update(e.context, settings.unwrap(), sd).await; + } } async fn on_key_up(&self, e: KeyEvent, sd: StreamDeck) { - let settings: LoadoutSettings = get_settings(e.payload.settings); - self.equip_loadout(sd, e.context, settings, e.is_double_tap) - .await; + let settings: Option = get_settings(e.payload.settings); + if settings.is_some() { + self.equip_loadout(sd, e.context, settings.unwrap(), e.is_double_tap) + .await; + } } - async fn on_settings_changed(&self, e: DidReceiveSettingsEvent, sd: StreamDeck) { - let settings = get_settings(e.payload.settings); - self.update(e.context, settings, sd).await; + async fn on_long_press(&self, e: KeyEvent, _timeout: f32, sd: StreamDeck) { + let settings: Option = get_settings(e.payload.settings); + if settings.is_some() { + self.equip_loadout(sd, e.context, settings.unwrap(), true) + .await + } } - async fn on_long_press(&self, e: KeyEvent, _timeout: f32, sd: StreamDeck) { - let settings: LoadoutSettings = get_settings(e.payload.settings); - self.equip_loadout(sd, e.context, settings, true).await; + async fn on_settings_changed(&self, e: DidReceiveSettingsEvent, sd: StreamDeck) { + let settings = get_settings(e.payload.settings); + if settings.is_some() { + self.update(e.context, settings.unwrap(), sd).await; + } } async fn on_send_to_plugin(&self, e: SendToPluginEvent, sd: StreamDeck) { diff --git a/rust/src/actions/max_power.rs b/rust/src/actions/max_power.rs index 243f005..3a9fbb5 100644 --- a/rust/src/actions/max_power.rs +++ b/rust/src/actions/max_power.rs @@ -35,15 +35,23 @@ struct PartialPluginSettings { pub(crate) max_power: Option, } -fn render_action(power_type: PowerType, max_power: MaxPower) -> String { +fn render_action(power_type: PowerType, max_power: MaxPower) -> Option { let file_image = format!("./images/max-power/{:?}.png", power_type); let (mut surface, mut paint, typeface) = prepare_render(file_image, 144); + if max_power.total.is_none() || max_power.base.is_none() || max_power.artifact.is_none() { + return None; + } + + let total = max_power.total.unwrap(); + let base = max_power.base.unwrap(); + let artifact = max_power.artifact.unwrap(); + match power_type { PowerType::All => { - let (base, _) = prepare_text(&max_power.base, &typeface, 26.0); - let (artifact, _) = prepare_text(&max_power.artifact.to_string(), &typeface, 26.0); - let (total, (w, _)) = prepare_text(&max_power.total, &typeface, 31.0); + let (base, _) = prepare_text(&base, &typeface, 26.0); + let (artifact, _) = prepare_text(&artifact.to_string(), &typeface, 26.0); + let (total, (w, _)) = prepare_text(&total, &typeface, 31.0); surface .canvas() @@ -58,9 +66,9 @@ fn render_action(power_type: PowerType, max_power: MaxPower) -> String { } _ => { let (level, y) = match power_type { - PowerType::Total => (max_power.total, 126.0), - PowerType::Base => (max_power.base, 128.0), - PowerType::Artifact => (max_power.artifact.to_string(), 128.0), + PowerType::Total => (total, 126.0), + PowerType::Base => (base, 128.0), + PowerType::Artifact => (artifact.to_string(), 128.0), _ => unreachable!(), }; let (label, (w, _)) = prepare_text(&level, &typeface, 28.0); @@ -70,25 +78,20 @@ fn render_action(power_type: PowerType, max_power: MaxPower) -> String { } } - surface_to_b64(surface) + Some(surface_to_b64(surface)) } impl MaxPowerAction { async fn update(&self, context: String, sd: StreamDeck, settings: Option) { - let max_power = sd - .global_settings::() - .await - .max_power; - - if settings.is_none() || max_power.is_none() { - return; + let global = sd.global_settings::().await; + if let Some(global) = global { + if let Some(max_power) = global.max_power { + let settings = settings.unwrap(); + let power_type = settings.power_type.unwrap_or(PowerType::All); + let image = render_action(power_type, max_power); + sd.set_image_b64(context, image).await; + } } - - let settings = settings.unwrap(); - let power_type = settings.power_type.unwrap_or(PowerType::All); - - let image = render_action(power_type, max_power.unwrap()); - sd.set_image_b64(context, Some(image)).await; } } @@ -99,8 +102,8 @@ impl Action for MaxPowerAction { } async fn on_appear(&self, e: AppearEvent, sd: StreamDeck) { - let settings: MaxPowerSettings = get_settings(e.payload.settings); - self.update(e.context, sd, Some(settings)).await; + let settings: Option = get_settings(e.payload.settings); + self.update(e.context, sd, settings).await; } async fn on_key_down(&self, e: KeyEvent, sd: StreamDeck) { @@ -109,8 +112,8 @@ impl Action for MaxPowerAction { } async fn on_settings_changed(&self, e: DidReceiveSettingsEvent, sd: StreamDeck) { - let settings: MaxPowerSettings = get_settings(e.payload.settings); - self.update(e.context, sd, Some(settings)).await; + let settings: Option = get_settings(e.payload.settings); + self.update(e.context, sd, settings).await; } async fn on_global_settings_changed(&self, _e: DidReceiveGlobalSettingsEvent, sd: StreamDeck) { diff --git a/rust/src/actions/metrics.rs b/rust/src/actions/metrics.rs index b2f525e..bdfc77b 100644 --- a/rust/src/actions/metrics.rs +++ b/rust/src/actions/metrics.rs @@ -11,7 +11,6 @@ use stream_deck_sdk::events::events::{ use stream_deck_sdk::get_settings; use stream_deck_sdk::stream_deck::StreamDeck; - use crate::dim::events_recv::Metrics; use crate::shared::SHADOW; use crate::util::{ @@ -21,7 +20,7 @@ use crate::util::{ pub struct MetricsAction; -#[derive(Serialize, Deserialize, Debug,)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] enum Metric { Vanguard, @@ -51,6 +50,7 @@ impl Metric { } } } + #[derive(Serialize, Deserialize, Debug)] struct MetricsSettings { pub(crate) metric: Option, @@ -69,12 +69,16 @@ async fn render_action(metric: Metric, metrics: Metrics) -> Option { Metric::Trials => metrics.trials, Metric::IronBanner => metrics.iron_banner, Metric::Triumphs => metrics.triumphs, - Metric::TriumphsActive => metrics.triumphs_active.unwrap_or_else(|| 0), + Metric::TriumphsActive => metrics.triumphs_active, Metric::Gunsmith => metrics.gunsmith, Metric::BattlePass => metrics.battle_pass, }; - let value = value.separated_string(); + if value.is_none() { + return None; + } + + let value = value.unwrap().separated_string(); let (file_image, bytes) = match metric { Metric::BattlePass => ( @@ -108,8 +112,13 @@ async fn render_action(metric: Metric, metrics: Metrics) -> Option { impl MetricsAction { async fn update(&self, context: String, sd: StreamDeck, settings: Option) { - let metrics = sd.global_settings::().await.metrics; - if let Some(metrics) = metrics { + let global: Option = sd.global_settings().await; + + if global.is_none() { + return; + } + + if let Some(metrics) = global.unwrap().metrics { let metric = match settings { Some(settings) => settings.metric.unwrap_or(Metric::Vanguard), None => Metric::Vanguard, @@ -129,13 +138,30 @@ impl Action for MetricsAction { } async fn on_appear(&self, e: AppearEvent, sd: StreamDeck) { - let settings: MetricsSettings = get_settings(e.payload.settings); - self.update(e.context, sd, Some(settings)).await; + let settings: Option = get_settings(e.payload.settings); + self.update(e.context, sd, settings).await; + } + + async fn on_key_up(&self, e: KeyEvent, sd: StreamDeck) { + let settings: Option = get_settings(e.payload.settings); + + let mut current_settings = settings.unwrap_or_else(|| MetricsSettings { + metric: Some(Metric::Vanguard), + }); + + current_settings.metric = Some( + current_settings + .metric + .unwrap_or(Metric::Vanguard) + .next_metric(), + ); + + sd.set_settings(e.context.clone(), current_settings).await; } async fn on_settings_changed(&self, e: DidReceiveSettingsEvent, sd: StreamDeck) { - let settings: MetricsSettings = get_settings(e.payload.settings); - self.update(e.context, sd, Some(settings)).await; + let settings: Option = get_settings(e.payload.settings); + self.update(e.context, sd, settings).await; } async fn on_global_settings_changed(&self, _e: DidReceiveGlobalSettingsEvent, sd: StreamDeck) { @@ -145,16 +171,4 @@ impl Action for MetricsAction { self.update(ctx.clone(), sd.clone(), settings).await } } - - async fn on_key_up(&self, e: KeyEvent, sd: StreamDeck) { - let mut current_setting: MetricsSettings = get_settings(e.payload.settings); - current_setting.metric = Some( - current_setting - .metric - .unwrap_or(Metric::Vanguard) - .next_metric(), - ); - - sd.set_settings(e.context.clone(), current_setting).await; - } -} \ No newline at end of file +} diff --git a/rust/src/actions/open_dim.rs b/rust/src/actions/open_dim.rs index e8bdf1d..248c3be 100644 --- a/rust/src/actions/open_dim.rs +++ b/rust/src/actions/open_dim.rs @@ -20,12 +20,14 @@ impl Action for OpenDimAction { async fn on_key_down(&self, e: KeyEvent, _sd: StreamDeck) { let settings = get_settings::(e.payload.settings); - let beta = settings.beta.unwrap_or(false); - let prefix = match beta { - true => "beta", - false => "app", - }; - open::that(format!("https://{}.destinyitemmanager.com", prefix)).unwrap(); + if let Some(settings) = settings { + let beta = settings.beta.unwrap_or(false); + let prefix = match beta { + true => "beta", + false => "app", + }; + open::that(format!("https://{}.destinyitemmanager.com", prefix)).unwrap(); + } } async fn on_key_up(&self, e: KeyEvent, sd: StreamDeck) { diff --git a/rust/src/actions/postmaster.rs b/rust/src/actions/postmaster.rs index 6d1ff70..88b321e 100644 --- a/rust/src/actions/postmaster.rs +++ b/rust/src/actions/postmaster.rs @@ -36,6 +36,12 @@ async fn render_action( let item = item.unwrap_or_else(|| "".to_string()); let is_total = item == ""; + if postmaster.total.is_none() { + return None; + } + + let total = postmaster.total.unwrap(); + let file_image = match is_total { true => "./images/postmaster/postmaster.png".to_string(), false => format!("./images/postmaster/{}.png", item), @@ -44,16 +50,20 @@ async fn render_action( let is_percentage = is_total && style.unwrap_or_else(|| "percentage".to_string()) == "percentage".to_string(); - let mut value = match item.as_str() { + let value = match item.as_str() { "spoils" => postmaster.spoils, "ascendantShards" => postmaster.ascendant_shards, "enhancementPrisms" => postmaster.enhancement_prisms, _ => match is_percentage { - true => ((postmaster.total as f32 / 21.0) * 100.0).ceil() as i32, - false => postmaster.total, + true => Some(((total as f32 / 21.0) * 100.0).ceil() as i32), + false => Some(total), }, - } - .to_string(); + }; + + let mut value = match value { + Some(v) => v.to_string(), + None => "".to_string(), + }; if is_percentage { value = value + "%"; @@ -77,26 +87,18 @@ async fn render_action( impl PostmasterAction { async fn update(&self, context: String, sd: StreamDeck) { - let postmaster = sd - .global_settings::() - .await - .postmaster; - - if postmaster.is_none() { + let global: Option = sd.global_settings().await; + if global.is_none() { return; } - - let settings: Option = sd.settings(context.clone()).await; - - if let Some(settings) = settings { - let image = render_action( - settings.postmaster_item, - settings.style, - postmaster.unwrap(), - ) - .await; - if image.is_some() { - sd.set_image_b64(context, image).await; + if let Some(postmaster) = global.unwrap().postmaster { + let settings: Option = sd.settings(context.clone()).await; + if let Some(settings) = settings { + let image = + render_action(settings.postmaster_item, settings.style, postmaster).await; + if image.is_some() { + sd.set_image_b64(context, image).await; + } } } } @@ -113,14 +115,16 @@ impl Action for PostmasterAction { } async fn on_key_down(&self, e: KeyEvent, sd: StreamDeck) { - let settings: PostmasterSettings = get_settings(e.payload.settings); - if settings.postmaster_item == Some("".to_string()) - && settings.collect_postmaster == Some(true) - { - sd.external(with_action("collectPostmaster", String::new())) - .await; - sd.show_ok(e.context).await; - return; + let settings: Option = get_settings(e.payload.settings); + if let Some(settings) = settings { + if settings.postmaster_item == Some("".to_string()) + && settings.collect_postmaster == Some(true) + { + sd.external(with_action("collectPostmaster", String::new())) + .await; + sd.show_ok(e.context).await; + return; + } } } diff --git a/rust/src/actions/pull_item.rs b/rust/src/actions/pull_item.rs index bea68e2..969bb4e 100644 --- a/rust/src/actions/pull_item.rs +++ b/rust/src/actions/pull_item.rs @@ -2,9 +2,9 @@ use async_trait::async_trait; use futures_util::future::join3; use serde::{Deserialize, Serialize}; use serde_json::json; +use skia_safe::{Color, Point, Rect}; use skia_safe::color_filters::matrix; use skia_safe::image_filters::blur; -use skia_safe::{Color, Point, Rect}; use stream_deck_sdk::action::Action; use stream_deck_sdk::events::events::{ AppearEvent, DidReceiveGlobalSettingsEvent, DidReceiveSettingsEvent, KeyEvent, @@ -16,9 +16,8 @@ use stream_deck_sdk::stream_deck::StreamDeck; use crate::actions::search::SearchSettings; use crate::dim::events_sent::Selection; use crate::dim::with_action; -use crate::global_settings::PluginSettings; use crate::json_string; -use crate::shared::{has_equipped_items, EQUIPPED_MARK, EXOTIC, GRAYSCALE, LEGENDARY, SHARED}; +use crate::shared::{EQUIPPED_MARK, EXOTIC, GRAYSCALE, has_equipped_items, LEGENDARY, SHARED}; use crate::util::{ bungify, bytes_to_skia_image, download_or_cache, prepare_render_empty, surface_to_b64, }; @@ -32,9 +31,11 @@ pub struct PullItemSettings { pub(crate) overlay: Option, pub(crate) element: Option, #[serde(rename = "altAction")] - pub(crate) alt_action: Option, // "hold" | "double" + pub(crate) alt_action: Option, + // "hold" | "double" #[serde(rename = "altActionTrigger")] - pub(crate) alt_action_trigger: Option, // "equip" for future use + pub(crate) alt_action_trigger: Option, + // "equip" for future use pub(crate) inventory: Option, #[serde(rename = "isExotic")] pub(crate) is_exotic: Option, @@ -47,6 +48,11 @@ pub struct SendPullItem { pub(crate) equip: bool, } +#[derive(Deserialize, Debug)] +struct PartialPluginSettings { + pub(crate) grayscale: Option, +} + pub struct PullItemAction; async fn render_action(settings: PullItemSettings, grayscale_enabled: bool) -> Option { @@ -155,10 +161,11 @@ async fn render_action(settings: PullItemSettings, grayscale_enabled: bool) -> O impl PullItemAction { async fn update(&self, context: String, settings: PullItemSettings, sd: StreamDeck) { - let global_settings: PluginSettings = sd.global_settings().await; + let global_settings = sd.global_settings().await.unwrap_or(PartialPluginSettings { + grayscale: Some(true), + }); let grayscale_enabled = global_settings.grayscale.unwrap_or(true); let image = render_action(settings, grayscale_enabled).await; - sd.set_image_b64(context, image).await; } @@ -195,29 +202,37 @@ impl Action for PullItemAction { } async fn on_appear(&self, e: AppearEvent, sd: StreamDeck) { - let settings = get_settings(e.payload.settings); - self.update(e.context, settings, sd).await; + let settings: Option = get_settings(e.payload.settings); + if let Some(settings) = settings { + self.update(e.context, settings, sd).await; + } } async fn on_key_up(&self, e: KeyEvent, sd: StreamDeck) { - let settings: PullItemSettings = get_settings(e.payload.settings); - if e.is_double_tap && settings.alt_action_trigger == Some("double".to_owned()) { - self.pull_item(e.context, settings, sd, true).await; - } else { - self.pull_item(e.context, settings, sd, false).await; + let settings: Option = get_settings(e.payload.settings); + if let Some(settings) = settings { + if e.is_double_tap && settings.alt_action_trigger == Some("double".to_owned()) { + self.pull_item(e.context, settings, sd, true).await; + } else { + self.pull_item(e.context, settings, sd, false).await; + } } } async fn on_long_press(&self, e: KeyEvent, _: f32, sd: StreamDeck) { - let settings: PullItemSettings = get_settings(e.payload.settings); - if settings.alt_action_trigger == Some("hold".to_owned()) { - self.pull_item(e.context, settings, sd, true).await; + let settings: Option = get_settings(e.payload.settings); + if let Some(settings) = settings { + if settings.alt_action_trigger == Some("hold".to_owned()) { + self.pull_item(e.context, settings, sd, true).await; + } } } async fn on_settings_changed(&self, e: DidReceiveSettingsEvent, sd: StreamDeck) { - let settings = get_settings(e.payload.settings); - self.update(e.context, settings, sd).await; + let settings: Option = get_settings(e.payload.settings); + if let Some(settings) = settings { + self.update(e.context, settings, sd).await + } } async fn on_global_settings_changed(&self, _e: DidReceiveGlobalSettingsEvent, sd: StreamDeck) { diff --git a/rust/src/actions/randomize.rs b/rust/src/actions/randomize.rs index 58d7c57..330ea70 100644 --- a/rust/src/actions/randomize.rs +++ b/rust/src/actions/randomize.rs @@ -27,7 +27,7 @@ impl Action for RandomizeAction { "randomize", serde_json::to_string(&settings).unwrap(), )) - .await + .await } async fn on_key_up(&self, e: KeyEvent, sd: StreamDeck) { diff --git a/rust/src/actions/refresh.rs b/rust/src/actions/refresh.rs index 8975275..6c6c3a1 100644 --- a/rust/src/actions/refresh.rs +++ b/rust/src/actions/refresh.rs @@ -1,9 +1,10 @@ -use crate::dim::with_action; use async_trait::async_trait; use stream_deck_sdk::action::Action; use stream_deck_sdk::events::events::KeyEvent; use stream_deck_sdk::stream_deck::StreamDeck; +use crate::dim::with_action; + pub struct RefreshAction; #[async_trait] diff --git a/rust/src/actions/search.rs b/rust/src/actions/search.rs index cac5191..04cd2fa 100644 --- a/rust/src/actions/search.rs +++ b/rust/src/actions/search.rs @@ -35,15 +35,22 @@ impl Action for SearchAction { async fn on_key_down(&self, e: KeyEvent, sd: StreamDeck) { let settings = get_settings::(e.payload.settings); - if settings.search.is_some() { - sd.external(with_action( - "search", - serde_json::to_string(&settings).unwrap(), - )) - .await; - sd.show_ok(e.context).await; - } else { - sd.show_alert(e.context).await; + match settings { + Some(settings) => { + if settings.search.is_some() { + sd.external(with_action( + "search", + serde_json::to_string(&settings).unwrap(), + )) + .await; + sd.show_ok(e.context).await; + } else { + sd.show_alert(e.context).await; + } + } + None => { + sd.show_alert(e.context).await; + } } } } diff --git a/rust/src/actions/vault.rs b/rust/src/actions/vault.rs index 3f21946..6d306d7 100644 --- a/rust/src/actions/vault.rs +++ b/rust/src/actions/vault.rs @@ -54,26 +54,28 @@ fn render_action(item: ItemType, counter: String) -> String { impl VaultAction { async fn update(&self, context: String, sd: StreamDeck, settings: Option) { - let vault = sd.global_settings::().await.vault; + let global: Option = sd.global_settings().await; - if settings.is_none() || vault.is_none() { + if settings.is_none() || global.is_none() { return; } - let vault = vault.unwrap(); - let settings = settings.unwrap(); - let item = settings.item.unwrap_or(ItemType::Vault); - - let counter = match item { - ItemType::Vault => vault.vault, - ItemType::Glimmer => vault.glimmer, - ItemType::Dust => vault.bright_dust, - ItemType::BrightDust => vault.bright_dust, - ItemType::Shards => vault.shards, - }; - - let image = render_action(item, counter.separated_string()); - sd.set_image_b64(context, Some(image)).await; + if let Some(vault) = global.unwrap().vault { + let settings = settings.unwrap(); + let item = settings.item.unwrap_or(ItemType::Vault); + let counter = match item { + ItemType::Vault => vault.vault, + ItemType::Glimmer => vault.glimmer, + ItemType::Dust => vault.bright_dust, + ItemType::BrightDust => vault.bright_dust, + ItemType::Shards => vault.shards, + }; + if counter.is_none() { + return; + } + let image = render_action(item, counter.unwrap().separated_string()); + sd.set_image_b64(context, Some(image)).await; + } } } @@ -84,13 +86,13 @@ impl Action for VaultAction { } async fn on_appear(&self, e: AppearEvent, sd: StreamDeck) { - let settings: VaultSettings = get_settings(e.payload.settings); - self.update(e.context, sd, Some(settings)).await; + let settings: Option = get_settings(e.payload.settings); + self.update(e.context, sd, settings).await; } async fn on_settings_changed(&self, e: DidReceiveSettingsEvent, sd: StreamDeck) { - let settings: VaultSettings = get_settings(e.payload.settings); - self.update(e.context, sd, Some(settings)).await; + let settings: Option = get_settings(e.payload.settings); + self.update(e.context, sd, settings).await; } async fn on_global_settings_changed(&self, _e: DidReceiveGlobalSettingsEvent, sd: StreamDeck) { diff --git a/rust/src/dim/events_recv.rs b/rust/src/dim/events_recv.rs index 3ed9052..2080381 100644 --- a/rust/src/dim/events_recv.rs +++ b/rust/src/dim/events_recv.rs @@ -1,6 +1,7 @@ -use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use serde::{Deserialize, Serialize}; + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub enum ToDimAction { @@ -32,41 +33,41 @@ pub enum StreamDeckSelectionType { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct MaxPower { - pub(crate) total: String, - pub(crate) base: String, - pub(crate) artifact: i32, + pub(crate) total: Option, + pub(crate) base: Option, + pub(crate) artifact: Option, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Vault { - pub(crate) vault: i32, - pub(crate) glimmer: i32, - pub(crate) shards: i32, - pub(crate) bright_dust: i32, + pub(crate) vault: Option, + pub(crate) glimmer: Option, + pub(crate) shards: Option, + pub(crate) bright_dust: Option, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Postmaster { - pub(crate) total: i32, - pub(crate) ascendant_shards: i32, - pub(crate) enhancement_prisms: i32, - pub(crate) spoils: i32, + pub(crate) total: Option, + pub(crate) ascendant_shards: Option, + pub(crate) enhancement_prisms: Option, + pub(crate) spoils: Option, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Metrics { - pub(crate) vanguard: i32, - pub(crate) gambit: i32, - pub(crate) crucible: i32, - pub(crate) trials: i32, - pub(crate) iron_banner: i32, - pub(crate) gunsmith: i32, - pub(crate) triumphs: i32, + pub(crate) vanguard: Option, + pub(crate) gambit: Option, + pub(crate) crucible: Option, + pub(crate) trials: Option, + pub(crate) iron_banner: Option, + pub(crate) gunsmith: Option, + pub(crate) triumphs: Option, pub(crate) triumphs_active: Option, - pub(crate) battle_pass: i32, + pub(crate) battle_pass: Option, pub(crate) artifact_icon: Option, } @@ -83,21 +84,21 @@ pub struct UpdateData { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SelectionItem { - pub(crate) item: String, - pub(crate) label: String, - pub(crate) subtitle: String, + pub(crate) item: Option, + pub(crate) label: Option, + pub(crate) subtitle: Option, pub(crate) icon: Option, pub(crate) element: Option, pub(crate) overlay: Option, - pub(crate) inventory: bool, + pub(crate) inventory: Option, #[serde(rename = "isExotic")] pub(crate) is_exotic: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SelectionLoadout { - pub(crate) loadout: String, - pub(crate) label: String, + pub(crate) loadout: Option, + pub(crate) label: Option, pub(crate) subtitle: Option, pub(crate) icon: Option, pub(crate) character: Option, @@ -130,7 +131,7 @@ pub struct UpdateMessage { #[derive(Deserialize, Debug)] pub struct ItemUpdateData { pub(crate) context: String, - pub(crate) equipped: bool, + pub(crate) equipped: Option, pub(crate) element: Option, } diff --git a/rust/src/global_settings.rs b/rust/src/global_settings.rs index 6894bad..920585c 100644 --- a/rust/src/global_settings.rs +++ b/rust/src/global_settings.rs @@ -7,10 +7,10 @@ use crate::dim::events_recv::{MaxPower, Postmaster, Vault}; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PluginSettings { - pub(crate) tokens: Option>, + tokens: Option>, postmaster: Option, max_power: Option, vault: Option, farming_mode: Option, - pub(crate) grayscale: Option, + grayscale: Option, } diff --git a/rust/src/main.rs b/rust/src/main.rs index 9a294e3..8cfbd60 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,16 +1,15 @@ #![allow(dead_code)] extern crate lazy_static; +use stream_deck_sdk::action_manager::ActionManager; +use stream_deck_sdk::init; + use crate::actions::authorization::AuthorizationAction; use crate::actions::auto_profile::AutoProfileAction; use crate::actions::farming_mode::FarmingModeAction; use crate::actions::loadout::LoadoutAction; use crate::actions::max_power::MaxPowerAction; use crate::actions::metrics::MetricsAction; -use stream_deck_sdk::action_manager::ActionManager; -use stream_deck_sdk::{connect, init}; -use tokio::select; - use crate::actions::open_dim::OpenDimAction; use crate::actions::postmaster::PostmasterAction; use crate::actions::pull_item::PullItemAction; @@ -30,27 +29,23 @@ mod util; #[tokio::main] async fn main() { let (tx, rx) = futures::channel::mpsc::unbounded(); - let actions_manager = ActionManager::new() - .register(Box::new(RefreshAction)) - .register(Box::new(OpenDimAction)) - .register(Box::new(SearchAction)) - .register(Box::new(RandomizeAction)) - .register(Box::new(VaultAction)) - .register(Box::new(MetricsAction)) - .register(Box::new(FarmingModeAction)) - .register(Box::new(PullItemAction)) - .register(Box::new(LoadoutAction)) - .register(Box::new(PostmasterAction)) - .register(Box::new(RotationAction)) - .register(Box::new(MaxPowerAction)) - .register(Box::new(AuthorizationAction)) - .register(Box::new(AutoProfileAction)); - let args = init(Some(tx)).await; - let sd = args.0.clone(); - let stream_deck = connect(args, actions_manager); - let ws_server = tokio::spawn(server::server(sd, rx)); - select! { - _ = stream_deck => {}, - _ = ws_server => {} - } + let actions_manager = ActionManager::new().register(vec![ + Box::new(RefreshAction), + Box::new(OpenDimAction), + Box::new(SearchAction), + Box::new(RandomizeAction), + Box::new(VaultAction), + Box::new(MetricsAction), + Box::new(FarmingModeAction), + Box::new(PullItemAction), + Box::new(LoadoutAction), + Box::new(PostmasterAction), + Box::new(RotationAction), + Box::new(MaxPowerAction), + Box::new(AuthorizationAction), + Box::new(AutoProfileAction), + ]); + let init = init(actions_manager, Some(tx)).await; + tokio::spawn(server::server(init.stream_deck.clone(), rx)); + init.connect().await; } diff --git a/rust/src/server.rs b/rust/src/server.rs index 6436392..50a14a2 100644 --- a/rust/src/server.rs +++ b/rust/src/server.rs @@ -1,26 +1,34 @@ use std::collections::HashMap; use std::sync::Arc; -use crate::actions::pull_item::PullItemSettings; use futures_channel::mpsc::UnboundedReceiver; use futures_util::{SinkExt, StreamExt, TryFutureExt}; +use serde::Deserialize; use serde_json::{Map, Value}; use stream_deck_sdk::stream_deck::StreamDeck; use tokio::sync::{mpsc, RwLock}; use tokio_stream::wrappers::UnboundedReceiverStream; +use warp::Filter; use warp::path::FullPath; use warp::ws::{Message, WebSocket}; -use warp::Filter; +use crate::actions::pull_item::PullItemSettings; use crate::dim::events_recv::{FromDimMessage, SelectionMessage}; -use crate::global_settings::PluginSettings; use crate::shared::{EQUIPPED, MISSING, SHARED}; type Clients = Arc, mpsc::UnboundedSender)>>>; +#[derive(Deserialize, Debug)] +struct PartialPluginSettings { + pub(crate) tokens: Option>, +} + async fn client_token(id: String, sd: StreamDeck) -> Option { - let plugin: PluginSettings = sd.global_settings().await; - return match plugin.tokens { + let plugin: Option = sd.global_settings().await; + if plugin.is_none() { + return None; + } + return match plugin.unwrap().tokens { Some(tokens) => { if let Some(token) = tokens.get(&id) { return Some(token.to_string()); @@ -51,6 +59,16 @@ pub async fn missing_update(id: String, add: bool) -> HashMap { changes } +async fn load_settings(sd: StreamDeck) -> PartialPluginSettings { + let settings: Option = sd.global_settings().await; + match settings { + Some(settings) => settings, + None => PartialPluginSettings { + tokens: Some(HashMap::default()), + }, + } +} + async fn client_connected(ws: WebSocket, id: String, clients: Clients, sd: StreamDeck) { let token = client_token(id.clone(), sd.clone()).await; @@ -86,7 +104,17 @@ async fn client_connected(ws: WebSocket, id: String, clients: Clients, sd: Strea match message { FromDimMessage::AuthorizationReset(_) => { let mut changes: HashMap = HashMap::default(); - changes.insert("tokens".to_string(), Value::Object(Map::new())); + let settings = load_settings(sd.clone()).await; + let filtered_tokens = Map::from_iter( + settings + .tokens + .unwrap_or_default() + .iter() + .map(|(k, v)| (k.to_string(), Value::String(v.to_string()))) + .filter(|(k, _)| k != &id), + ); + + changes.insert("tokens".to_string(), Value::Object(filtered_tokens)); changes.insert( "missing".to_string(), Value::Array(vec![Value::String(id.clone())]), @@ -95,7 +123,7 @@ async fn client_connected(ws: WebSocket, id: String, clients: Clients, sd: Strea } FromDimMessage::AuthorizationConfirm(item) => { - let settings: PluginSettings = sd.global_settings().await; + let settings = load_settings(sd.clone()).await; let mut map = Map::from_iter( settings.tokens.unwrap_or_default().iter().map(|(k, v)| { @@ -124,13 +152,23 @@ async fn client_connected(ws: WebSocket, id: String, clients: Clients, sd: Strea } FromDimMessage::ItemUpdate(item) => { let data = item.data; - let mut settings: PullItemSettings = - sd.settings(data.context.clone()).await.unwrap(); + + let settings: Option = + sd.settings(data.context.clone()).await; + + let mut settings = match settings { + Some(settings) => settings, + None => { + sd.log("[UPDATE ITEM] No settings found".to_string()).await; + return; + } + }; + settings.element = data.element; // Update equip state let mut equipped_items = EQUIPPED.lock().await; let id = settings.item.clone().unwrap(); - if data.equipped { + if data.equipped == Some(true) { equipped_items.insert(id); } else { equipped_items.remove(&id); @@ -162,6 +200,7 @@ async fn client_connected(ws: WebSocket, id: String, clients: Clients, sd: Strea let shared = SHARED.lock().await; let context = shared.get(key); if context.is_none() { + sd.log(format!("No context found for {}", key)).await; return; } let context = context.unwrap().as_str().unwrap().to_string(); @@ -192,7 +231,7 @@ async fn broadcast(msg: String, clients: &Clients) { .replacen("{", r#"{"token": "$token", "#, 1) .replace("$token", token.clone().unwrap().as_str()); } - tx.send(Message::text(send)).expect("TODO: panic message"); + tx.send(Message::text(send)).expect("websocket send error"); } } diff --git a/rust/src/shared.rs b/rust/src/shared.rs index 038cec2..bc43571 100644 --- a/rust/src/shared.rs +++ b/rust/src/shared.rs @@ -1,9 +1,11 @@ -use crate::util::get_file_as_byte_vec; +use std::collections::{HashMap, HashSet}; + use lazy_static::lazy_static; use skia_safe::{ColorMatrix, Rect}; -use std::collections::{HashMap, HashSet}; use tokio::sync::Mutex; +use crate::util::get_file_as_byte_vec; + lazy_static! { pub static ref SHARED: Mutex> = { let m = HashMap::new(); diff --git a/rust/src/util.rs b/rust/src/util.rs index b57dc11..fdee12f 100644 --- a/rust/src/util.rs +++ b/rust/src/util.rs @@ -2,13 +2,14 @@ use std::fs; use std::fs::File; use std::io::Read; -use crate::shared::TILE; use skia_safe::{ - scalar, Color, Data, EncodedImageFormat, Font, Image, Paint, Rect, Surface, TextBlob, Typeface, + Color, Data, EncodedImageFormat, Font, Image, Paint, Rect, scalar, Surface, TextBlob, Typeface, }; use stream_deck_sdk::download::download_image; use stream_deck_sdk::images::image_to_base64; +use crate::shared::TILE; + pub fn get_file_as_byte_vec(filename: &str) -> Vec { let mut f = File::open(&filename).expect("no file found"); let metadata = fs::metadata(&filename).expect("unable to read metadata"); From 8725249244c94f72740a294921be050eff959d18 Mon Sep 17 00:00:00 2001 From: Francesco Saverio Cannizzaro Date: Sat, 14 Jan 2023 00:53:18 +0100 Subject: [PATCH 3/3] update plugin version --- plugin/manifest.json | 2 +- rust/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/manifest.json b/plugin/manifest.json index e339717..e4c7c93 100644 --- a/plugin/manifest.json +++ b/plugin/manifest.json @@ -3,7 +3,7 @@ "Author": "fcannizzaro", "Description": "Use Destiny Item Manager from your Stream Deck! Equip Loadouts, Pull Items, Search and much more", "Icon": "icons/pluginIcon", - "Version": "2.0.3", + "Version": "2.0.4", "SDKVersion": 2, "URL": "https://dimstreamdeck.vercel.app", "uuid": "com.dim.streamdeck", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index cedb22a..10848fb 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dim-stream-deck" -version = "2.0.3" +version = "2.0.4" edition = "2021" [dependencies]