Add spend txs to app cache
This commit is contained in:
parent
ecd5962831
commit
95aa8a1529
@ -1,7 +1,8 @@
|
||||
use crate::daemon::model::Coin;
|
||||
use crate::daemon::model::{Coin, SpendTx};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Cache {
|
||||
pub blockheight: i32,
|
||||
pub coins: Vec<Coin>,
|
||||
pub spend_txs: Vec<SpendTx>,
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
pub enum Menu {
|
||||
Home,
|
||||
Receive,
|
||||
Spend,
|
||||
Settings,
|
||||
Coins,
|
||||
}
|
||||
|
||||
@ -65,6 +65,7 @@ impl App {
|
||||
menu::Menu::Home => Home::new(&self.cache.coins).into(),
|
||||
menu::Menu::Coins => CoinsPanel::new(&self.cache.coins).into(),
|
||||
menu::Menu::Receive => ReceivePanel::default().into(),
|
||||
menu::Menu::Spend => ReceivePanel::default().into(),
|
||||
};
|
||||
self.state.load(self.daemon.clone())
|
||||
}
|
||||
|
||||
@ -25,9 +25,10 @@ impl CoinsPanel {
|
||||
}
|
||||
|
||||
impl State for CoinsPanel {
|
||||
fn view<'a>(&'a self, _cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
view::dashboard(
|
||||
&Menu::Coins,
|
||||
cache,
|
||||
self.warning.as_ref(),
|
||||
view::coins::coins_view(&self.coins),
|
||||
)
|
||||
|
||||
@ -42,8 +42,13 @@ impl Home {
|
||||
}
|
||||
|
||||
impl State for Home {
|
||||
fn view<'a>(&'a self, _cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
view::dashboard(&Menu::Home, None, view::home::home_view(&self.balance))
|
||||
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
view::dashboard(
|
||||
&Menu::Home,
|
||||
cache,
|
||||
None,
|
||||
view::home::home_view(&self.balance),
|
||||
)
|
||||
}
|
||||
|
||||
fn update(
|
||||
@ -83,15 +88,16 @@ pub struct ReceivePanel {
|
||||
}
|
||||
|
||||
impl State for ReceivePanel {
|
||||
fn view<'a>(&'a self, _cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
if let Some(address) = &self.address {
|
||||
view::dashboard(
|
||||
&Menu::Receive,
|
||||
cache,
|
||||
self.warning.as_ref(),
|
||||
view::receive::receive(address, self.qr_code.as_ref().unwrap()),
|
||||
)
|
||||
} else {
|
||||
view::dashboard(&Menu::Receive, self.warning.as_ref(), column())
|
||||
view::dashboard(&Menu::Receive, cache, self.warning.as_ref(), column())
|
||||
}
|
||||
}
|
||||
fn update(
|
||||
|
||||
@ -103,6 +103,7 @@ impl State for SettingsState {
|
||||
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
|
||||
let can_edit = self.current.is_none() && !self.daemon_is_external;
|
||||
view::settings::list(
|
||||
cache,
|
||||
self.warning.as_ref(),
|
||||
self.settings
|
||||
.iter()
|
||||
|
||||
@ -16,13 +16,14 @@ use iced::{
|
||||
|
||||
use crate::ui::{
|
||||
color,
|
||||
component::{button, separation, text::*},
|
||||
icon::{coin_icon, home_icon, receive_icon, settings_icon},
|
||||
component::{badge, button, separation, text::*},
|
||||
icon::{coin_icon, home_icon, receive_icon, send_icon, settings_icon},
|
||||
util::Collection,
|
||||
};
|
||||
|
||||
use crate::app::{error::Error, menu::Menu};
|
||||
use crate::app::{cache::Cache, error::Error, menu::Menu};
|
||||
|
||||
pub fn sidebar(menu: &Menu) -> widget::Container<Message> {
|
||||
pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Message> {
|
||||
let home_button = if *menu == Menu::Home {
|
||||
button::primary(Some(home_icon()), "Home")
|
||||
.on_press(Message::Reload)
|
||||
@ -34,13 +35,131 @@ pub fn sidebar(menu: &Menu) -> widget::Container<Message> {
|
||||
};
|
||||
|
||||
let coins_button = if *menu == Menu::Coins {
|
||||
button::primary(Some(coin_icon()), "Coins")
|
||||
.on_press(Message::Reload)
|
||||
.width(iced::Length::Units(200))
|
||||
iced::pure::widget::button::Button::new(
|
||||
container(
|
||||
row()
|
||||
.push(
|
||||
row()
|
||||
.push(coin_icon())
|
||||
.push(text("Coins"))
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.push(
|
||||
container(text(&format!(" {} ", cache.coins.len())).small().bold())
|
||||
.style(badge::PillStyle::InversePrimary),
|
||||
)
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.width(iced::Length::Fill)
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Primary)
|
||||
.on_press(Message::Reload)
|
||||
.width(iced::Length::Units(200))
|
||||
} else {
|
||||
button::transparent(Some(coin_icon()), "Coins")
|
||||
.on_press(Message::Menu(Menu::Coins))
|
||||
.width(iced::Length::Units(200))
|
||||
iced::pure::widget::button::Button::new(
|
||||
container(
|
||||
row()
|
||||
.push(
|
||||
row()
|
||||
.push(coin_icon())
|
||||
.push(text("Coins"))
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.push(
|
||||
container(text(&format!(" {} ", cache.coins.len())).small().bold())
|
||||
.style(badge::PillStyle::Primary),
|
||||
)
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.width(iced::Length::Fill)
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Transparent)
|
||||
.on_press(Message::Menu(Menu::Coins))
|
||||
.width(iced::Length::Units(200))
|
||||
};
|
||||
|
||||
let spend_button = if *menu == Menu::Spend {
|
||||
iced::pure::widget::button::Button::new(
|
||||
container(
|
||||
row()
|
||||
.push(
|
||||
row()
|
||||
.push(send_icon())
|
||||
.push(text("Send"))
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.push_maybe(if cache.spend_txs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
container(
|
||||
text(&format!(" {} ", cache.spend_txs.len()))
|
||||
.small()
|
||||
.bold(),
|
||||
)
|
||||
.style(badge::PillStyle::InversePrimary),
|
||||
)
|
||||
})
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.width(iced::Length::Fill)
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Primary)
|
||||
.on_press(Message::Reload)
|
||||
.width(iced::Length::Units(200))
|
||||
} else {
|
||||
iced::pure::widget::button::Button::new(
|
||||
container(
|
||||
row()
|
||||
.push(
|
||||
row()
|
||||
.push(coin_icon())
|
||||
.push(text("Send"))
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.push_maybe(if cache.spend_txs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
container(
|
||||
text(&format!(" {} ", cache.spend_txs.len()))
|
||||
.small()
|
||||
.bold(),
|
||||
)
|
||||
.style(badge::PillStyle::Primary),
|
||||
)
|
||||
})
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(iced::Alignment::Center),
|
||||
)
|
||||
.width(iced::Length::Fill)
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Transparent)
|
||||
.on_press(Message::Menu(Menu::Spend))
|
||||
.width(iced::Length::Units(200))
|
||||
};
|
||||
|
||||
let receive_button = if *menu == Menu::Receive {
|
||||
@ -76,6 +195,7 @@ pub fn sidebar(menu: &Menu) -> widget::Container<Message> {
|
||||
)
|
||||
.push(home_button)
|
||||
.push(coins_button)
|
||||
.push(spend_button)
|
||||
.push(receive_button)
|
||||
.spacing(15)
|
||||
.height(Length::Fill),
|
||||
@ -99,11 +219,16 @@ impl widget::container::StyleSheet for SidebarStyle {
|
||||
|
||||
pub fn dashboard<'a, T: Into<Element<'a, Message>>>(
|
||||
menu: &'a Menu,
|
||||
cache: &'a Cache,
|
||||
warning: Option<&Error>,
|
||||
content: T,
|
||||
) -> Element<'a, Message> {
|
||||
row()
|
||||
.push(sidebar(menu).width(Length::Shrink).height(Length::Fill))
|
||||
.push(
|
||||
sidebar(menu, cache)
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Fill),
|
||||
)
|
||||
.push(
|
||||
column().push(warn(warning)).push(
|
||||
main_section(container(scrollable(content)))
|
||||
|
||||
@ -12,7 +12,7 @@ use super::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{error::Error, menu::Menu},
|
||||
app::{cache::Cache, error::Error, menu::Menu},
|
||||
ui::{
|
||||
color,
|
||||
component::{badge, button, card, form, separation, text::*},
|
||||
@ -21,11 +21,13 @@ use crate::{
|
||||
};
|
||||
|
||||
pub fn list<'a>(
|
||||
cache: &'a Cache,
|
||||
warning: Option<&Error>,
|
||||
settings: Vec<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
dashboard(
|
||||
&Menu::Settings,
|
||||
cache,
|
||||
warning,
|
||||
widget::Column::with_children(settings).spacing(20),
|
||||
)
|
||||
|
||||
@ -70,6 +70,10 @@ impl<C: Client + Debug> Daemon for Minisafed<C> {
|
||||
fn list_coins(&self) -> Result<ListCoinsResult, DaemonError> {
|
||||
self.call("listcoins", Option::<Request>::None)
|
||||
}
|
||||
|
||||
fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||
self.call("listspend", Option::<Request>::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
|
||||
@ -91,4 +91,15 @@ impl Daemon for EmbeddedDaemon {
|
||||
.control
|
||||
.list_coins())
|
||||
}
|
||||
|
||||
fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||
Ok(self
|
||||
.handle
|
||||
.as_ref()
|
||||
.ok_or(DaemonError::NoAnswer)?
|
||||
.lock()
|
||||
.unwrap()
|
||||
.control
|
||||
.list_spend())
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,4 +49,6 @@ pub trait Daemon: Debug {
|
||||
fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>;
|
||||
|
||||
fn list_coins(&self) -> Result<model::ListCoinsResult, DaemonError>;
|
||||
|
||||
fn list_spend_txs(&self) -> Result<model::ListSpendResult, DaemonError>;
|
||||
}
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
pub use minisafe::commands::{GetAddressResult, GetInfoResult, ListCoinsEntry, ListCoinsResult};
|
||||
pub use minisafe::commands::{
|
||||
GetAddressResult, GetInfoResult, ListCoinsEntry, ListCoinsResult, ListSpendEntry,
|
||||
ListSpendResult,
|
||||
};
|
||||
|
||||
pub type Coin = ListCoinsEntry;
|
||||
pub type SpendTx = ListSpendEntry;
|
||||
|
||||
@ -42,7 +42,12 @@ enum Step {
|
||||
pub enum Message {
|
||||
Event(iced_native::Event),
|
||||
Syncing(Result<GetInfoResult, DaemonError>),
|
||||
Synced(GetInfoResult, Vec<Coin>, Arc<dyn Daemon + Sync + Send>),
|
||||
Synced(
|
||||
GetInfoResult,
|
||||
Vec<Coin>,
|
||||
Vec<SpendTx>,
|
||||
Arc<dyn Daemon + Sync + Send>,
|
||||
),
|
||||
Started(Result<Arc<dyn Daemon + Sync + Send>, Error>),
|
||||
Loaded(Result<Arc<dyn Daemon + Sync + Send>, Error>),
|
||||
Failure(DaemonError),
|
||||
@ -127,9 +132,13 @@ impl Loader {
|
||||
.list_coins()
|
||||
.map(|res| res.coins)
|
||||
.unwrap_or_else(|_| Vec::new());
|
||||
(info, coins, daemon)
|
||||
let spend_txs = daemon
|
||||
.list_spend_txs()
|
||||
.map(|res| res.spend_txs)
|
||||
.unwrap_or_else(|_| Vec::new());
|
||||
(info, coins, spend_txs, daemon)
|
||||
},
|
||||
|res| Message::Synced(res.0, res.1, res.2),
|
||||
|res| Message::Synced(res.0, res.1, res.2, res.3),
|
||||
);
|
||||
} else {
|
||||
*progress = info.sync
|
||||
|
||||
@ -161,10 +161,11 @@ impl Application for GUI {
|
||||
}
|
||||
}
|
||||
(State::Loader(loader), Message::Load(msg)) => {
|
||||
if let loader::Message::Synced(info, coins, minisafed) = *msg {
|
||||
if let loader::Message::Synced(info, coins, spend_txs, minisafed) = *msg {
|
||||
let cache = Cache {
|
||||
blockheight: info.blockheight,
|
||||
coins,
|
||||
spend_txs,
|
||||
};
|
||||
|
||||
let (app, command) = App::new(cache, loader.gui_config.clone(), minisafed);
|
||||
|
||||
@ -117,3 +117,27 @@ pub fn coin<T>() -> widget::container::Container<'static, T> {
|
||||
.center_x()
|
||||
.center_y()
|
||||
}
|
||||
|
||||
pub enum PillStyle {
|
||||
InversePrimary,
|
||||
Primary,
|
||||
}
|
||||
|
||||
impl widget::container::StyleSheet for PillStyle {
|
||||
fn style(&self) -> widget::container::Style {
|
||||
match self {
|
||||
Self::Primary => widget::container::Style {
|
||||
background: color::PRIMARY.into(),
|
||||
border_radius: 10.0,
|
||||
text_color: iced::Color::WHITE.into(),
|
||||
..widget::container::Style::default()
|
||||
},
|
||||
Self::InversePrimary => widget::container::Style {
|
||||
background: color::FOREGROUND.into(),
|
||||
border_radius: 10.0,
|
||||
text_color: color::PRIMARY.into(),
|
||||
..widget::container::Style::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user