From 702a4556176f35d9886bb7075815166758e98f39 Mon Sep 17 00:00:00 2001 From: x86y Date: Mon, 18 Mar 2024 16:02:03 +0400 Subject: [PATCH] update code for newer rust and add preliminary settings --- src/main.rs | 110 +++++++++++++++++++++++++---- src/views/components/better_btn.rs | 30 ++++++-- src/views/panes/book.rs | 2 +- src/views/panes/market.rs | 2 +- src/views/panes/mod.rs | 2 +- src/views/panes/orders.rs | 11 ++- src/views/panes/trades.rs | 7 +- src/ws/book.rs | 65 ++++++++--------- src/ws/prices.rs | 5 -- src/ws/trades.rs | 5 -- src/ws/user.rs | 1 - src/ws/util.rs | 2 +- 12 files changed, 160 insertions(+), 82 deletions(-) diff --git a/src/main.rs b/src/main.rs index 53249ee..5b01ca3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use iced::font; use iced::widget::button; use iced::widget::responsive; use iced::widget::svg; +use iced::widget::text_input; use iced::widget::Row; use iced::widget::Space; use iced::Font; @@ -16,6 +17,7 @@ use pane_grid::Configuration; use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::VecDeque; +use std::env; use views::panes::style; use views::panes::view_controls; use views::panes::Pane; @@ -68,6 +70,15 @@ struct App { filter: WatchlistFilter, filter_string: String, data: AppData, + current_view: ViewState, + api_key: String, + api_secret_key: String, +} + +#[derive(PartialEq)] +enum ViewState { + Dashboard, + Settings, } #[derive(Default)] @@ -82,6 +93,10 @@ struct AppData { #[derive(Debug, Clone)] pub enum Message { + SettingsApiKeyChanged(String), + SettingsApiSecretChanged(String), + SetDashboardView, + SetSettingsView, Split(pane_grid::Axis, pane_grid::Pane), SplitFocused(pane_grid::Axis), FocusAdjacent(pane_grid::Direction), @@ -168,7 +183,7 @@ impl Application for App { panes, panes_created: 1, focus: None, - filter: WatchlistFilter::Btc, + filter: WatchlistFilter::Favorites, filter_string: "".to_string(), watchlist_favorites: [ "BTCUSDT", "ETHUSDT", "LINKUSDT", "UNIUSDT", "ARBUSDT", "SYNUSDT", "OPUSDT", @@ -181,6 +196,13 @@ impl Application for App { new_pair: "BTCUSDT".into(), pair_submitted: true, data: Default::default(), + current_view: ViewState::Dashboard, + api_key: env::var_os("DYN_PUB") + .map(|s| s.into_string().unwrap()) + .unwrap(), + api_secret_key: env::var_os("DYN_SEC") + .map(|s| s.into_string().unwrap()) + .unwrap(), }, Command::batch(vec![ Command::perform(api::orders_history(), Message::OrdersRecieved), @@ -197,6 +219,26 @@ impl Application for App { fn update(&mut self, message: Message) -> Command { match message { + Message::SettingsApiKeyChanged(value) => { + self.api_key = value; + Command::none() + } + Message::SettingsApiSecretChanged(value) => { + self.api_secret_key = value; + Command::none() + } + Message::SetSettingsView => { + if self.current_view == ViewState::Settings { + self.current_view = ViewState::Dashboard; + } else { + self.current_view = ViewState::Settings; + } + Command::none() + } + Message::SetDashboardView => { + self.current_view = ViewState::Dashboard; + Command::none() + } Message::Split(axis, pane) => { let result = self .panes @@ -490,13 +532,12 @@ impl Application for App { let pane_grid = PaneGrid::new(&self.panes, |id, pane, is_maximized| { let is_focused = focus == Some(id); - let title = - row![text(pane.id.to_string()).style(if is_focused { - PANE_ID_COLOR_FOCUSED - } else { - PANE_ID_COLOR_UNFOCUSED - })] - .spacing(5); + let title = row![text(pane.id.to_string()).style(if is_focused { + PANE_ID_COLOR_FOCUSED + } else { + PANE_ID_COLOR_UNFOCUSED + })] + .spacing(5); let title_bar = pane_grid::TitleBar::new(title) .controls(view_controls(id, total_panes, pane.is_pinned, is_maximized)) @@ -541,9 +582,11 @@ impl Application for App { .map(|t| { let price_now = self.data.prices.get(t).unwrap_or(&0.0); let ticker = t.split("USDT").next().unwrap(); - let handle = svg::Handle::from_path( - format!("{}/assets/logos/{}.svg", env!("CARGO_MANIFEST_DIR"), ticker) - ); + let handle = svg::Handle::from_path(format!( + "{}/assets/logos/{}.svg", + env!("CARGO_MANIFEST_DIR"), + ticker + )); let svg = svg(handle) .width(Length::Fixed(16.0)) @@ -559,8 +602,31 @@ impl Application for App { button("Settings") .padding(8) .style(iced::theme::Button::Text) + .on_press(Message::SetSettingsView) + ] + .align_items(iced::Alignment::Center); + + let api_key_input = text_input("API Key", &self.api_key) + .secure(true) + .width(Length::Fill) + .on_input(Message::SettingsApiKeyChanged); + let api_secret_key_input = text_input("API Secret Key", &self.api_secret_key) + .secure(true) + .width(Length::Fill) + .on_input(Message::SettingsApiSecretChanged); + + let settings = column![ + row![text("API Key:").width(Length::Fixed(100.0)), api_key_input].spacing(10), + row![ + text("API Secret Key:").width(Length::Fixed(100.0)), + api_secret_key_input, + ] + .spacing(10), ] + .spacing(10) + .width(Length::Fill) .align_items(iced::Alignment::Center); + let message_log: Element<_> = if self.data.prices.is_empty() { container(text("Loading...").style(Color::from_rgb8(0x88, 0x88, 0x88))) .width(Length::Fill) @@ -569,10 +635,24 @@ impl Application for App { .center_y() .into() } else { - column![container(column![header, pane_grid].spacing(8)) - .width(Length::Fill) - .height(Length::Fill) - .padding(10),] + column![container( + column![ + header, + if self.current_view == ViewState::Dashboard { + container(pane_grid) + } else { + container( + column![settings] + .width(Length::Fill) + .height(Length::Fill) + ) + } + ] + .spacing(8) + ) + .width(Length::Fill) + .height(Length::Fill) + .padding(10),] .into() }; diff --git a/src/views/components/better_btn.rs b/src/views/components/better_btn.rs index 2d59dbe..599a5b7 100644 --- a/src/views/components/better_btn.rs +++ b/src/views/components/better_btn.rs @@ -6,7 +6,9 @@ impl button::StyleSheet for BetterBtn { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> button::Appearance { button::Appearance { - background: Some(iced::Background::Color(Color::from_rgba(0.3, 0.3, 0.3, 0.3))), + background: Some(iced::Background::Color(Color::from_rgba( + 0.3, 0.3, 0.3, 0.3, + ))), text_color: Color::WHITE, shadow_offset: iced::Vector { x: 1.0, y: 1.0 }, border: iced::Border { @@ -20,7 +22,9 @@ impl button::StyleSheet for BetterBtn { fn pressed(&self, _: &Self::Style) -> button::Appearance { button::Appearance { - background: Some(iced::Background::Color(Color::from_rgba(0.3, 0.3, 0.3, 0.3))), + background: Some(iced::Background::Color(Color::from_rgba( + 0.3, 0.3, 0.3, 0.3, + ))), text_color: Color::WHITE, shadow_offset: iced::Vector { x: 1.0, y: 1.0 }, border: iced::Border { @@ -39,7 +43,12 @@ impl button::StyleSheet for GreenBtn { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> button::Appearance { button::Appearance { - background: Some(iced::Background::Color(Color::from_rgba(0.0, 1.0, 0.0, 1.0))), + background: Some(iced::Background::Color(Color::from_rgba( + 50.0 / 255.0, + 217.0 / 255.0, + 147.0 / 255.0, + 1.0, + ))), text_color: Color::WHITE, shadow_offset: iced::Vector { x: 1.0, y: 1.0 }, border: iced::Border { @@ -53,7 +62,9 @@ impl button::StyleSheet for GreenBtn { fn pressed(&self, _: &Self::Style) -> button::Appearance { button::Appearance { - background: Some(iced::Background::Color(Color::from_rgba(0.3, 0.3, 0.3, 0.3))), + background: Some(iced::Background::Color(Color::from_rgba( + 0.3, 0.3, 0.3, 0.3, + ))), text_color: Color::WHITE, shadow_offset: iced::Vector { x: 1.0, y: 1.0 }, border: iced::Border { @@ -72,7 +83,12 @@ impl button::StyleSheet for RedBtn { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> button::Appearance { button::Appearance { - background: Some(iced::Background::Color(Color::from_rgba(1.0, 0.0, 0.0, 1.0))), + background: Some(iced::Background::Color(Color::from_rgba( + 1.0, + 112.0 / 255.0, + 126.0 / 255.0, + 1.0, + ))), text_color: Color::WHITE, shadow_offset: iced::Vector { x: 1.0, y: 1.0 }, border: iced::Border { @@ -86,7 +102,9 @@ impl button::StyleSheet for RedBtn { fn pressed(&self, _: &Self::Style) -> button::Appearance { button::Appearance { - background: Some(iced::Background::Color(Color::from_rgba(0.3, 0.3, 0.3, 0.3))), + background: Some(iced::Background::Color(Color::from_rgba( + 0.3, 0.3, 0.3, 0.3, + ))), text_color: Color::WHITE, shadow_offset: iced::Vector { x: 1.0, y: 1.0 }, border: iced::Border { diff --git a/src/views/panes/book.rs b/src/views/panes/book.rs index d121db8..69c6ffc 100644 --- a/src/views/panes/book.rs +++ b/src/views/panes/book.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use iced::{ - widget::{column, row, scrollable, Column, Container, Rule}, + widget::{column, row, scrollable, Column, Container}, Element, Length, }; diff --git a/src/views/panes/market.rs b/src/views/panes/market.rs index 4a95a63..ac76d57 100644 --- a/src/views/panes/market.rs +++ b/src/views/panes/market.rs @@ -1,4 +1,4 @@ -use crate::views::components::better_btn::{BetterBtn, GreenBtn, RedBtn}; +use crate::views::components::better_btn::{GreenBtn, RedBtn}; use crate::views::components::input::Inp; use iced::{ widget::{button, column, container, row, text, text_input, Space}, diff --git a/src/views/panes/mod.rs b/src/views/panes/mod.rs index a8053ef..95a52ff 100644 --- a/src/views/panes/mod.rs +++ b/src/views/panes/mod.rs @@ -59,7 +59,7 @@ impl From for PaneType { impl ToString for PaneType { fn to_string(&self) -> String { match self { - PaneType::Prices => "Prices", + PaneType::Prices => "Watchlist", PaneType::Book => "Book", PaneType::Trades => "Trades", PaneType::Market => "Market", diff --git a/src/views/panes/orders.rs b/src/views/panes/orders.rs index 7341664..7b68849 100644 --- a/src/views/panes/orders.rs +++ b/src/views/panes/orders.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use binance::rest_model::{Order, OrderType}; -use crate::{theme::h2c, views::components::scrollbar::ScrollbarStyle, Message}; +use crate::{theme::h2c, Message}; use iced::{ widget::{column, container, row, scrollable, text, Column, Space}, Element, Font, Length, @@ -41,13 +41,12 @@ pub fn orders_view<'a>(os: &[Order], ps: &'a HashMap) -> Element<'a tb("Status").width(Length::Fixed(100.0)), tb("PNL").width(Length::Fixed(100.0)) ] - .padding(12) + .padding([0, 12]) .width(Length::Fill); let rows: Vec> = os .iter() - .enumerate() - .map(|(i, b)| { + .map(|b| { let time_t = { let dt: chrono::DateTime = chrono::TimeZone::timestamp_opt(&chrono::Utc, (b.time / 1000) as i64, 0) @@ -94,14 +93,14 @@ pub fn orders_view<'a>(os: &[Order], ps: &'a HashMap) -> Element<'a ] .width(Length::Fill), ) - .padding(4) + .padding([2, 4]) .into() }) .collect(); column![ header, - scrollable(Column::with_children(rows).padding(8)).style(ScrollbarStyle::theme()) + scrollable(Column::with_children(rows).padding(8)) //.style(ScrollbarStyle::theme()) ] .into() } diff --git a/src/views/panes/trades.rs b/src/views/panes/trades.rs index ad00f0d..f78cfaf 100644 --- a/src/views/panes/trades.rs +++ b/src/views/panes/trades.rs @@ -6,7 +6,7 @@ use iced::{ Color, Element, Length, }; -use crate::{theme::h2c, views::components::scrollbar::ScrollbarStyle, Message}; +use crate::{theme::h2c, Message}; use super::orders::{t, tb}; @@ -38,9 +38,8 @@ pub fn trades_view(bs: &VecDeque) -> Element<'_, Message> { .width(Length::Fill) }) .map(Element::from), - )) - .style(ScrollbarStyle::theme()) + )) // .style(ScrollbarStyle::theme()) ] - .padding(12) + .padding([2, 12]) .into() } diff --git a/src/ws/book.rs b/src/ws/book.rs index c488d12..986fb2e 100644 --- a/src/ws/book.rs +++ b/src/ws/book.rs @@ -1,9 +1,7 @@ -use binance::{websockets::*, ws_model::WebsocketEventUntag}; -use futures::channel::mpsc; +use binance::websockets::*; use futures::sink::SinkExt; use iced::futures::FutureExt; use iced::subscription::{self, Subscription}; -use iced_futures::futures; use std::collections::BTreeMap; use std::sync::atomic::AtomicBool; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; @@ -32,44 +30,42 @@ pub fn connect(token: String) -> Subscription { let mut web_socket: WebSockets<'_, binance::ws_model::DepthOrderBookEvent> = WebSockets::new(|events: binance::ws_model::DepthOrderBookEvent| { - if let binance::ws_model::DepthOrderBookEvent { - event_time: du, + let binance::ws_model::DepthOrderBookEvent { + event_time: _, symbol, - first_update_id, - final_update_id, + first_update_id: _, + final_update_id: _, bids, asks, - } = events - { - let mut b: BTreeMap = BTreeMap::new(); - let mut a: BTreeMap = BTreeMap::new(); + } = events; + let mut b: BTreeMap = BTreeMap::new(); + let mut a: BTreeMap = BTreeMap::new(); - for bid in bids { - let price = bid.price; - let quantity = bid.qty; - if quantity == 0.0 { - b.remove(&price.to_string()); - } else { - b.insert(price.to_string(), quantity); - } + for bid in bids { + let price = bid.price; + let quantity = bid.qty; + if quantity == 0.0 { + b.remove(&price.to_string()); + } else { + b.insert(price.to_string(), quantity); } + } - for ask in asks { - let price = ask.price; - let quantity = ask.qty; - if quantity == 0.0 { - a.remove(&price.to_string()); - } else { - a.insert(price.to_string(), quantity); - } + for ask in asks { + let price = ask.price; + let quantity = ask.qty; + if quantity == 0.0 { + a.remove(&price.to_string()); + } else { + a.insert(price.to_string(), quantity); } + } - let _ = s.send(OrderBookDetails { - sym: symbol, - bids: b, - asks: a, - }); - }; + let _ = s.send(OrderBookDetails { + sym: symbol, + bids: b, + asks: a, + }); Ok(()) }); @@ -97,6 +93,3 @@ pub fn connect(token: String) -> Subscription { pub enum BookEvent { MessageReceived(OrderBookDetails), } - -#[derive(Debug, Clone)] -pub struct Connection(mpsc::Sender); diff --git a/src/ws/prices.rs b/src/ws/prices.rs index 70738ba..fbd0305 100644 --- a/src/ws/prices.rs +++ b/src/ws/prices.rs @@ -1,9 +1,7 @@ use iced::futures::FutureExt; use iced::subscription::{self, Subscription}; -use iced_futures::futures; use binance::{websockets::*, ws_model::WebsocketEvent}; -use futures::channel::mpsc; use futures::sink::SinkExt; use std::sync::atomic::AtomicBool; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; @@ -67,6 +65,3 @@ pub fn connect() -> Subscription { pub enum Event { MessageReceived(AssetDetails), } - -#[derive(Debug, Clone)] -pub struct Connection(mpsc::Sender); diff --git a/src/ws/trades.rs b/src/ws/trades.rs index eff3805..d709fe5 100644 --- a/src/ws/trades.rs +++ b/src/ws/trades.rs @@ -1,10 +1,8 @@ use binance::ws_model::TradesEvent; use iced::futures::FutureExt; use iced::subscription::{self, Subscription}; -use iced_futures::futures; use binance::{websockets::*, ws_model::WebsocketEvent}; -use futures::channel::mpsc; use futures::sink::SinkExt; use std::sync::atomic::AtomicBool; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; @@ -53,6 +51,3 @@ pub fn connect(token: String) -> Subscription { pub enum Event { MessageReceived(TradesEvent), } - -#[derive(Debug, Clone)] -pub struct Connection(mpsc::Sender); diff --git a/src/ws/user.rs b/src/ws/user.rs index 6915303..d28ecf9 100644 --- a/src/ws/user.rs +++ b/src/ws/user.rs @@ -1,5 +1,4 @@ use iced::subscription::{self, Subscription}; -use iced_futures::futures; use binance::{api::Binance, userstream::UserStream, websockets::*, ws_model::WebsocketEvent}; use futures::sink::SinkExt; diff --git a/src/ws/util.rs b/src/ws/util.rs index 13c6c66..0f5f3b2 100644 --- a/src/ws/util.rs +++ b/src/ws/util.rs @@ -43,5 +43,5 @@ pub mod m { } }; } - pub(crate) use con; + }