gui: transitioning to ui crate
This commit is contained in:
parent
8d337eb7e1
commit
d4d5a66aa1
10
gui/Cargo.lock
generated
10
gui/Cargo.lock
generated
@ -1690,6 +1690,7 @@ dependencies = [
|
||||
"iced_lazy",
|
||||
"iced_native",
|
||||
"liana",
|
||||
"liana_ui",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1699,6 +1700,15 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "liana_ui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"iced",
|
||||
"iced_lazy",
|
||||
"iced_native",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.137"
|
||||
|
||||
@ -16,6 +16,7 @@ path = "src/main.rs"
|
||||
[dependencies]
|
||||
async-hwi = "0.0.4"
|
||||
liana = { git = "https://github.com/wizardsardine/liana", branch = "master", default-features = false }
|
||||
liana_ui = { path = "ui" }
|
||||
backtrace = "0.3"
|
||||
base64 = "0.13"
|
||||
|
||||
@ -39,3 +40,6 @@ chrono = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = {version = "1.9.0", features = ["rt", "macros"]}
|
||||
|
||||
[workspace]
|
||||
members = ["ui"]
|
||||
|
||||
@ -15,10 +15,11 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use iced::{clipboard, time, Command, Element, Subscription};
|
||||
use iced::{clipboard, time, Command, Subscription};
|
||||
use tracing::{info, warn};
|
||||
|
||||
pub use liana::{config::Config as DaemonConfig, miniscript::bitcoin};
|
||||
use liana_ui::widget::Element;
|
||||
|
||||
pub use config::Config;
|
||||
pub use message::Message;
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
|
||||
use liana_ui::widget::Element;
|
||||
|
||||
use crate::{
|
||||
app::{cache::Cache, error::Error, menu::Menu, message::Message, state::State, view},
|
||||
|
||||
@ -8,8 +8,8 @@ use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use iced::{widget::qr_code, Command, Subscription};
|
||||
use iced::{widget::Column, Element};
|
||||
use liana::miniscript::bitcoin::{Address, Amount};
|
||||
use liana_ui::widget::*;
|
||||
|
||||
use super::{cache::Cache, error::Error, menu::Menu, message::Message, view, wallet::Wallet};
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
|
||||
use liana_ui::{component::form, widget::Element};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
@ -18,7 +20,6 @@ use crate::{
|
||||
model::{remaining_sequence, Coin, SpendTx},
|
||||
Daemon,
|
||||
},
|
||||
ui::component::form,
|
||||
};
|
||||
|
||||
use liana::miniscript::bitcoin::{Address, Amount};
|
||||
|
||||
@ -5,15 +5,16 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
use tracing::info;
|
||||
|
||||
use liana::config::{BitcoinConfig, BitcoindConfig, Config};
|
||||
|
||||
use liana_ui::{component::form, widget::Element};
|
||||
|
||||
use crate::{
|
||||
app::{cache::Cache, error::Error, message::Message, state::settings::Setting, view, State},
|
||||
daemon::Daemon,
|
||||
ui::component::form,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -5,7 +5,9 @@ use std::convert::From;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
|
||||
use liana_ui::widget::Element;
|
||||
|
||||
use bitcoind::BitcoindSettingsState;
|
||||
use wallet::WalletSettingsState;
|
||||
|
||||
@ -3,17 +3,21 @@ use std::convert::From;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
|
||||
use liana::miniscript::bitcoin::{hashes::hex::ToHex, util::bip32::Fingerprint, Network};
|
||||
|
||||
use liana_ui::{
|
||||
component::{form, modal},
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
cache::Cache, error::Error, message::Message, settings, state::State, view, wallet::Wallet,
|
||||
},
|
||||
daemon::Daemon,
|
||||
hw::{list_hardware_wallets, HardwareWallet, HardwareWalletConfig},
|
||||
ui::component::{form, modal},
|
||||
};
|
||||
|
||||
pub struct WalletSettingsState {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
use liana::{
|
||||
descriptors::LianaDescInfo,
|
||||
miniscript::bitcoin::{
|
||||
@ -9,6 +9,11 @@ use liana::{
|
||||
},
|
||||
};
|
||||
|
||||
use liana_ui::{
|
||||
component::{form, modal},
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
cache::Cache,
|
||||
@ -23,7 +28,6 @@ use crate::{
|
||||
Daemon,
|
||||
},
|
||||
hw::{list_hardware_wallets, HardwareWallet},
|
||||
ui::component::{form, modal},
|
||||
};
|
||||
|
||||
trait Action {
|
||||
|
||||
@ -2,9 +2,13 @@ pub mod detail;
|
||||
mod step;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
|
||||
use liana::miniscript::bitcoin::{consensus, util::psbt::Psbt};
|
||||
use liana_ui::{
|
||||
component::{form, modal},
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use super::{redirect, State};
|
||||
use crate::{
|
||||
@ -13,7 +17,6 @@ use crate::{
|
||||
model::{Coin, SpendTx},
|
||||
Daemon,
|
||||
},
|
||||
ui::component::{form, modal},
|
||||
};
|
||||
|
||||
pub struct SpendPanel {
|
||||
|
||||
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
use liana::{
|
||||
descriptors::MultipathDescriptor,
|
||||
miniscript::bitcoin::{
|
||||
@ -10,6 +10,8 @@ use liana::{
|
||||
},
|
||||
};
|
||||
|
||||
use liana_ui::{component::form, widget::Element};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
cache::Cache, error::Error, message::Message, state::spend::detail, view, wallet::Wallet,
|
||||
@ -18,7 +20,6 @@ use crate::{
|
||||
model::{remaining_sequence, Coin, SpendTx},
|
||||
Daemon,
|
||||
},
|
||||
ui::component::form,
|
||||
};
|
||||
|
||||
/// See: https://github.com/wizardsardine/liana/blob/master/src/commands/mod.rs#L32
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
use iced::{
|
||||
widget::{Button, Column, Container, Row},
|
||||
Alignment, Element, Length,
|
||||
use iced::{Alignment, Length};
|
||||
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{badge, separation, text::*},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -9,12 +14,6 @@ use crate::{
|
||||
view::{message::Message, util::*},
|
||||
},
|
||||
daemon::model::{remaining_sequence, Coin},
|
||||
ui::{
|
||||
color,
|
||||
component::{badge, button, card, separation, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn coins_view<'a>(
|
||||
@ -77,11 +76,11 @@ fn coin_list_view(
|
||||
Some(Container::new(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.push(text(" 0").small().style(color::ALERT))
|
||||
.push(text(" 0").small().style(color::legacy::ALERT))
|
||||
.push(
|
||||
icon::hourglass_done_icon()
|
||||
.small()
|
||||
.style(color::ALERT),
|
||||
.style(color::legacy::ALERT),
|
||||
)
|
||||
.align_items(Alignment::Center),
|
||||
))
|
||||
@ -92,12 +91,12 @@ fn coin_list_view(
|
||||
.push(
|
||||
text(format!(" {}", seq))
|
||||
.small()
|
||||
.style(color::WARNING),
|
||||
.style(color::legacy::WARNING),
|
||||
)
|
||||
.push(
|
||||
icon::hourglass_icon()
|
||||
.small()
|
||||
.style(color::WARNING),
|
||||
.style(color::legacy::WARNING),
|
||||
)
|
||||
.align_items(Alignment::Center),
|
||||
))
|
||||
@ -124,7 +123,7 @@ fn coin_list_view(
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(20),
|
||||
)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.padding(10)
|
||||
.on_press(Message::Select(index)),
|
||||
)
|
||||
@ -144,7 +143,7 @@ fn coin_list_view(
|
||||
text("The recovery path is available")
|
||||
.bold()
|
||||
.small()
|
||||
.style(color::ALERT),
|
||||
.style(color::legacy::ALERT),
|
||||
))
|
||||
} else {
|
||||
Some(Container::new(
|
||||
@ -169,7 +168,7 @@ fn coin_list_view(
|
||||
.push(text(format!("{}", coin.outpoint)).small())
|
||||
.push(Button::new(icon::clipboard_icon())
|
||||
.on_press(Message::Clipboard(coin.outpoint.to_string()))
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
))
|
||||
.spacing(5),
|
||||
)
|
||||
@ -204,5 +203,5 @@ fn coin_list_view(
|
||||
None
|
||||
}),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
use chrono::NaiveDateTime;
|
||||
|
||||
use iced::{
|
||||
alignment,
|
||||
widget::{Button, Column, Container, Row},
|
||||
Alignment, Element, Length,
|
||||
};
|
||||
use iced::{alignment, Alignment, Length};
|
||||
|
||||
use crate::ui::{
|
||||
color,
|
||||
component::{badge, button::Style, card, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
};
|
||||
use liana::miniscript::bitcoin;
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{badge, card, text::*},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
@ -38,7 +35,11 @@ pub fn home_view<'a>(
|
||||
Row::new()
|
||||
.spacing(15)
|
||||
.align_items(Alignment::Center)
|
||||
.push(icon::hourglass_icon().size(30).style(color::WARNING))
|
||||
.push(
|
||||
icon::hourglass_icon()
|
||||
.size(30)
|
||||
.style(color::legacy::WARNING),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
@ -56,7 +57,7 @@ pub fn home_view<'a>(
|
||||
Row::new()
|
||||
.spacing(15)
|
||||
.align_items(Alignment::Center)
|
||||
.push(icon::hourglass_done_icon().style(color::ALERT))
|
||||
.push(icon::hourglass_done_icon().style(color::legacy::ALERT))
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
@ -97,11 +98,11 @@ pub fn home_view<'a>(
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.padding(15)
|
||||
.style(Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.on_press(Message::Next),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -154,9 +155,9 @@ fn event_list_view<'a>(i: usize, event: &HistoryTransaction) -> Element<'a, Mess
|
||||
)
|
||||
.padding(10)
|
||||
.on_press(Message::Select(i))
|
||||
.style(Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -203,7 +204,7 @@ pub fn event_view<'a>(cache: &Cache, event: &'a HistoryTransaction) -> Element<'
|
||||
.push(
|
||||
Button::new(icon::clipboard_icon())
|
||||
.on_press(Message::Clipboard(event.tx.txid().to_string()))
|
||||
.style(Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
)
|
||||
.width(Length::Shrink),
|
||||
),
|
||||
|
||||
@ -1,21 +1,14 @@
|
||||
use iced::{
|
||||
widget::{tooltip, Button, Column, Container, Row},
|
||||
Alignment, Element, Length,
|
||||
use iced::{widget::tooltip, Alignment, Length};
|
||||
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::text::{text, Text},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::view::message::*,
|
||||
hw::HardwareWallet,
|
||||
ui::{
|
||||
color,
|
||||
component::{
|
||||
button, card,
|
||||
text::{text, Text},
|
||||
},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
use crate::{app::view::message::*, hw::HardwareWallet};
|
||||
|
||||
pub fn hw_list_view<'a>(
|
||||
i: usize,
|
||||
@ -57,7 +50,7 @@ pub fn hw_list_view<'a>(
|
||||
message,
|
||||
tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
),
|
||||
})
|
||||
.spacing(5)
|
||||
@ -76,20 +69,20 @@ pub fn hw_list_view<'a>(
|
||||
Row::new()
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(5)
|
||||
.push(icon::circle_check_icon().style(color::SUCCESS))
|
||||
.push(text(v).style(color::SUCCESS))
|
||||
.push(icon::circle_check_icon().style(color::legacy::SUCCESS))
|
||||
.push(text(v).style(color::legacy::SUCCESS))
|
||||
}))
|
||||
.align_items(Alignment::Center)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.padding(10)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.width(Length::Fill);
|
||||
if !processing && hw.is_supported() {
|
||||
bttn = bttn.on_press(Message::SelectHardwareWallet(i));
|
||||
}
|
||||
Container::new(bttn)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -13,20 +13,19 @@ pub mod spend;
|
||||
pub use message::*;
|
||||
use warning::warn;
|
||||
|
||||
use iced::{
|
||||
widget::{self, scrollable, Button, Column, Container, Row},
|
||||
Element, Length,
|
||||
};
|
||||
use iced::{widget::scrollable, Length};
|
||||
|
||||
use crate::ui::{
|
||||
component::{badge, button, container, separation, text::*},
|
||||
use liana_ui::{
|
||||
component::{button, separation, text::*},
|
||||
icon::{coin_icon, cross_icon, home_icon, receive_icon, send_icon, settings_icon},
|
||||
theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::app::{cache::Cache, error::Error, menu::Menu};
|
||||
|
||||
pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Message> {
|
||||
pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> {
|
||||
let home_button = if *menu == Menu::Home {
|
||||
button::primary(Some(home_icon()), "Home")
|
||||
.on_press(Message::Reload)
|
||||
@ -63,7 +62,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.small()
|
||||
.bold(),
|
||||
)
|
||||
.style(badge::PillStyle::InversePrimary),
|
||||
.style(theme::Container::Pill(theme::Pill::InversePrimary)),
|
||||
)
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
@ -73,7 +72,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Primary.into())
|
||||
.style(theme::Button::Primary)
|
||||
.on_press(Message::Reload)
|
||||
.width(iced::Length::Units(200))
|
||||
} else {
|
||||
@ -102,7 +101,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.small()
|
||||
.bold(),
|
||||
)
|
||||
.style(badge::PillStyle::Primary),
|
||||
.style(theme::Pill::Primary),
|
||||
)
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
@ -112,7 +111,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Menu(Menu::Coins))
|
||||
.width(iced::Length::Units(200))
|
||||
};
|
||||
@ -138,7 +137,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.small()
|
||||
.bold(),
|
||||
)
|
||||
.style(badge::PillStyle::InversePrimary),
|
||||
.style(theme::Pill::InversePrimary),
|
||||
)
|
||||
})
|
||||
.spacing(10)
|
||||
@ -149,7 +148,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Primary.into())
|
||||
.style(theme::Button::Primary)
|
||||
.on_press(Message::Reload)
|
||||
.width(iced::Length::Units(200))
|
||||
} else {
|
||||
@ -173,7 +172,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.small()
|
||||
.bold(),
|
||||
)
|
||||
.style(badge::PillStyle::Primary),
|
||||
.style(theme::Pill::Primary),
|
||||
)
|
||||
})
|
||||
.spacing(10)
|
||||
@ -184,7 +183,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.padding(5)
|
||||
.center_x(),
|
||||
)
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Menu(Menu::Spend))
|
||||
.width(iced::Length::Units(200))
|
||||
};
|
||||
@ -234,14 +233,14 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> widget::Container<'a, Messa
|
||||
.push_maybe(cache.rescan_progress.map(|p| {
|
||||
Container::new(text(format!(" Rescan...{:.2}% ", p * 100.0)))
|
||||
.padding(5)
|
||||
.style(badge::PillStyle::Simple)
|
||||
.style(theme::Pill::Simple)
|
||||
}))
|
||||
.push(settings_button),
|
||||
)
|
||||
.height(Length::Shrink),
|
||||
),
|
||||
)
|
||||
.style(container::Style::Sidebar)
|
||||
.style(theme::Container::Foreground)
|
||||
}
|
||||
|
||||
pub fn dashboard<'a, T: Into<Element<'a, Message>>>(
|
||||
@ -268,9 +267,9 @@ pub fn dashboard<'a, T: Into<Element<'a, Message>>>(
|
||||
.into()
|
||||
}
|
||||
|
||||
fn main_section<'a, T: 'a>(menu: widget::Container<'a, T>) -> widget::Container<'a, T> {
|
||||
fn main_section<'a, T: 'a>(menu: Container<'a, T>) -> Container<'a, T> {
|
||||
Container::new(menu.max_width(1500))
|
||||
.style(container::Style::Background)
|
||||
.style(theme::Container::Background)
|
||||
.center_x()
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
@ -300,7 +299,7 @@ pub fn modal<'a, T: Into<Element<'a, Message>>, F: Into<Element<'a, Message>>>(
|
||||
.push(button::primary(Some(cross_icon()), "Close").on_press(Message::Close)),
|
||||
)
|
||||
.padding(10)
|
||||
.style(container::Style::Background),
|
||||
.style(theme::Container::Background),
|
||||
)
|
||||
.push(modal_section(Container::new(scrollable(content))))
|
||||
.push_maybe(fixed_footer)
|
||||
@ -309,9 +308,9 @@ pub fn modal<'a, T: Into<Element<'a, Message>>, F: Into<Element<'a, Message>>>(
|
||||
.into()
|
||||
}
|
||||
|
||||
fn modal_section<'a, T: 'a>(menu: widget::Container<'a, T>) -> widget::Container<'a, T> {
|
||||
fn modal_section<'a, T: 'a>(menu: Container<'a, T>) -> Container<'a, T> {
|
||||
Container::new(menu.max_width(1500))
|
||||
.style(container::Style::Background)
|
||||
.style(theme::Container::Background)
|
||||
.center_x()
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
use iced::{
|
||||
widget::{
|
||||
qr_code::{self, QRCode},
|
||||
Button, Column, Row,
|
||||
},
|
||||
Alignment, Element,
|
||||
widget::qr_code::{self, QRCode},
|
||||
Alignment,
|
||||
};
|
||||
|
||||
use liana::miniscript::bitcoin;
|
||||
|
||||
use crate::ui::{
|
||||
component::{button, card, text::*},
|
||||
icon,
|
||||
use liana_ui::{
|
||||
component::{card, text::*},
|
||||
icon, theme,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use super::message::Message;
|
||||
@ -25,7 +23,7 @@ pub fn receive<'a>(address: &'a bitcoin::Address, qr: &'a qr_code::State) -> Ele
|
||||
.push(
|
||||
Button::new(icon::clipboard_icon())
|
||||
.on_press(Message::Clipboard(address.to_string()))
|
||||
.style(button::Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
)
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
|
||||
@ -1,19 +1,16 @@
|
||||
use iced::{
|
||||
widget::{Column, Container, Row, Space},
|
||||
Alignment, Element, Length,
|
||||
};
|
||||
use iced::{widget::Space, Alignment, Length};
|
||||
|
||||
use liana::miniscript::bitcoin::Amount;
|
||||
|
||||
use crate::{
|
||||
app::view::message::{CreateSpendMessage, Message},
|
||||
ui::{
|
||||
component::{button, form, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
use liana_ui::{
|
||||
component::{button, form, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::app::view::message::{CreateSpendMessage, Message};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn recovery<'a>(
|
||||
locked_coins: &(usize, Amount),
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
|
||||
use iced::{
|
||||
alignment,
|
||||
widget::{self, Button, Column, Container, ProgressBar, Row, Space},
|
||||
Alignment, Element, Length,
|
||||
};
|
||||
use iced::{alignment, widget::Space, Alignment, Length};
|
||||
|
||||
use liana::miniscript::bitcoin::{util::bip32::Fingerprint, Network};
|
||||
|
||||
use super::{dashboard, message::*};
|
||||
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{badge, button, card, form, separation, text::*, tooltip::tooltip},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
cache::Cache,
|
||||
@ -19,12 +23,6 @@ use crate::{
|
||||
view::{hw, warning::warn},
|
||||
},
|
||||
hw::HardwareWallet,
|
||||
ui::{
|
||||
color,
|
||||
component::{badge, button, card, form, separation, text::*, tooltip::tooltip},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn list(cache: &Cache) -> Element<Message> {
|
||||
@ -37,7 +35,7 @@ pub fn list(cache: &Cache) -> Element<Message> {
|
||||
.width(Length::Fill)
|
||||
.push(
|
||||
Button::new(text("Settings").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Menu(Menu::Settings)))
|
||||
.push(
|
||||
Container::new(
|
||||
@ -51,11 +49,11 @@ pub fn list(cache: &Cache) -> Element<Message> {
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::Settings(SettingsMessage::EditBitcoindSettings))
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
)
|
||||
.push(
|
||||
Container::new(
|
||||
@ -69,11 +67,11 @@ pub fn list(cache: &Cache) -> Element<Message> {
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::Settings(SettingsMessage::EditWalletSettings))
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
)
|
||||
.push(
|
||||
Container::new(
|
||||
@ -88,11 +86,11 @@ pub fn list(cache: &Cache) -> Element<Message> {
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::Menu(Menu::Recovery))
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
)
|
||||
.push(
|
||||
Container::new(
|
||||
@ -106,11 +104,11 @@ pub fn list(cache: &Cache) -> Element<Message> {
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::Settings(SettingsMessage::AboutSection))
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -131,17 +129,17 @@ pub fn bitcoind_settings<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Button::new(text("Settings").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Menu(Menu::Settings)),
|
||||
)
|
||||
.push(icon::chevron_right().size(30))
|
||||
.push(
|
||||
Button::new(text("Bitcoin Core").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Settings(SettingsMessage::EditBitcoindSettings)),
|
||||
),
|
||||
)
|
||||
.push(widget::Column::with_children(settings).spacing(20)),
|
||||
.push(Column::with_children(settings).spacing(20)),
|
||||
)
|
||||
}
|
||||
|
||||
@ -162,13 +160,13 @@ pub fn about_section<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Button::new(text("Settings").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Menu(Menu::Settings)),
|
||||
)
|
||||
.push(icon::chevron_right().size(30))
|
||||
.push(
|
||||
Button::new(text("About").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Settings(SettingsMessage::AboutSection)),
|
||||
),
|
||||
)
|
||||
@ -374,12 +372,11 @@ pub fn bitcoind<'a>(
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push(if can_edit {
|
||||
widget::Button::new(icon::pencil_icon())
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
Button::new(icon::pencil_icon())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.on_press(SettingsEditMessage::Select)
|
||||
} else {
|
||||
widget::Button::new(icon::pencil_icon())
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
Button::new(icon::pencil_icon()).style(theme::Button::TransparentBorder)
|
||||
})
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
@ -391,20 +388,20 @@ pub fn bitcoind<'a>(
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn is_running_label<'a, T: 'a>(is_running: Option<bool>) -> widget::Container<'a, T> {
|
||||
pub fn is_running_label<'a, T: 'a>(is_running: Option<bool>) -> Container<'a, T> {
|
||||
if let Some(running) = is_running {
|
||||
if running {
|
||||
Container::new(
|
||||
Row::new()
|
||||
.push(icon::dot_icon().size(5).style(color::SUCCESS))
|
||||
.push(text("Running").small().style(color::SUCCESS))
|
||||
.push(icon::dot_icon().size(5).style(color::legacy::SUCCESS))
|
||||
.push(text("Running").small().style(color::legacy::SUCCESS))
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
} else {
|
||||
Container::new(
|
||||
Row::new()
|
||||
.push(icon::dot_icon().size(5).style(color::ALERT))
|
||||
.push(text("Not running").small().style(color::ALERT))
|
||||
.push(icon::dot_icon().size(5).style(color::legacy::ALERT))
|
||||
.push(text("Not running").small().style(color::legacy::ALERT))
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
}
|
||||
@ -429,7 +426,7 @@ pub fn rescan<'a>(
|
||||
.push(badge::Badge::new(icon::block_icon()))
|
||||
.push(text("Rescan blockchain").bold().width(Length::Fill))
|
||||
.push_maybe(if success {
|
||||
Some(text("Rescan was successful").style(color::SUCCESS))
|
||||
Some(text("Rescan was successful").style(color::legacy::SUCCESS))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@ -539,13 +536,13 @@ pub fn wallet_settings<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Button::new(text("Settings").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Menu(Menu::Settings)),
|
||||
)
|
||||
.push(icon::chevron_right().size(30))
|
||||
.push(
|
||||
Button::new(text("Wallet").size(30).bold())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(Message::Settings(SettingsMessage::AboutSection)),
|
||||
),
|
||||
)
|
||||
@ -604,8 +601,10 @@ pub fn wallet_settings<'a>(
|
||||
Some(
|
||||
Row::new()
|
||||
.align_items(Alignment::Center)
|
||||
.push(icon::circle_check_icon().style(color::SUCCESS))
|
||||
.push(text("Updated").style(color::SUCCESS)),
|
||||
.push(
|
||||
icon::circle_check_icon().style(color::legacy::SUCCESS),
|
||||
)
|
||||
.push(text("Updated").style(color::legacy::SUCCESS)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use iced::{
|
||||
widget::{scrollable, tooltip, Button, Column, Container, Row, Scrollable, Space},
|
||||
Alignment, Element, Length,
|
||||
widget::{scrollable, tooltip, Space},
|
||||
Alignment, Length,
|
||||
};
|
||||
|
||||
use liana::{
|
||||
@ -13,6 +13,19 @@ use liana::{
|
||||
},
|
||||
};
|
||||
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{
|
||||
badge, button, card,
|
||||
collapse::Collapse,
|
||||
form, separation,
|
||||
text::{text, Text},
|
||||
},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
error::Error,
|
||||
@ -20,17 +33,6 @@ use crate::{
|
||||
},
|
||||
daemon::model::{Coin, SpendStatus, SpendTx},
|
||||
hw::HardwareWallet,
|
||||
ui::{
|
||||
color,
|
||||
component::{
|
||||
badge, button, card,
|
||||
collapse::Collapse,
|
||||
container, form, separation,
|
||||
text::{text, Text},
|
||||
},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn spend_view<'a>(
|
||||
@ -178,16 +180,16 @@ pub fn spend_modal<'a, T: Into<Element<'a, Message>>>(
|
||||
}),
|
||||
)
|
||||
.padding(10)
|
||||
.style(container::Style::Background),
|
||||
.style(theme::Container::Background),
|
||||
)
|
||||
.push(
|
||||
Container::new(Scrollable::new(
|
||||
Container::new(scrollable(
|
||||
Container::new(Container::new(content).max_width(800))
|
||||
.width(Length::Fill)
|
||||
.center_x(),
|
||||
))
|
||||
.height(Length::Fill)
|
||||
.style(container::Style::Background),
|
||||
.style(theme::Container::Background),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
@ -200,7 +202,7 @@ fn spend_header<'a>(tx: &SpendTx) -> Element<'a, Message> {
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Row::new()
|
||||
.push(badge::Badge::new(icon::send_icon()).style(badge::Style::Standard))
|
||||
.push(badge::Badge::new(icon::send_icon()).style(theme::Badge::Standard))
|
||||
.push(if tx.sigs.recovery_path().is_some() {
|
||||
text("Recovery").bold()
|
||||
} else {
|
||||
@ -266,14 +268,14 @@ fn spend_overview_view<'a>(
|
||||
.on_press(Message::Clipboard(
|
||||
tx.psbt.unsigned_tx.txid().to_string(),
|
||||
))
|
||||
.style(button::Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
)
|
||||
.align_items(Alignment::Center),
|
||||
),
|
||||
)
|
||||
.push(signatures(tx, desc_info, key_aliases)),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -286,12 +288,12 @@ pub fn signatures<'a>(
|
||||
.push(
|
||||
if let Some(sigs) = tx.path_ready() {
|
||||
Container::new(
|
||||
Scrollable::new(
|
||||
scrollable(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.align_items(Alignment::Center)
|
||||
.push(icon::circle_check_icon().style(color::SUCCESS))
|
||||
.push(text("Ready").bold().style(color::SUCCESS))
|
||||
.push(icon::circle_check_icon().style(color::legacy::SUCCESS))
|
||||
.push(text("Ready").bold().style(color::legacy::SUCCESS))
|
||||
.push(text(", signed by"))
|
||||
.push(
|
||||
sigs.signed_pubkeys
|
||||
@ -302,16 +304,16 @@ pub fn signatures<'a>(
|
||||
tooltip::Tooltip::new(
|
||||
Container::new(text(alias))
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple),
|
||||
.style(theme::Container::Pill(theme::Pill::Simple)),
|
||||
value.0.to_string(),
|
||||
tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
)
|
||||
} else {
|
||||
Container::new(text(value.0.to_string()))
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple)
|
||||
.style(theme::Container::Pill(theme::Pill::Simple))
|
||||
})
|
||||
}),
|
||||
)
|
||||
@ -335,7 +337,7 @@ pub fn signatures<'a>(
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
},
|
||||
move || {
|
||||
Button::new(
|
||||
@ -353,7 +355,7 @@ pub fn signatures<'a>(
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
},
|
||||
move || {
|
||||
Into::<Element<'a, Message>>::into(
|
||||
@ -423,11 +425,11 @@ pub fn path_view<'a>(
|
||||
sigs.threshold - sigs.sigs_count
|
||||
};
|
||||
keys.sort();
|
||||
Scrollable::new(
|
||||
scrollable(
|
||||
Row::new()
|
||||
.align_items(Alignment::Center)
|
||||
.push(if sigs.sigs_count >= sigs.threshold {
|
||||
icon::circle_check_icon().style(color::SUCCESS)
|
||||
icon::circle_check_icon().style(color::legacy::SUCCESS)
|
||||
} else {
|
||||
icon::circle_cross_icon()
|
||||
})
|
||||
@ -452,16 +454,16 @@ pub fn path_view<'a>(
|
||||
tooltip::Tooltip::new(
|
||||
Container::new(text(alias))
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple),
|
||||
.style(theme::Container::Pill(theme::Pill::Simple)),
|
||||
value.0.to_string(),
|
||||
tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
)
|
||||
} else {
|
||||
Container::new(text(value.0.to_string()))
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple)
|
||||
.style(theme::Container::Pill(theme::Pill::Simple))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -482,16 +484,16 @@ pub fn path_view<'a>(
|
||||
tooltip::Tooltip::new(
|
||||
Container::new(text(alias))
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple),
|
||||
.style(theme::Container::Pill(theme::Pill::Simple)),
|
||||
value.0.to_string(),
|
||||
tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
)
|
||||
} else {
|
||||
Container::new(text(value.0.to_string()))
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple)
|
||||
.style(theme::Container::Pill(theme::Pill::Simple))
|
||||
})
|
||||
}),
|
||||
),
|
||||
@ -531,7 +533,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
},
|
||||
move || {
|
||||
Button::new(
|
||||
@ -550,7 +552,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
},
|
||||
move || {
|
||||
coins
|
||||
@ -575,7 +577,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
coin.outpoint.to_string(),
|
||||
))
|
||||
.style(
|
||||
button::Style::TransparentBorder.into(),
|
||||
theme::Button::TransparentBorder,
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -585,7 +587,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
.into()
|
||||
},
|
||||
))
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -609,7 +611,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
},
|
||||
move || {
|
||||
Button::new(
|
||||
@ -628,7 +630,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
)
|
||||
.padding(15)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
},
|
||||
move || {
|
||||
tx.output
|
||||
@ -655,7 +657,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
addr.to_string(),
|
||||
))
|
||||
.style(
|
||||
button::Style::TransparentBorder.into(),
|
||||
theme::Button::TransparentBorder,
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -669,7 +671,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
Some(
|
||||
Container::new(text("Change"))
|
||||
.padding(5)
|
||||
.style(badge::PillStyle::Success),
|
||||
.style(theme::Container::Pill(theme::Pill::Success)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -684,7 +686,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
Some(
|
||||
Container::new(text("Deposit"))
|
||||
.padding(5)
|
||||
.style(badge::PillStyle::Success),
|
||||
.style(theme::Container::Pill(theme::Pill::Success)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -698,7 +700,7 @@ pub fn inputs_and_outputs_view<'a>(
|
||||
.into()
|
||||
},
|
||||
))
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
),
|
||||
)
|
||||
.into()
|
||||
@ -768,9 +770,10 @@ pub fn sign_action<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(5)
|
||||
.push(
|
||||
icon::circle_check_icon().style(color::SUCCESS),
|
||||
icon::circle_check_icon()
|
||||
.style(color::legacy::SUCCESS),
|
||||
)
|
||||
.push(text("Signed").style(color::SUCCESS)),
|
||||
.push(text("Signed").style(color::legacy::SUCCESS)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -778,7 +781,7 @@ pub fn sign_action<'a>(
|
||||
)
|
||||
.on_press(Message::Spend(SpendTxMessage::SelectHotSigner))
|
||||
.padding(10)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.width(Length::Fill)
|
||||
}))
|
||||
.width(Length::Fill),
|
||||
@ -844,7 +847,7 @@ pub fn update_spend_success_view<'a>() -> Element<'a, Message> {
|
||||
Column::new()
|
||||
.push(
|
||||
card::simple(Container::new(
|
||||
text("Spend transaction is updated").style(color::SUCCESS),
|
||||
text("Spend transaction is updated").style(color::legacy::SUCCESS),
|
||||
))
|
||||
.padding(50),
|
||||
)
|
||||
|
||||
@ -1,20 +1,19 @@
|
||||
pub mod detail;
|
||||
pub mod step;
|
||||
|
||||
use iced::{
|
||||
widget::{Button, Column, Container, Row, Space},
|
||||
Alignment, Element, Length,
|
||||
use iced::{widget::Space, Alignment, Length};
|
||||
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{badge, button, card, form, text::*},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{error::Error, menu::Menu, view::util::*},
|
||||
daemon::model::{SpendStatus, SpendTx},
|
||||
ui::{
|
||||
color,
|
||||
component::{badge, button, card, form, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{message::*, warning::warn};
|
||||
@ -57,7 +56,7 @@ pub fn import_spend_success_view<'a>() -> Element<'a, Message> {
|
||||
Column::new()
|
||||
.push(
|
||||
card::simple(Container::new(
|
||||
text("PSBT is imported").style(color::SUCCESS),
|
||||
text("PSBT is imported").style(color::legacy::SUCCESS),
|
||||
))
|
||||
.padding(50),
|
||||
)
|
||||
@ -133,7 +132,7 @@ fn spend_tx_list_view<'a>(i: usize, tx: &SpendTx) -> Element<'a, Message> {
|
||||
.push(
|
||||
Container::new(text(" Recovery ").small())
|
||||
.padding(3)
|
||||
.style(badge::PillStyle::Simple),
|
||||
.style(theme::Container::Pill(theme::Pill::Simple)),
|
||||
)
|
||||
} else {
|
||||
let sigs = tx.sigs.primary_path();
|
||||
@ -172,8 +171,8 @@ fn spend_tx_list_view<'a>(i: usize, tx: &SpendTx) -> Element<'a, Message> {
|
||||
)
|
||||
.padding(10)
|
||||
.on_press(Message::Select(i))
|
||||
.style(button::Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
use iced::{
|
||||
widget::{self, Button, Column, Container, Row},
|
||||
Alignment, Element, Length,
|
||||
};
|
||||
use iced::{Alignment, Length};
|
||||
|
||||
use liana::miniscript::bitcoin::Amount;
|
||||
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{
|
||||
badge, button, form,
|
||||
text::{text, Text},
|
||||
},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
cache::Cache,
|
||||
@ -12,15 +20,6 @@ use crate::{
|
||||
view::{message::*, modal, util::amount},
|
||||
},
|
||||
daemon::model::{remaining_sequence, Coin},
|
||||
ui::{
|
||||
color,
|
||||
component::{
|
||||
badge, button, card, form,
|
||||
text::{text, Text},
|
||||
},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn choose_recipients_view<'a>(
|
||||
@ -37,7 +36,7 @@ pub fn choose_recipients_view<'a>(
|
||||
.push(text("Choose recipients").bold().size(50))
|
||||
.push(
|
||||
Column::new()
|
||||
.push(widget::Column::with_children(recipients).spacing(10))
|
||||
.push(Column::with_children(recipients).spacing(10))
|
||||
.push(
|
||||
button::transparent(Some(icon::plus_icon()), "Add recipient")
|
||||
.on_press(Message::CreateSpend(CreateSpendMessage::AddRecipient)),
|
||||
@ -64,7 +63,10 @@ pub fn choose_recipients_view<'a>(
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push_maybe(if duplicate {
|
||||
Some(text("Two recipient addresses are the same").style(color::WARNING))
|
||||
Some(
|
||||
text("Two recipient addresses are the same")
|
||||
.style(color::legacy::WARNING),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@ -213,9 +215,11 @@ fn coin_list_view<'a>(
|
||||
Some(Container::new(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.push(text(" 0").small().style(color::ALERT))
|
||||
.push(text(" 0").small().style(color::legacy::ALERT))
|
||||
.push(
|
||||
icon::hourglass_done_icon().small().style(color::ALERT),
|
||||
icon::hourglass_done_icon()
|
||||
.small()
|
||||
.style(color::legacy::ALERT),
|
||||
)
|
||||
.align_items(Alignment::Center),
|
||||
))
|
||||
@ -224,9 +228,15 @@ fn coin_list_view<'a>(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.push(
|
||||
text(format!(" {}", seq)).small().style(color::WARNING),
|
||||
text(format!(" {}", seq))
|
||||
.small()
|
||||
.style(color::legacy::WARNING),
|
||||
)
|
||||
.push(
|
||||
icon::hourglass_icon()
|
||||
.small()
|
||||
.style(color::legacy::WARNING),
|
||||
)
|
||||
.push(icon::hourglass_icon().small().style(color::WARNING))
|
||||
.align_items(Alignment::Center),
|
||||
))
|
||||
} else {
|
||||
@ -254,8 +264,8 @@ fn coin_list_view<'a>(
|
||||
)
|
||||
.padding(10)
|
||||
.on_press(Message::CreateSpend(CreateSpendMessage::SelectCoin(i)))
|
||||
.style(button::Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use iced::{widget::Row, Element};
|
||||
use liana::miniscript::bitcoin::Amount;
|
||||
|
||||
use crate::ui::{color, component::text::*, util::Collection};
|
||||
use liana_ui::{color, component::text::*, util::Collection, widget::*};
|
||||
|
||||
pub fn amount<'a, T: 'a>(a: &Amount) -> impl Into<Element<'a, T>> {
|
||||
amount_with_size(a, TEXT_REGULAR_SIZE)
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
use std::convert::From;
|
||||
|
||||
use iced::{
|
||||
widget::{self, Column, Container},
|
||||
Length,
|
||||
};
|
||||
use iced::Length;
|
||||
|
||||
use liana_ui::{component::notification, widget::*};
|
||||
|
||||
use crate::{
|
||||
app::error::Error,
|
||||
daemon::{client::error::RpcErrorCode, DaemonError},
|
||||
ui::component::notification,
|
||||
};
|
||||
|
||||
/// Simple warning message displayed to non technical user.
|
||||
@ -48,7 +46,7 @@ impl std::fmt::Display for WarningMessage {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn warn<'a, T: 'a + Clone>(error: Option<&Error>) -> widget::Container<'a, T> {
|
||||
pub fn warn<'a, T: 'a + Clone>(error: Option<&Error>) -> Container<'a, T> {
|
||||
if let Some(w) = error {
|
||||
let message: WarningMessage = w.into();
|
||||
notification::warning(message.to_string(), w.to_string()).width(Length::Fill)
|
||||
|
||||
@ -4,8 +4,9 @@ mod prompt;
|
||||
mod step;
|
||||
mod view;
|
||||
|
||||
use iced::{clipboard, Command, Element, Subscription};
|
||||
use iced::{clipboard, Command, Subscription};
|
||||
use liana::miniscript::bitcoin;
|
||||
use liana_ui::widget::Element;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use context::Context;
|
||||
|
||||
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
use liana::{
|
||||
descriptors::{LianaDescKeys, MultipathDescriptor},
|
||||
miniscript::{
|
||||
@ -17,6 +17,11 @@ use liana::{
|
||||
},
|
||||
};
|
||||
|
||||
use liana_ui::{
|
||||
component::{form, modal::Modal},
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use async_hwi::DeviceKind;
|
||||
|
||||
use crate::{
|
||||
@ -28,7 +33,6 @@ use crate::{
|
||||
view, Error,
|
||||
},
|
||||
signer::Signer,
|
||||
ui::component::{form, modal::Modal},
|
||||
};
|
||||
|
||||
pub trait DescriptorKeyModal {
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
use liana::{bip39, signer::HotSigner};
|
||||
|
||||
use liana_ui::widget::Element;
|
||||
|
||||
use crate::{
|
||||
installer::{context::Context, message::Message, step::Step, view},
|
||||
signer::Signer,
|
||||
|
||||
@ -10,10 +10,10 @@ pub use mnemonic::{BackupMnemonic, RecoverMnemonic};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use iced::{Command, Element};
|
||||
use iced::Command;
|
||||
use liana::{config::BitcoindConfig, miniscript::bitcoin};
|
||||
|
||||
use crate::ui::component::form;
|
||||
use liana_ui::{component::form, widget::*};
|
||||
|
||||
use crate::installer::{
|
||||
context::Context,
|
||||
|
||||
@ -1,12 +1,22 @@
|
||||
use iced::widget::{
|
||||
scrollable::Properties, Button, Checkbox, Column, Container, PickList, Row, Scrollable, Space,
|
||||
TextInput,
|
||||
checkbox, container, pick_list, scrollable, scrollable::Properties, Space, TextInput,
|
||||
};
|
||||
use iced::{alignment, Alignment, Element, Length};
|
||||
use iced::{alignment, Alignment, Length};
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use liana::miniscript::bitcoin;
|
||||
use liana_ui::{
|
||||
color,
|
||||
component::{
|
||||
button, card, collapse, form, separation,
|
||||
text::{text, Text},
|
||||
tooltip,
|
||||
},
|
||||
icon, theme,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
hw::HardwareWallet,
|
||||
@ -15,16 +25,6 @@ use crate::{
|
||||
message::{self, Message},
|
||||
prompt, Error,
|
||||
},
|
||||
ui::{
|
||||
color,
|
||||
component::{
|
||||
button, card, collapse, container, form, separation,
|
||||
text::{text, Text},
|
||||
tooltip,
|
||||
},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -92,7 +92,7 @@ pub fn welcome<'a>() -> Element<'a, Message> {
|
||||
)
|
||||
.padding(20),
|
||||
)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::CreateWallet),
|
||||
)
|
||||
.push(
|
||||
@ -106,7 +106,7 @@ pub fn welcome<'a>() -> Element<'a, Message> {
|
||||
)
|
||||
.padding(20),
|
||||
)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::ParticipateWallet),
|
||||
)
|
||||
.push(
|
||||
@ -120,7 +120,7 @@ pub fn welcome<'a>() -> Element<'a, Message> {
|
||||
)
|
||||
.padding(20),
|
||||
)
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::ImportWallet),
|
||||
),
|
||||
)
|
||||
@ -153,10 +153,11 @@ pub fn define_descriptor<'a>(
|
||||
.spacing(10)
|
||||
.align_items(Alignment::Center)
|
||||
.push(text("Network:").bold())
|
||||
.push(Container::new(
|
||||
PickList::new(&NETWORKS[..], Some(Network::from(network)), |net| {
|
||||
.push(container(
|
||||
pick_list(&NETWORKS[..], Some(Network::from(network)), |net| {
|
||||
Message::Network(net.into())
|
||||
})
|
||||
.style(theme::PickList::Simple)
|
||||
.padding(10),
|
||||
))
|
||||
.push_maybe(if network_valid {
|
||||
@ -195,7 +196,7 @@ pub fn define_descriptor<'a>(
|
||||
None
|
||||
})
|
||||
.push(
|
||||
Scrollable::new(
|
||||
scrollable(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.align_items(Alignment::Center)
|
||||
@ -210,7 +211,7 @@ pub fn define_descriptor<'a>(
|
||||
)
|
||||
.width(Length::Units(200))
|
||||
.height(Length::Units(200))
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.on_press(
|
||||
Message::DefineDescriptor(
|
||||
message::DefineDescriptor::AddKey(false),
|
||||
@ -252,7 +253,7 @@ pub fn define_descriptor<'a>(
|
||||
None
|
||||
})
|
||||
.push(
|
||||
Scrollable::new(
|
||||
scrollable(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.align_items(Alignment::Center)
|
||||
@ -267,7 +268,7 @@ pub fn define_descriptor<'a>(
|
||||
)
|
||||
.width(Length::Units(200))
|
||||
.height(Length::Units(200))
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.on_press(
|
||||
Message::DefineDescriptor(
|
||||
message::DefineDescriptor::AddKey(true),
|
||||
@ -359,7 +360,7 @@ pub fn import_descriptor<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.push(text("Network:").bold())
|
||||
.push(Container::new(
|
||||
PickList::new(&NETWORKS[..], Some(Network::from(network)), |net| {
|
||||
pick_list(&NETWORKS[..], Some(Network::from(network)), |net| {
|
||||
Message::Network(net.into())
|
||||
})
|
||||
.padding(10),
|
||||
@ -430,7 +431,7 @@ pub fn signer_xpubs(xpubs: &Vec<String>) -> Element<Message> {
|
||||
)
|
||||
.on_press(Message::UseHotSigner)
|
||||
.padding(10)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push_maybe(if xpubs.is_empty() {
|
||||
@ -448,7 +449,7 @@ pub fn signer_xpubs(xpubs: &Vec<String>) -> Element<Message> {
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Container::new(
|
||||
Scrollable::new(Container::new(text(xpub).small()).padding(10))
|
||||
scrollable(Container::new(text(xpub).small()).padding(10))
|
||||
.horizontal_scroll(
|
||||
Properties::new().width(2).scroller_width(2),
|
||||
),
|
||||
@ -478,7 +479,7 @@ pub fn signer_xpubs(xpubs: &Vec<String>) -> Element<Message> {
|
||||
None
|
||||
}),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -523,7 +524,7 @@ pub fn hardware_wallet_xpubs<'a>(
|
||||
message,
|
||||
iced::widget::tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
),
|
||||
})
|
||||
.spacing(5)
|
||||
@ -534,16 +535,16 @@ pub fn hardware_wallet_xpubs<'a>(
|
||||
Row::new()
|
||||
.spacing(5)
|
||||
.align_items(Alignment::Center)
|
||||
.push(icon::warning_icon().style(color::ALERT))
|
||||
.push(text("An error occured").style(color::ALERT)),
|
||||
.push(icon::warning_icon().style(color::legacy::ALERT))
|
||||
.push(text("An error occured").style(color::legacy::ALERT)),
|
||||
e,
|
||||
iced::widget::tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::ErrorCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Error))
|
||||
})),
|
||||
)
|
||||
.padding(10)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.width(Length::Fill);
|
||||
if !processing && hw.is_supported() {
|
||||
bttn = bttn.on_press(Message::Select(i));
|
||||
@ -566,7 +567,7 @@ pub fn hardware_wallet_xpubs<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Container::new(
|
||||
Scrollable::new(Container::new(text(xpub).small()).padding(10))
|
||||
scrollable(Container::new(text(xpub).small()).padding(10))
|
||||
.horizontal_scroll(
|
||||
Properties::new().width(2).scroller_width(2),
|
||||
),
|
||||
@ -598,7 +599,7 @@ pub fn hardware_wallet_xpubs<'a>(
|
||||
None
|
||||
}),
|
||||
)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -615,7 +616,7 @@ pub fn participate_xpub<'a>(
|
||||
.align_items(Alignment::Center)
|
||||
.push(text("Network:").bold())
|
||||
.push(Container::new(
|
||||
PickList::new(&NETWORKS[..], Some(Network::from(network)), |net| {
|
||||
pick_list(&NETWORKS[..], Some(Network::from(network)), |net| {
|
||||
Message::Network(net.into())
|
||||
})
|
||||
.padding(10),
|
||||
@ -658,7 +659,7 @@ pub fn participate_xpub<'a>(
|
||||
.push(signer)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push(Checkbox::new(
|
||||
.push(checkbox(
|
||||
"I have shared my public keys",
|
||||
shared,
|
||||
Message::UserActionDone,
|
||||
@ -744,7 +745,7 @@ pub fn register_descriptor<'a>(
|
||||
)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push(Checkbox::new(
|
||||
.push(checkbox(
|
||||
"I have registered the descriptor on my device(s)",
|
||||
done,
|
||||
Message::UserActionDone,
|
||||
@ -789,7 +790,7 @@ pub fn backup_descriptor<'a>(
|
||||
.push(text("Learn more").small().bold())
|
||||
.push(icon::collapse_icon()),
|
||||
)
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
},
|
||||
|| {
|
||||
Button::new(
|
||||
@ -799,7 +800,7 @@ pub fn backup_descriptor<'a>(
|
||||
.push(text("Learn more").small().bold())
|
||||
.push(icon::collapsed_icon()),
|
||||
)
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
},
|
||||
help_backup,
|
||||
))
|
||||
@ -818,7 +819,7 @@ pub fn backup_descriptor<'a>(
|
||||
.spacing(10)
|
||||
.max_width(1000),
|
||||
))
|
||||
.push(Checkbox::new(
|
||||
.push(checkbox(
|
||||
"I have backed up my descriptor",
|
||||
done,
|
||||
Message::UserActionDone,
|
||||
@ -1051,7 +1052,7 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> {
|
||||
.push(Space::with_width(Length::Fill))
|
||||
.push(
|
||||
Button::new(icon::cross_icon())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(message::DefineKey::Delete),
|
||||
),
|
||||
)
|
||||
@ -1061,7 +1062,7 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> {
|
||||
.spacing(15)
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Scrollable::new(
|
||||
scrollable(
|
||||
icon::key_icon()
|
||||
.style(color::DARK_GREY)
|
||||
.size(50)
|
||||
@ -1069,7 +1070,11 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> {
|
||||
)
|
||||
.horizontal_scroll(Properties::new().width(2).scroller_width(2)),
|
||||
)
|
||||
.push(icon::circle_check_icon().style(color::FOREGROUND).size(50)),
|
||||
.push(
|
||||
icon::circle_check_icon()
|
||||
.style(color::legacy::FOREGROUND)
|
||||
.size(50),
|
||||
),
|
||||
)
|
||||
.height(Length::Fill)
|
||||
.align_y(alignment::Vertical::Center),
|
||||
@ -1100,7 +1105,7 @@ pub fn defined_descriptor_key(
|
||||
.push(Space::with_width(Length::Fill))
|
||||
.push(
|
||||
Button::new(icon::cross_icon())
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.on_press(message::DefineKey::Delete),
|
||||
),
|
||||
)
|
||||
@ -1114,13 +1119,13 @@ pub fn defined_descriptor_key(
|
||||
.spacing(15)
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
Scrollable::new(text(name).bold()).horizontal_scroll(
|
||||
scrollable(text(name).bold()).horizontal_scroll(
|
||||
Properties::new().width(2).scroller_width(2),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
icon::circle_check_icon()
|
||||
.style(color::SUCCESS)
|
||||
.style(color::legacy::SUCCESS)
|
||||
.size(40)
|
||||
.width(Length::Units(50)),
|
||||
),
|
||||
@ -1145,7 +1150,7 @@ pub fn defined_descriptor_key(
|
||||
.push(
|
||||
text("Key is for a different network")
|
||||
.small()
|
||||
.style(color::ALERT),
|
||||
.style(color::legacy::ALERT),
|
||||
)
|
||||
.into()
|
||||
} else if duplicate_key {
|
||||
@ -1157,7 +1162,7 @@ pub fn defined_descriptor_key(
|
||||
.height(Length::Units(200))
|
||||
.width(Length::Units(200)),
|
||||
)
|
||||
.push(text("Duplicate key").small().style(color::ALERT))
|
||||
.push(text("Duplicate key").small().style(color::legacy::ALERT))
|
||||
.into()
|
||||
} else if duplicate_name {
|
||||
Column::new()
|
||||
@ -1168,7 +1173,7 @@ pub fn defined_descriptor_key(
|
||||
.height(Length::Units(200))
|
||||
.width(Length::Units(200)),
|
||||
)
|
||||
.push(text("Duplicate name").small().style(color::ALERT))
|
||||
.push(text("Duplicate name").small().style(color::legacy::ALERT))
|
||||
.into()
|
||||
} else {
|
||||
card::simple(col)
|
||||
@ -1243,7 +1248,7 @@ pub fn edit_key_modal<'a>(
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push_maybe(if chosen_signer {
|
||||
Some(icon::circle_check_icon().style(color::SUCCESS))
|
||||
Some(icon::circle_check_icon().style(color::legacy::SUCCESS))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@ -1251,7 +1256,7 @@ pub fn edit_key_modal<'a>(
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.on_press(Message::UseHotSigner)
|
||||
.style(button::Style::Border.into()),
|
||||
.style(theme::Button::Secondary),
|
||||
)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
@ -1382,7 +1387,7 @@ fn hw_list_view(
|
||||
message,
|
||||
iced::widget::tooltip::Position::Bottom,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
.style(theme::Container::Card(theme::Card::Simple)),
|
||||
),
|
||||
})
|
||||
.spacing(5)
|
||||
@ -1398,7 +1403,7 @@ fn hw_list_view(
|
||||
None
|
||||
})
|
||||
.push_maybe(if registered {
|
||||
Some(Column::new().push(icon::circle_check_icon().style(color::SUCCESS)))
|
||||
Some(Column::new().push(icon::circle_check_icon().style(color::legacy::SUCCESS)))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@ -1406,14 +1411,14 @@ fn hw_list_view(
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.padding(10)
|
||||
.style(button::Style::TransparentBorder.into())
|
||||
.style(theme::Button::TransparentBorder)
|
||||
.width(Length::Fill);
|
||||
if !processing && hw.is_supported() {
|
||||
bttn = bttn.on_press(Message::Select(i));
|
||||
}
|
||||
Container::new(bttn)
|
||||
.width(Length::Fill)
|
||||
.style(card::SimpleCardStyle)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -1443,7 +1448,7 @@ pub fn backup_mnemonic<'a>(
|
||||
)
|
||||
}),
|
||||
)
|
||||
.push(Checkbox::new(
|
||||
.push(checkbox(
|
||||
"I have backed up my mnemonic",
|
||||
done,
|
||||
Message::UserActionDone,
|
||||
@ -1485,7 +1490,7 @@ pub fn recover_mnemonic<'a>(
|
||||
suggestions.iter().fold(Row::new().spacing(5), |row, sugg| {
|
||||
row.push(
|
||||
Button::new(text(sugg))
|
||||
.style(button::Style::Border.into())
|
||||
.style(theme::Button::Secondary)
|
||||
.on_press(Message::MnemonicWord(
|
||||
current,
|
||||
sugg.to_string(),
|
||||
@ -1516,7 +1521,10 @@ pub fn recover_mnemonic<'a>(
|
||||
.width(Length::Units(100)),
|
||||
)
|
||||
.push_maybe(if *valid {
|
||||
Some(icon::circle_check_icon().style(color::SUCCESS))
|
||||
Some(
|
||||
icon::circle_check_icon()
|
||||
.style(color::legacy::SUCCESS),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}),
|
||||
@ -1524,7 +1532,9 @@ pub fn recover_mnemonic<'a>(
|
||||
},
|
||||
))
|
||||
.push(Space::with_height(Length::Units(50)))
|
||||
.push_maybe(error.map(|e| card::invalid(text(e).style(color::ALERT)))),
|
||||
.push_maybe(
|
||||
error.map(|e| card::invalid(text(e).style(color::legacy::ALERT))),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -1572,7 +1582,7 @@ fn layout<'a>(
|
||||
progress: (usize, usize),
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
Container::new(Scrollable::new(
|
||||
Container::new(scrollable(
|
||||
Column::new()
|
||||
.push(
|
||||
Container::new(button::transparent(None, "< Previous").on_press(Message::Previous))
|
||||
@ -1588,19 +1598,15 @@ fn layout<'a>(
|
||||
.center_x()
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.style(container::Style::Background)
|
||||
.style(theme::Container::Background)
|
||||
.into()
|
||||
}
|
||||
|
||||
mod threshsold_input {
|
||||
use crate::ui::{
|
||||
component::{button, text::*},
|
||||
icon,
|
||||
};
|
||||
use iced::alignment::{self, Alignment};
|
||||
use iced::widget::{Button, Column, Container};
|
||||
use iced::{Element, Length};
|
||||
use iced::Length;
|
||||
use iced_lazy::{self, Component};
|
||||
use liana_ui::{component::text::*, icon, theme, widget::*};
|
||||
|
||||
pub struct ThresholdInput<Message> {
|
||||
value: usize,
|
||||
@ -1636,7 +1642,7 @@ mod threshsold_input {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message> Component<Message, iced::Renderer> for ThresholdInput<Message> {
|
||||
impl<Message> Component<Message, iced::Renderer<theme::Theme>> for ThresholdInput<Message> {
|
||||
type State = ();
|
||||
type Event = Event;
|
||||
|
||||
@ -1662,7 +1668,7 @@ mod threshsold_input {
|
||||
fn view(&self, _state: &Self::State) -> Element<Self::Event> {
|
||||
let button = |label, on_press| {
|
||||
Button::new(label)
|
||||
.style(button::Style::Transparent.into())
|
||||
.style(theme::Button::Transparent)
|
||||
.width(Length::Units(50))
|
||||
.on_press(on_press)
|
||||
};
|
||||
|
||||
@ -1,21 +1,17 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use iced::{
|
||||
widget::{Button, Column, Container, Row},
|
||||
Alignment, Command, Element, Length, Subscription,
|
||||
};
|
||||
use iced::{Alignment, Command, Length, Subscription};
|
||||
|
||||
use liana::{config::ConfigError, miniscript::bitcoin::Network};
|
||||
|
||||
use crate::{
|
||||
app,
|
||||
ui::{
|
||||
component::{badge, button, card, text::*},
|
||||
icon,
|
||||
util::*,
|
||||
},
|
||||
use liana_ui::{
|
||||
component::{badge, card, text::*},
|
||||
icon, theme,
|
||||
util::*,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::app;
|
||||
|
||||
pub struct Launcher {
|
||||
choices: Vec<Network>,
|
||||
datadir_path: PathBuf,
|
||||
@ -102,9 +98,9 @@ impl Launcher {
|
||||
badge::Badge::new(icon::bitcoin_icon()).style(
|
||||
match choice {
|
||||
Network::Bitcoin => {
|
||||
badge::Style::Bitcoin
|
||||
theme::Badge::Bitcoin
|
||||
}
|
||||
_ => badge::Style::Standard,
|
||||
_ => theme::Badge::Standard,
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -118,7 +114,7 @@ impl Launcher {
|
||||
.on_press(ViewMessage::Check(*choice))
|
||||
.padding(10)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::Border.into()),
|
||||
.style(theme::Button::Secondary),
|
||||
)
|
||||
},
|
||||
)
|
||||
@ -133,7 +129,7 @@ impl Launcher {
|
||||
.on_press(ViewMessage::StartInstall)
|
||||
.padding(10)
|
||||
.width(Length::Fill)
|
||||
.style(button::Style::TransparentBorder.into()),
|
||||
.style(theme::Button::TransparentBorder),
|
||||
),
|
||||
)
|
||||
.max_width(500)
|
||||
|
||||
@ -6,7 +6,6 @@ pub mod launcher;
|
||||
pub mod loader;
|
||||
pub mod logger;
|
||||
pub mod signer;
|
||||
pub mod ui;
|
||||
pub mod utils;
|
||||
|
||||
use liana::Version;
|
||||
|
||||
@ -3,10 +3,6 @@ use std::io::ErrorKind;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use iced::{
|
||||
widget::{Column, Container, ProgressBar, Row},
|
||||
Element,
|
||||
};
|
||||
use iced::{Alignment, Command, Length, Subscription};
|
||||
use tracing::{debug, info};
|
||||
|
||||
@ -15,6 +11,12 @@ use liana::{
|
||||
miniscript::bitcoin,
|
||||
StartupError,
|
||||
};
|
||||
use liana_ui::{
|
||||
component::{button, notification, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
widget::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{
|
||||
@ -23,11 +25,6 @@ use crate::{
|
||||
wallet::{Wallet, WalletError},
|
||||
},
|
||||
daemon::{client, embedded::EmbeddedDaemon, model::*, Daemon, DaemonError},
|
||||
ui::{
|
||||
component::{button, notification, text::*},
|
||||
icon,
|
||||
util::Collection,
|
||||
},
|
||||
};
|
||||
|
||||
type Lianad = client::Lianad<client::jsonrpc::JsonRPCClient>;
|
||||
|
||||
@ -2,13 +2,14 @@
|
||||
|
||||
use std::{error::Error, io::Write, path::PathBuf, str::FromStr};
|
||||
|
||||
use iced::{executor, Application, Command, Element, Settings, Subscription};
|
||||
use iced::{executor, Application, Command, Settings, Subscription};
|
||||
use tracing::{error, info};
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
use liana::{config::Config as DaemonConfig, miniscript::bitcoin};
|
||||
use liana_ui::{theme, widget::Element};
|
||||
|
||||
use liana_gui::{
|
||||
app::{
|
||||
@ -87,7 +88,7 @@ impl Application for GUI {
|
||||
type Executor = executor::Default;
|
||||
type Message = Message;
|
||||
type Flags = Config;
|
||||
type Theme = iced::Theme;
|
||||
type Theme = theme::Theme;
|
||||
|
||||
fn title(&self) -> String {
|
||||
match self.state {
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
use iced::Color;
|
||||
|
||||
pub const BACKGROUND: Color = Color::from_rgb(
|
||||
0xF6 as f32 / 255.0,
|
||||
0xF7 as f32 / 255.0,
|
||||
0xF8 as f32 / 255.0,
|
||||
);
|
||||
|
||||
pub const BORDER_GREY: Color = Color::from_rgb(
|
||||
0xd0 as f32 / 255.0,
|
||||
0xd7 as f32 / 255.0,
|
||||
0xde as f32 / 255.0,
|
||||
);
|
||||
|
||||
pub const FOREGROUND: Color = Color::WHITE;
|
||||
|
||||
pub const PRIMARY: Color = Color::BLACK;
|
||||
|
||||
pub const SECONDARY: Color = DARK_GREY;
|
||||
|
||||
pub const SUCCESS: Color = Color::from_rgb(
|
||||
0x29 as f32 / 255.0,
|
||||
0xBC as f32 / 255.0,
|
||||
0x97 as f32 / 255.0,
|
||||
);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const SUCCESS_LIGHT: Color = Color::from_rgba(
|
||||
0x29 as f32 / 255.0,
|
||||
0xBC as f32 / 255.0,
|
||||
0x97 as f32 / 255.0,
|
||||
0.5f32,
|
||||
);
|
||||
|
||||
pub const ALERT: Color = Color::from_rgb(
|
||||
0xF0 as f32 / 255.0,
|
||||
0x43 as f32 / 255.0,
|
||||
0x59 as f32 / 255.0,
|
||||
);
|
||||
|
||||
pub const ALERT_LIGHT: Color = Color::from_rgba(
|
||||
0xF0 as f32 / 255.0,
|
||||
0x43 as f32 / 255.0,
|
||||
0x59 as f32 / 255.0,
|
||||
0.5f32,
|
||||
);
|
||||
|
||||
pub const WARNING: Color =
|
||||
Color::from_rgb(0xFF as f32 / 255.0, 0xa7 as f32 / 255.0, 0x0 as f32 / 255.0);
|
||||
|
||||
pub const WARNING_LIGHT: Color = Color::from_rgba(
|
||||
0xFF as f32 / 255.0,
|
||||
0xa7 as f32 / 255.0,
|
||||
0x0 as f32 / 255.0,
|
||||
0.5f32,
|
||||
);
|
||||
|
||||
pub const CANCEL: Color = Color::from_rgb(
|
||||
0x34 as f32 / 255.0,
|
||||
0x37 as f32 / 255.0,
|
||||
0x3D as f32 / 255.0,
|
||||
);
|
||||
|
||||
pub const INFO: Color = Color::from_rgb(
|
||||
0x2A as f32 / 255.0,
|
||||
0x98 as f32 / 255.0,
|
||||
0xBD as f32 / 255.0,
|
||||
);
|
||||
|
||||
pub const INFO_LIGHT: Color = Color::from_rgba(
|
||||
0x2A as f32 / 255.0,
|
||||
0x98 as f32 / 255.0,
|
||||
0xBD as f32 / 255.0,
|
||||
0.5f32,
|
||||
);
|
||||
|
||||
pub const DARK_GREY: Color = Color::from_rgb(
|
||||
0x8c as f32 / 255.0,
|
||||
0x97 as f32 / 255.0,
|
||||
0xa6 as f32 / 255.0,
|
||||
);
|
||||
@ -1,209 +0,0 @@
|
||||
use iced::{
|
||||
widget::{self, tooltip, Container},
|
||||
Element, Length,
|
||||
};
|
||||
|
||||
use crate::ui::{
|
||||
color,
|
||||
component::{card, text::*},
|
||||
icon,
|
||||
};
|
||||
|
||||
pub enum Style {
|
||||
Standard,
|
||||
Success,
|
||||
Warning,
|
||||
Bitcoin,
|
||||
}
|
||||
|
||||
impl widget::container::StyleSheet for Style {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
match self {
|
||||
Self::Standard => widget::container::Appearance {
|
||||
border_radius: 40.0,
|
||||
background: color::BACKGROUND.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
Self::Success => widget::container::Appearance {
|
||||
border_radius: 40.0,
|
||||
background: color::SUCCESS_LIGHT.into(),
|
||||
text_color: color::SUCCESS.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
Self::Warning => widget::container::Appearance {
|
||||
border_radius: 40.0,
|
||||
background: color::WARNING_LIGHT.into(),
|
||||
text_color: color::WARNING.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
Self::Bitcoin => widget::container::Appearance {
|
||||
border_radius: 40.0,
|
||||
background: color::WARNING.into(),
|
||||
text_color: iced::Color::WHITE.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: Style) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for iced::theme::Container {
|
||||
fn from(i: Style) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Badge {
|
||||
icon: widget::Text<'static>,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl Badge {
|
||||
pub fn new(icon: widget::Text<'static>) -> Self {
|
||||
Self {
|
||||
icon,
|
||||
style: Style::Standard,
|
||||
}
|
||||
}
|
||||
pub fn style(self, style: Style) -> Self {
|
||||
Self {
|
||||
icon: self.icon,
|
||||
style,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a> From<Badge> for Element<'a, Message> {
|
||||
fn from(badge: Badge) -> Element<'a, Message> {
|
||||
Container::new(badge.icon.width(Length::Units(20)))
|
||||
.width(Length::Units(40))
|
||||
.height(Length::Units(40))
|
||||
.style(badge.style)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive<T>() -> widget::container::Container<'static, T> {
|
||||
Container::new(icon::receive_icon().width(Length::Units(20)))
|
||||
.width(Length::Units(40))
|
||||
.height(Length::Units(40))
|
||||
.style(Style::Standard)
|
||||
.center_x()
|
||||
.center_y()
|
||||
}
|
||||
|
||||
pub fn spend<T>() -> widget::container::Container<'static, T> {
|
||||
Container::new(icon::send_icon().width(Length::Units(20)))
|
||||
.width(Length::Units(40))
|
||||
.height(Length::Units(40))
|
||||
.style(Style::Standard)
|
||||
.center_x()
|
||||
.center_y()
|
||||
}
|
||||
|
||||
pub fn coin<T>() -> widget::container::Container<'static, T> {
|
||||
Container::new(icon::coin_icon().width(Length::Units(20)))
|
||||
.width(Length::Units(40))
|
||||
.height(Length::Units(40))
|
||||
.style(Style::Standard)
|
||||
.center_x()
|
||||
.center_y()
|
||||
}
|
||||
|
||||
pub enum PillStyle {
|
||||
InversePrimary,
|
||||
Primary,
|
||||
Success,
|
||||
Simple,
|
||||
}
|
||||
|
||||
impl widget::container::StyleSheet for PillStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
match self {
|
||||
Self::Primary => widget::container::Appearance {
|
||||
background: color::PRIMARY.into(),
|
||||
border_radius: 10.0,
|
||||
text_color: iced::Color::WHITE.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
Self::InversePrimary => widget::container::Appearance {
|
||||
background: color::FOREGROUND.into(),
|
||||
border_radius: 10.0,
|
||||
text_color: color::PRIMARY.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
Self::Success => widget::container::Appearance {
|
||||
background: color::SUCCESS.into(),
|
||||
border_radius: 10.0,
|
||||
text_color: iced::Color::WHITE.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
Self::Simple => widget::container::Appearance {
|
||||
background: color::BACKGROUND.into(),
|
||||
border_radius: 10.0,
|
||||
text_color: iced::Color::BLACK.into(),
|
||||
..widget::container::Appearance::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PillStyle> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: PillStyle) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PillStyle> for iced::theme::Container {
|
||||
fn from(i: PillStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unconfirmed<'a, T: 'a>() -> widget::container::Container<'a, T> {
|
||||
Container::new(
|
||||
tooltip::Tooltip::new(
|
||||
Container::new(text(" Unconfirmed ").small())
|
||||
.padding(3)
|
||||
.style(PillStyle::Simple),
|
||||
"Do not treat this as a payment until it is confirmed",
|
||||
tooltip::Position::Top,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn deprecated<'a, T: 'a>() -> widget::container::Container<'a, T> {
|
||||
Container::new(
|
||||
tooltip::Tooltip::new(
|
||||
Container::new(text(" Deprecated ").small())
|
||||
.padding(3)
|
||||
.style(PillStyle::Simple),
|
||||
"This spend cannot be included anymore in the blockchain",
|
||||
tooltip::Position::Top,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn spent<'a, T: 'a>() -> widget::container::Container<'a, T> {
|
||||
Container::new(
|
||||
tooltip::Tooltip::new(
|
||||
Container::new(text(" Spent ").small())
|
||||
.padding(3)
|
||||
.style(PillStyle::Simple),
|
||||
"The spend transaction was included in the blockchain",
|
||||
tooltip::Position::Top,
|
||||
)
|
||||
.style(card::SimpleCardStyle),
|
||||
)
|
||||
}
|
||||
@ -1,151 +0,0 @@
|
||||
use iced::widget::{button, container, Container, Row, Text};
|
||||
use iced::{Alignment, Color, Length, Vector};
|
||||
|
||||
use super::text::text;
|
||||
use crate::ui::color;
|
||||
|
||||
pub fn alert<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> button::Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(Style::Destructive.into())
|
||||
}
|
||||
|
||||
pub fn primary<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> button::Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(Style::Primary.into())
|
||||
}
|
||||
|
||||
pub fn transparent<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> button::Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(Style::Transparent.into())
|
||||
}
|
||||
|
||||
pub fn border<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> button::Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(Style::Border.into())
|
||||
}
|
||||
|
||||
pub fn transparent_border<'a, T: 'a>(
|
||||
icon: Option<Text<'a>>,
|
||||
t: &'static str,
|
||||
) -> button::Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(Style::TransparentBorder.into())
|
||||
}
|
||||
|
||||
fn content<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Container<'a, T> {
|
||||
match icon {
|
||||
None => container(text(t)).width(Length::Fill).center_x().padding(5),
|
||||
Some(i) => container(
|
||||
Row::new()
|
||||
.push(i)
|
||||
.push(text(t))
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
.width(iced::Length::Fill)
|
||||
.center_x()
|
||||
.padding(5),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Style {
|
||||
Primary,
|
||||
Transparent,
|
||||
TransparentBorder,
|
||||
Border,
|
||||
Destructive,
|
||||
}
|
||||
|
||||
impl button::StyleSheet for Style {
|
||||
type Style = iced::Theme;
|
||||
fn active(&self, _style: &Self::Style) -> button::Appearance {
|
||||
match self {
|
||||
Style::Primary => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color::PRIMARY.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
text_color: color::FOREGROUND,
|
||||
},
|
||||
Style::Destructive => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color::FOREGROUND.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: color::ALERT,
|
||||
text_color: color::ALERT,
|
||||
},
|
||||
Style::Transparent | Style::TransparentBorder => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Color::TRANSPARENT.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
text_color: Color::BLACK,
|
||||
},
|
||||
Style::Border => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Color::TRANSPARENT.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 1.2,
|
||||
border_color: color::BORDER_GREY,
|
||||
text_color: Color::BLACK,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, _style: &Self::Style) -> button::Appearance {
|
||||
match self {
|
||||
Style::Primary => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color::PRIMARY.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
text_color: color::FOREGROUND,
|
||||
},
|
||||
Style::Destructive => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color::FOREGROUND.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: color::ALERT,
|
||||
text_color: color::ALERT,
|
||||
},
|
||||
Style::Transparent => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Color::TRANSPARENT.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
text_color: Color::BLACK,
|
||||
},
|
||||
Style::TransparentBorder => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Color::TRANSPARENT.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 1.0,
|
||||
border_color: Color::BLACK,
|
||||
text_color: Color::BLACK,
|
||||
},
|
||||
Style::Border => button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Color::TRANSPARENT.into(),
|
||||
border_radius: 10.0,
|
||||
border_width: 1.0,
|
||||
border_color: Color::BLACK,
|
||||
text_color: Color::BLACK,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for Box<dyn button::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: Style) -> Box<dyn button::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for iced::theme::Button {
|
||||
fn from(i: Style) -> iced::theme::Button {
|
||||
iced::theme::Button::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,149 +0,0 @@
|
||||
use iced::{
|
||||
widget::{self, Container, Row, Tooltip},
|
||||
Element,
|
||||
};
|
||||
|
||||
use crate::ui::{color, component::text::text, icon};
|
||||
|
||||
pub fn simple<'a, T: 'a, C: Into<Element<'a, T>>>(content: C) -> widget::Container<'a, T> {
|
||||
Container::new(content).padding(15).style(SimpleCardStyle)
|
||||
}
|
||||
|
||||
pub struct SimpleCardStyle;
|
||||
impl widget::container::StyleSheet for SimpleCardStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
widget::container::Appearance {
|
||||
border_radius: 10.0,
|
||||
border_color: color::BORDER_GREY,
|
||||
border_width: 1.0,
|
||||
background: color::FOREGROUND.into(),
|
||||
..widget::container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SimpleCardStyle> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: SimpleCardStyle) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SimpleCardStyle> for iced::theme::Container {
|
||||
fn from(i: SimpleCardStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalid<'a, T: 'a, C: Into<Element<'a, T>>>(content: C) -> widget::Container<'a, T> {
|
||||
Container::new(content).padding(15).style(InvalidCardStyle)
|
||||
}
|
||||
|
||||
pub struct InvalidCardStyle;
|
||||
impl widget::container::StyleSheet for InvalidCardStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
widget::container::Appearance {
|
||||
border_radius: 10.0,
|
||||
border_color: color::ALERT,
|
||||
border_width: 1.0,
|
||||
background: color::FOREGROUND.into(),
|
||||
..widget::container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidCardStyle> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: InvalidCardStyle) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidCardStyle> for iced::theme::Container {
|
||||
fn from(i: InvalidCardStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// display an error card with the message and the error in a tooltip.
|
||||
pub fn warning<'a, T: 'a>(message: String) -> widget::Container<'a, T> {
|
||||
Container::new(
|
||||
Row::new()
|
||||
.spacing(20)
|
||||
.align_items(iced::Alignment::Center)
|
||||
.push(icon::warning_octagon_icon().style(color::WARNING))
|
||||
.push(text(message).style(color::WARNING)),
|
||||
)
|
||||
.padding(15)
|
||||
.style(WarningCardStyle)
|
||||
}
|
||||
|
||||
pub struct WarningCardStyle;
|
||||
impl widget::container::StyleSheet for WarningCardStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
widget::container::Appearance {
|
||||
border_radius: 10.0,
|
||||
border_color: color::WARNING,
|
||||
border_width: 1.5,
|
||||
background: color::FOREGROUND.into(),
|
||||
..widget::container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WarningCardStyle> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: WarningCardStyle) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WarningCardStyle> for iced::theme::Container {
|
||||
fn from(i: WarningCardStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// display an error card with the message and the error in a tooltip.
|
||||
pub fn error<'a, T: 'a>(message: &'static str, error: String) -> widget::Container<'a, T> {
|
||||
Container::new(
|
||||
Tooltip::new(
|
||||
Row::new()
|
||||
.spacing(20)
|
||||
.align_items(iced::Alignment::Center)
|
||||
.push(icon::warning_icon().style(color::ALERT))
|
||||
.push(text(message).style(color::ALERT)),
|
||||
error,
|
||||
widget::tooltip::Position::Bottom,
|
||||
)
|
||||
.style(ErrorCardStyle),
|
||||
)
|
||||
.padding(15)
|
||||
.style(ErrorCardStyle)
|
||||
}
|
||||
|
||||
pub struct ErrorCardStyle;
|
||||
impl widget::container::StyleSheet for ErrorCardStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
widget::container::Appearance {
|
||||
border_radius: 10.0,
|
||||
border_color: color::ALERT,
|
||||
border_width: 1.5,
|
||||
background: color::FOREGROUND.into(),
|
||||
..widget::container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorCardStyle> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: ErrorCardStyle) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorCardStyle> for iced::theme::Container {
|
||||
fn from(i: ErrorCardStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,85 +0,0 @@
|
||||
use iced::{
|
||||
widget::{Button, Column},
|
||||
Element,
|
||||
};
|
||||
use iced_lazy::{self, Component};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct Collapse<'a, M, H, F, C> {
|
||||
before: H,
|
||||
after: F,
|
||||
content: C,
|
||||
phantom: PhantomData<&'a M>,
|
||||
}
|
||||
|
||||
impl<'a, Message, T, H, F, C> Collapse<'a, Message, H, F, C>
|
||||
where
|
||||
Message: 'a,
|
||||
T: Into<Message> + Clone + 'a,
|
||||
H: Fn() -> Button<'a, Event<T>> + 'a,
|
||||
F: Fn() -> Button<'a, Event<T>> + 'a,
|
||||
C: Fn() -> Element<'a, T> + 'a,
|
||||
{
|
||||
pub fn new(before: H, after: F, content: C) -> Self {
|
||||
Collapse {
|
||||
before,
|
||||
after,
|
||||
content,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Event<T> {
|
||||
Internal(T),
|
||||
Collapse(bool),
|
||||
}
|
||||
|
||||
impl<'a, Message, T, H, F, C> Component<Message, iced::Renderer> for Collapse<'a, Message, H, F, C>
|
||||
where
|
||||
T: Into<Message> + Clone + 'a,
|
||||
H: Fn() -> Button<'a, Event<T>>,
|
||||
F: Fn() -> Button<'a, Event<T>>,
|
||||
C: Fn() -> Element<'a, T>,
|
||||
{
|
||||
type State = bool;
|
||||
type Event = Event<T>;
|
||||
|
||||
fn update(&mut self, state: &mut Self::State, event: Event<T>) -> Option<Message> {
|
||||
match event {
|
||||
Event::Internal(e) => Some(e.into()),
|
||||
Event::Collapse(s) => {
|
||||
*state = s;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, state: &Self::State) -> Element<Self::Event> {
|
||||
if *state {
|
||||
Column::new()
|
||||
.push((self.after)().on_press(Event::Collapse(false)))
|
||||
.push((self.content)().map(Event::Internal))
|
||||
.into()
|
||||
} else {
|
||||
Column::new()
|
||||
.push((self.before)().on_press(Event::Collapse(true)))
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, T, H: 'a, F: 'a, C: 'a> From<Collapse<'a, Message, H, F, C>>
|
||||
for Element<'a, Message>
|
||||
where
|
||||
Message: 'a,
|
||||
T: Into<Message> + Clone + 'a,
|
||||
H: Fn() -> Button<'a, Event<T>, iced::Renderer>,
|
||||
F: Fn() -> Button<'a, Event<T>, iced::Renderer>,
|
||||
C: Fn() -> Element<'a, T, iced::Renderer>,
|
||||
{
|
||||
fn from(c: Collapse<'a, Message, H, F, C>) -> Self {
|
||||
iced_lazy::component(c)
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
use crate::ui::color;
|
||||
use iced::widget::container;
|
||||
|
||||
pub enum Style {
|
||||
Sidebar,
|
||||
Background,
|
||||
}
|
||||
|
||||
impl container::StyleSheet for Style {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> container::Appearance {
|
||||
match self {
|
||||
Self::Background => container::Appearance {
|
||||
background: color::BACKGROUND.into(),
|
||||
..container::Appearance::default()
|
||||
},
|
||||
Self::Sidebar => container::Appearance {
|
||||
background: color::FOREGROUND.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::BORDER_GREY,
|
||||
..container::Appearance::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for Box<dyn container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: Style) -> Box<dyn container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for iced::theme::Container {
|
||||
fn from(i: Style) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,137 +0,0 @@
|
||||
use iced::{
|
||||
widget::{
|
||||
text_input::{Appearance, StyleSheet, TextInput},
|
||||
Column, Container,
|
||||
},
|
||||
Element, Length,
|
||||
};
|
||||
|
||||
use crate::ui::{color, component::text::*, util::Collection};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Value<T> {
|
||||
pub value: T,
|
||||
pub valid: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for Value<String> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
value: "".to_string(),
|
||||
valid: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Form<'a, Message> {
|
||||
input: TextInput<'a, Message>,
|
||||
warning: Option<&'a str>,
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a> Form<'a, Message>
|
||||
where
|
||||
Message: Clone,
|
||||
{
|
||||
/// Creates a new [`Form`].
|
||||
///
|
||||
/// It expects:
|
||||
/// - a placeholder
|
||||
/// - the current value
|
||||
/// - a function that produces a message when the [`Form`] changes
|
||||
pub fn new<F>(placeholder: &str, value: &Value<String>, on_change: F) -> Self
|
||||
where
|
||||
F: 'static + Fn(String) -> Message,
|
||||
{
|
||||
Self {
|
||||
input: TextInput::new(placeholder, &value.value, on_change),
|
||||
warning: None,
|
||||
valid: value.valid,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the [`Form`] with a warning message
|
||||
pub fn warning(mut self, warning: &'a str) -> Self {
|
||||
self.warning = Some(warning);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the padding of the [`Form`].
|
||||
pub fn padding(mut self, units: u16) -> Self {
|
||||
self.input = self.input.padding(units);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Form`] with a text size
|
||||
pub fn size(mut self, size: u16) -> Self {
|
||||
self.input = self.input.size(size);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a + Clone> From<Form<'a, Message>> for Element<'a, Message> {
|
||||
fn from(form: Form<'a, Message>) -> Element<'a, Message> {
|
||||
Container::new(
|
||||
Column::new()
|
||||
.push(if !form.valid {
|
||||
form.input.style(InvalidFormStyle)
|
||||
} else {
|
||||
form.input
|
||||
})
|
||||
.push_maybe(if !form.valid {
|
||||
form.warning
|
||||
.map(|message| text(message).style(color::ALERT).small())
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.width(Length::Fill)
|
||||
.spacing(5),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct InvalidFormStyle;
|
||||
impl StyleSheet for InvalidFormStyle {
|
||||
type Style = iced::Theme;
|
||||
fn active(&self, _style: &Self::Style) -> Appearance {
|
||||
Appearance {
|
||||
background: iced::Background::Color(color::FOREGROUND),
|
||||
border_radius: 5.0,
|
||||
border_width: 1.0,
|
||||
border_color: color::ALERT,
|
||||
}
|
||||
}
|
||||
|
||||
fn focused(&self, style: &Self::Style) -> Appearance {
|
||||
Appearance {
|
||||
border_color: color::ALERT,
|
||||
..self.active(style)
|
||||
}
|
||||
}
|
||||
|
||||
fn placeholder_color(&self, _style: &Self::Style) -> iced::Color {
|
||||
iced::Color::from_rgb(0.7, 0.7, 0.7)
|
||||
}
|
||||
|
||||
fn value_color(&self, _style: &Self::Style) -> iced::Color {
|
||||
iced::Color::from_rgb(0.3, 0.3, 0.3)
|
||||
}
|
||||
|
||||
fn selection_color(&self, _style: &Self::Style) -> iced::Color {
|
||||
iced::Color::from_rgb(0.8, 0.8, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidFormStyle> for Box<dyn StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: InvalidFormStyle) -> Box<dyn StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidFormStyle> for iced::theme::TextInput {
|
||||
fn from(i: InvalidFormStyle) -> iced::theme::TextInput {
|
||||
iced::theme::TextInput::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
pub mod badge;
|
||||
pub mod button;
|
||||
pub mod card;
|
||||
pub mod collapse;
|
||||
pub mod container;
|
||||
pub mod form;
|
||||
pub mod modal;
|
||||
pub mod notification;
|
||||
pub mod text;
|
||||
pub mod tooltip;
|
||||
|
||||
pub use tooltip::tooltip;
|
||||
|
||||
use iced::widget::{Column, Container, Text};
|
||||
use iced::Length;
|
||||
|
||||
use crate::ui::color;
|
||||
|
||||
pub fn separation<'a, T: 'a>() -> Container<'a, T> {
|
||||
Container::new(Column::new().push(Text::new(" ")))
|
||||
.style(SepStyle)
|
||||
.height(Length::Units(1))
|
||||
}
|
||||
|
||||
pub struct SepStyle;
|
||||
impl iced::widget::container::StyleSheet for SepStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> iced::widget::container::Appearance {
|
||||
iced::widget::container::Appearance {
|
||||
background: color::BORDER_GREY.into(),
|
||||
..iced::widget::container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SepStyle> for Box<dyn iced::widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: SepStyle) -> Box<dyn iced::widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SepStyle> for iced::theme::Container {
|
||||
fn from(i: SepStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,279 +0,0 @@
|
||||
/// modal widget from https://github.com/iced-rs/iced/blob/master/examples/modal/
|
||||
use iced_native::alignment::Alignment;
|
||||
use iced_native::widget::{self, Tree};
|
||||
use iced_native::{
|
||||
event, layout, mouse, overlay, renderer, Clipboard, Color, Element, Event, Layout, Length,
|
||||
Point, Rectangle, Shell, Size, Widget,
|
||||
};
|
||||
|
||||
/// A widget that centers a modal element over some base element
|
||||
pub struct Modal<'a, Message, Renderer> {
|
||||
base: Element<'a, Message, Renderer>,
|
||||
modal: Element<'a, Message, Renderer>,
|
||||
on_blur: Option<Message>,
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Modal<'a, Message, Renderer> {
|
||||
/// Returns a new [`Modal`]
|
||||
pub fn new(
|
||||
base: impl Into<Element<'a, Message, Renderer>>,
|
||||
modal: impl Into<Element<'a, Message, Renderer>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
base: base.into(),
|
||||
modal: modal.into(),
|
||||
on_blur: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the message that will be produces when the background
|
||||
/// of the [`Modal`] is pressed
|
||||
pub fn on_blur(self, on_blur: Option<Message>) -> Self {
|
||||
Self { on_blur, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer> for Modal<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Message: Clone,
|
||||
{
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
vec![Tree::new(&self.base), Tree::new(&self.modal)]
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
tree.diff_children(&[&self.base, &self.modal]);
|
||||
}
|
||||
|
||||
fn width(&self) -> Length {
|
||||
self.base.as_widget().width()
|
||||
}
|
||||
|
||||
fn height(&self) -> Length {
|
||||
self.base.as_widget().height()
|
||||
}
|
||||
|
||||
fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node {
|
||||
self.base.as_widget().layout(renderer, limits)
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
&mut self,
|
||||
state: &mut Tree,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
) -> event::Status {
|
||||
self.base.as_widget_mut().on_event(
|
||||
&mut state.children[0],
|
||||
event,
|
||||
layout,
|
||||
cursor_position,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
)
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
state: &Tree,
|
||||
renderer: &mut Renderer,
|
||||
theme: &<Renderer as iced_native::Renderer>::Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.base.as_widget().draw(
|
||||
&state.children[0],
|
||||
renderer,
|
||||
theme,
|
||||
style,
|
||||
layout,
|
||||
cursor_position,
|
||||
viewport,
|
||||
);
|
||||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b mut self,
|
||||
state: &'b mut Tree,
|
||||
layout: Layout<'_>,
|
||||
_renderer: &Renderer,
|
||||
) -> Option<overlay::Element<'b, Message, Renderer>> {
|
||||
Some(overlay::Element::new(
|
||||
layout.position(),
|
||||
Box::new(Overlay {
|
||||
content: &mut self.modal,
|
||||
tree: &mut state.children[1],
|
||||
size: layout.bounds().size(),
|
||||
on_blur: self.on_blur.clone(),
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
state: &Tree,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
viewport: &Rectangle,
|
||||
renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
self.base.as_widget().mouse_interaction(
|
||||
&state.children[0],
|
||||
layout,
|
||||
cursor_position,
|
||||
viewport,
|
||||
renderer,
|
||||
)
|
||||
}
|
||||
|
||||
fn operate(
|
||||
&self,
|
||||
state: &mut Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn widget::Operation<Message>,
|
||||
) {
|
||||
self.base
|
||||
.as_widget()
|
||||
.operate(&mut state.children[0], layout, renderer, operation);
|
||||
}
|
||||
}
|
||||
|
||||
struct Overlay<'a, 'b, Message, Renderer> {
|
||||
content: &'b mut Element<'a, Message, Renderer>,
|
||||
tree: &'b mut Tree,
|
||||
size: Size,
|
||||
on_blur: Option<Message>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer>
|
||||
for Overlay<'a, 'b, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
Message: Clone,
|
||||
{
|
||||
fn layout(&self, renderer: &Renderer, _bounds: Size, position: Point) -> layout::Node {
|
||||
let limits = layout::Limits::new(Size::ZERO, self.size)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill);
|
||||
|
||||
let mut child = self.content.as_widget().layout(renderer, &limits);
|
||||
child.align(Alignment::Center, Alignment::Center, limits.max());
|
||||
|
||||
let mut node = layout::Node::with_children(self.size, vec![child]);
|
||||
node.move_to(position);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
&mut self,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
) -> event::Status {
|
||||
let content_bounds = layout.children().next().unwrap().bounds();
|
||||
|
||||
if let Some(message) = self.on_blur.as_ref() {
|
||||
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = &event {
|
||||
if !content_bounds.contains(cursor_position) {
|
||||
shell.publish(message.clone());
|
||||
return event::Status::Captured;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.content.as_widget_mut().on_event(
|
||||
self.tree,
|
||||
event,
|
||||
layout.children().next().unwrap(),
|
||||
cursor_position,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
)
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
theme: &Renderer::Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) {
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds: layout.bounds(),
|
||||
border_radius: renderer::BorderRadius::from(0.0),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
},
|
||||
Color {
|
||||
a: 0.80,
|
||||
..Color::BLACK
|
||||
},
|
||||
);
|
||||
|
||||
self.content.as_widget().draw(
|
||||
self.tree,
|
||||
renderer,
|
||||
theme,
|
||||
style,
|
||||
layout.children().next().unwrap(),
|
||||
cursor_position,
|
||||
&layout.bounds(),
|
||||
);
|
||||
}
|
||||
|
||||
fn operate(
|
||||
&mut self,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn widget::Operation<Message>,
|
||||
) {
|
||||
self.content.as_widget().operate(
|
||||
self.tree,
|
||||
layout.children().next().unwrap(),
|
||||
renderer,
|
||||
operation,
|
||||
);
|
||||
}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
viewport: &Rectangle,
|
||||
renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
self.content.as_widget().mouse_interaction(
|
||||
self.tree,
|
||||
layout.children().next().unwrap(),
|
||||
cursor_position,
|
||||
viewport,
|
||||
renderer,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> From<Modal<'a, Message, Renderer>> for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: 'a + iced_native::Renderer,
|
||||
Message: 'a + Clone,
|
||||
{
|
||||
fn from(modal: Modal<'a, Message, Renderer>) -> Self {
|
||||
Element::new(modal)
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
use crate::ui::{
|
||||
color,
|
||||
component::{button, collapse, text::*},
|
||||
icon,
|
||||
};
|
||||
use iced::{
|
||||
widget::{container, Button, Container, Row},
|
||||
Alignment, Element, Length,
|
||||
};
|
||||
|
||||
pub fn warning<'a, T: 'a + Clone>(message: String, error: String) -> Container<'a, T> {
|
||||
let message_clone = message.clone();
|
||||
Container::new(Container::new(collapse::Collapse::new(
|
||||
move || {
|
||||
Button::new(
|
||||
Row::new()
|
||||
.push(
|
||||
Container::new(text(message_clone.to_string()).small().bold())
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(10)
|
||||
.push(text("Learn more").small().bold())
|
||||
.push(icon::collapse_icon()),
|
||||
),
|
||||
)
|
||||
.style(button::Style::Transparent.into())
|
||||
},
|
||||
move || {
|
||||
Button::new(
|
||||
Row::new()
|
||||
.push(
|
||||
Container::new(text(message.to_owned()).small().bold()).width(Length::Fill),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(10)
|
||||
.push(text("Learn more").small().bold())
|
||||
.push(icon::collapsed_icon()),
|
||||
),
|
||||
)
|
||||
.style(button::Style::Transparent.into())
|
||||
},
|
||||
move || Element::<'a, T>::from(text(error.to_owned()).small()),
|
||||
)))
|
||||
.padding(15)
|
||||
.style(WarningStyle)
|
||||
.width(Length::Fill)
|
||||
}
|
||||
|
||||
pub struct WarningStyle;
|
||||
impl container::StyleSheet for WarningStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> container::Appearance {
|
||||
container::Appearance {
|
||||
border_radius: 0.0,
|
||||
text_color: iced::Color::BLACK.into(),
|
||||
background: color::WARNING.into(),
|
||||
border_color: color::WARNING,
|
||||
..container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WarningStyle> for Box<dyn container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: WarningStyle) -> Box<dyn container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WarningStyle> for iced::theme::Container {
|
||||
fn from(i: WarningStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
use crate::ui::font;
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub const TEXT_REGULAR_SIZE: u16 = 25;
|
||||
|
||||
pub fn text<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a> {
|
||||
iced::widget::Text::new(content)
|
||||
.font(font::REGULAR)
|
||||
.size(TEXT_REGULAR_SIZE)
|
||||
}
|
||||
|
||||
pub trait Text {
|
||||
fn bold(self) -> Self;
|
||||
fn small(self) -> Self;
|
||||
}
|
||||
|
||||
impl Text for iced::widget::Text<'_> {
|
||||
fn bold(self) -> Self {
|
||||
self.font(font::BOLD)
|
||||
}
|
||||
fn small(self) -> Self {
|
||||
self.size(20)
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
use crate::ui::{color, icon};
|
||||
use iced::widget::{self, Tooltip};
|
||||
|
||||
pub fn tooltip<'a, T: 'a>(help: &'static str) -> Tooltip<'a, T> {
|
||||
Tooltip::new(
|
||||
icon::tooltip_icon().style(color::DARK_GREY),
|
||||
help,
|
||||
widget::tooltip::Position::Right,
|
||||
)
|
||||
.style(TooltipStyle)
|
||||
}
|
||||
pub struct TooltipStyle;
|
||||
impl widget::container::StyleSheet for TooltipStyle {
|
||||
type Style = iced::Theme;
|
||||
fn appearance(&self, _style: &Self::Style) -> widget::container::Appearance {
|
||||
widget::container::Appearance {
|
||||
border_radius: 10.0,
|
||||
border_color: color::DARK_GREY,
|
||||
border_width: 1.5,
|
||||
background: color::FOREGROUND.into(),
|
||||
..widget::container::Appearance::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TooltipStyle> for Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
fn from(s: TooltipStyle) -> Box<dyn widget::container::StyleSheet<Style = iced::Theme>> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TooltipStyle> for iced::theme::Container {
|
||||
fn from(i: TooltipStyle) -> iced::theme::Container {
|
||||
iced::theme::Container::Custom(i.into())
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
use iced::Font;
|
||||
|
||||
pub const BOLD: Font = Font::External {
|
||||
name: "Bold",
|
||||
bytes: include_bytes!("../../static/fonts/OpenSans-Bold.ttf"),
|
||||
};
|
||||
|
||||
pub const REGULAR: Font = Font::External {
|
||||
name: "Regular",
|
||||
bytes: include_bytes!("../../static/fonts/OpenSans-Regular.ttf"),
|
||||
};
|
||||
@ -1,232 +0,0 @@
|
||||
use iced::{alignment, widget::Text, Font, Length};
|
||||
|
||||
const ICONS: Font = Font::External {
|
||||
name: "Icons",
|
||||
bytes: include_bytes!("../../static/icons/bootstrap-icons.ttf"),
|
||||
};
|
||||
|
||||
fn icon(unicode: char) -> Text<'static> {
|
||||
Text::new(unicode.to_string())
|
||||
.font(ICONS)
|
||||
.width(Length::Units(20))
|
||||
.horizontal_alignment(alignment::Horizontal::Center)
|
||||
.size(20)
|
||||
}
|
||||
|
||||
pub fn arrow_down() -> Text<'static> {
|
||||
icon('\u{F128}')
|
||||
}
|
||||
|
||||
pub fn chevron_right() -> Text<'static> {
|
||||
icon('\u{F285}')
|
||||
}
|
||||
|
||||
pub fn recovery_icon() -> Text<'static> {
|
||||
icon('\u{F467}')
|
||||
}
|
||||
|
||||
pub fn plug_icon() -> Text<'static> {
|
||||
icon('\u{F4F6}')
|
||||
}
|
||||
|
||||
pub fn reload_icon() -> Text<'static> {
|
||||
icon('\u{F130}')
|
||||
}
|
||||
|
||||
pub fn import_icon() -> Text<'static> {
|
||||
icon('\u{F30A}')
|
||||
}
|
||||
|
||||
pub fn wallet_icon() -> Text<'static> {
|
||||
icon('\u{F615}')
|
||||
}
|
||||
|
||||
pub fn hourglass_icon() -> Text<'static> {
|
||||
icon('\u{F41F}')
|
||||
}
|
||||
|
||||
pub fn hourglass_done_icon() -> Text<'static> {
|
||||
icon('\u{F41E}')
|
||||
}
|
||||
|
||||
pub fn vault_icon() -> Text<'static> {
|
||||
icon('\u{F65A}')
|
||||
}
|
||||
|
||||
pub fn bitcoin_icon() -> Text<'static> {
|
||||
icon('\u{F635}')
|
||||
}
|
||||
|
||||
pub fn history_icon() -> Text<'static> {
|
||||
icon('\u{F292}')
|
||||
}
|
||||
|
||||
pub fn home_icon() -> Text<'static> {
|
||||
icon('\u{F3FC}')
|
||||
}
|
||||
|
||||
pub fn unlock_icon() -> Text<'static> {
|
||||
icon('\u{F600}')
|
||||
}
|
||||
|
||||
pub fn warning_octagon_icon() -> Text<'static> {
|
||||
icon('\u{F337}')
|
||||
}
|
||||
|
||||
pub fn send_icon() -> Text<'static> {
|
||||
icon('\u{F144}')
|
||||
}
|
||||
|
||||
pub fn connect_device_icon() -> Text<'static> {
|
||||
icon('\u{F348}')
|
||||
}
|
||||
|
||||
pub fn connected_device_icon() -> Text<'static> {
|
||||
icon('\u{F350}')
|
||||
}
|
||||
|
||||
pub fn receive_icon() -> Text<'static> {
|
||||
icon('\u{F123}')
|
||||
}
|
||||
|
||||
pub fn calendar_icon() -> Text<'static> {
|
||||
icon('\u{F1E8}')
|
||||
}
|
||||
|
||||
pub fn turnback_icon() -> Text<'static> {
|
||||
icon('\u{F131}')
|
||||
}
|
||||
|
||||
pub fn vaults_icon() -> Text<'static> {
|
||||
icon('\u{F1C7}')
|
||||
}
|
||||
|
||||
pub fn coin_icon() -> Text<'static> {
|
||||
icon('\u{F567}')
|
||||
}
|
||||
|
||||
pub fn settings_icon() -> Text<'static> {
|
||||
icon('\u{F3E5}')
|
||||
}
|
||||
|
||||
pub fn block_icon() -> Text<'static> {
|
||||
icon('\u{F1C8}')
|
||||
}
|
||||
|
||||
pub fn square_icon() -> Text<'static> {
|
||||
icon('\u{F584}')
|
||||
}
|
||||
|
||||
pub fn square_check_icon() -> Text<'static> {
|
||||
icon('\u{F26D}')
|
||||
}
|
||||
|
||||
pub fn circle_check_icon() -> Text<'static> {
|
||||
icon('\u{F26B}')
|
||||
}
|
||||
|
||||
pub fn circle_cross_icon() -> Text<'static> {
|
||||
icon('\u{F623}')
|
||||
}
|
||||
|
||||
pub fn network_icon() -> Text<'static> {
|
||||
icon('\u{F40D}')
|
||||
}
|
||||
|
||||
pub fn dot_icon() -> Text<'static> {
|
||||
icon('\u{F287}')
|
||||
}
|
||||
|
||||
pub fn clipboard_icon() -> Text<'static> {
|
||||
icon('\u{F3C2}')
|
||||
}
|
||||
|
||||
pub fn shield_icon() -> Text<'static> {
|
||||
icon('\u{F53F}')
|
||||
}
|
||||
|
||||
pub fn shield_notif_icon() -> Text<'static> {
|
||||
icon('\u{F530}')
|
||||
}
|
||||
|
||||
pub fn shield_check_icon() -> Text<'static> {
|
||||
icon('\u{F52F}')
|
||||
}
|
||||
|
||||
pub fn person_check_icon() -> Text<'static> {
|
||||
icon('\u{F4D6}')
|
||||
}
|
||||
|
||||
pub fn person_icon() -> Text<'static> {
|
||||
icon('\u{F4DA}')
|
||||
}
|
||||
|
||||
pub fn tooltip_icon() -> Text<'static> {
|
||||
icon('\u{F431}')
|
||||
}
|
||||
|
||||
pub fn plus_icon() -> Text<'static> {
|
||||
icon('\u{F4FE}')
|
||||
}
|
||||
|
||||
pub fn warning_icon() -> Text<'static> {
|
||||
icon('\u{F33B}')
|
||||
}
|
||||
|
||||
pub fn chip_icon() -> Text<'static> {
|
||||
icon('\u{F2D6}')
|
||||
}
|
||||
|
||||
pub fn trash_icon() -> Text<'static> {
|
||||
icon('\u{F5DE}')
|
||||
}
|
||||
|
||||
pub fn key_icon() -> Text<'static> {
|
||||
icon('\u{F44F}')
|
||||
}
|
||||
|
||||
pub fn cross_icon() -> Text<'static> {
|
||||
icon('\u{F62A}')
|
||||
}
|
||||
|
||||
pub fn pencil_icon() -> Text<'static> {
|
||||
icon('\u{F4CB}')
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn stakeholder_icon() -> Text<'static> {
|
||||
icon('\u{F4AE}')
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn manager_icon() -> Text<'static> {
|
||||
icon('\u{F4B4}')
|
||||
}
|
||||
|
||||
pub fn done_icon() -> Text<'static> {
|
||||
icon('\u{F26B}')
|
||||
}
|
||||
|
||||
pub fn todo_icon() -> Text<'static> {
|
||||
icon('\u{F28A}')
|
||||
}
|
||||
|
||||
pub fn collapse_icon() -> Text<'static> {
|
||||
icon('\u{F284}')
|
||||
}
|
||||
|
||||
pub fn collapsed_icon() -> Text<'static> {
|
||||
icon('\u{F282}')
|
||||
}
|
||||
|
||||
pub fn down_icon() -> Text<'static> {
|
||||
icon('\u{F279}')
|
||||
}
|
||||
|
||||
pub fn up_icon() -> Text<'static> {
|
||||
icon('\u{F27C}')
|
||||
}
|
||||
|
||||
pub fn people_icon() -> Text<'static> {
|
||||
icon('\u{F4CF}')
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
pub mod color;
|
||||
/// component are wrappers around iced elements;
|
||||
pub mod component;
|
||||
pub mod font;
|
||||
pub mod icon;
|
||||
pub mod util;
|
||||
@ -1,28 +0,0 @@
|
||||
/// from hecjr idea on Discord
|
||||
use iced::{
|
||||
widget::{Column, Row},
|
||||
Element,
|
||||
};
|
||||
|
||||
pub trait Collection<'a, Message>: Sized {
|
||||
fn push(self, element: impl Into<Element<'a, Message>>) -> Self;
|
||||
|
||||
fn push_maybe(self, element: Option<impl Into<Element<'a, Message>>>) -> Self {
|
||||
match element {
|
||||
Some(element) => self.push(element),
|
||||
None => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message> Collection<'a, Message> for Column<'a, Message> {
|
||||
fn push(self, element: impl Into<Element<'a, Message>>) -> Self {
|
||||
Self::push(self, element)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message> Collection<'a, Message> for Row<'a, Message> {
|
||||
fn push(self, element: impl Into<Element<'a, Message>>) -> Self {
|
||||
Self::push(self, element)
|
||||
}
|
||||
}
|
||||
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019-2020 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@ -1,6 +0,0 @@
|
||||
# Icons
|
||||
|
||||
From the getbootstrap.com repository.
|
||||
Converted from .woff to ttf with https://raw.githubusercontent.com/hanikesn/woff2otf/master/woff2otf.py
|
||||
|
||||
Use http://mathew-kurian.github.io/CharacterMap/ to check Unicode.
|
||||
Binary file not shown.
@ -9,8 +9,3 @@ edition = "2021"
|
||||
iced = "0.7"
|
||||
iced_native = "0.8"
|
||||
iced_lazy = { version = "0.4"}
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"examples/*"
|
||||
]
|
||||
|
||||
@ -5,23 +5,23 @@ use iced::{Alignment, Length};
|
||||
use super::text::text;
|
||||
|
||||
pub fn alert<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Destructive.into())
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Destructive)
|
||||
}
|
||||
|
||||
pub fn primary<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Primary.into())
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Primary)
|
||||
}
|
||||
|
||||
pub fn transparent<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Transparent.into())
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Transparent)
|
||||
}
|
||||
|
||||
pub fn border<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Secondary.into())
|
||||
button::Button::new(content(icon, t)).style(theme::Button::Secondary)
|
||||
}
|
||||
|
||||
pub fn transparent_border<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
|
||||
button(content(icon, t)).style(theme::Button::TransparentBorder.into())
|
||||
button(content(icon, t)).style(theme::Button::TransparentBorder)
|
||||
}
|
||||
|
||||
fn content<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Container<'a, T> {
|
||||
|
||||
@ -2,10 +2,10 @@ use iced::Font;
|
||||
|
||||
pub const BOLD: Font = Font::External {
|
||||
name: "Bold",
|
||||
bytes: include_bytes!("../../static/fonts/OpenSans-Bold.ttf"),
|
||||
bytes: include_bytes!("../static/fonts/OpenSans-Bold.ttf"),
|
||||
};
|
||||
|
||||
pub const REGULAR: Font = Font::External {
|
||||
name: "Regular",
|
||||
bytes: include_bytes!("../../static/fonts/OpenSans-Regular.ttf"),
|
||||
bytes: include_bytes!("../static/fonts/OpenSans-Regular.ttf"),
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ use iced::{alignment, Font, Length};
|
||||
|
||||
const ICONS: Font = Font::External {
|
||||
name: "Icons",
|
||||
bytes: include_bytes!("../../static/icons/bootstrap-icons.ttf"),
|
||||
bytes: include_bytes!("../static/icons/bootstrap-icons.ttf"),
|
||||
};
|
||||
|
||||
fn icon(unicode: char) -> Text<'static> {
|
||||
|
||||
@ -17,4 +17,7 @@ pub mod widget {
|
||||
pub type Button<'a, Message> = iced::widget::Button<'a, Message, Renderer>;
|
||||
pub type Text<'a> = iced::widget::Text<'a, Renderer>;
|
||||
pub type Tooltip<'a> = iced::widget::Tooltip<'a, Renderer>;
|
||||
pub type ProgressBar = iced::widget::ProgressBar<Renderer>;
|
||||
pub type PickList<'a, Message> = iced::widget::PickList<'a, Message, Renderer>;
|
||||
pub type Scrollable<'a, Message> = iced::widget::Scrollable<'a, Message, Renderer>;
|
||||
}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
use iced::{
|
||||
application,
|
||||
widget::{button, container, radio, text, text_input},
|
||||
widget::{
|
||||
button, checkbox, container, pick_list, progress_bar, radio, scrollable, text, text_input,
|
||||
},
|
||||
};
|
||||
|
||||
use super::color;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub enum Theme {
|
||||
#[default]
|
||||
Dark,
|
||||
Light,
|
||||
#[default]
|
||||
Legacy,
|
||||
}
|
||||
|
||||
@ -34,6 +36,32 @@ impl application::StyleSheet for Theme {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub enum Overlay {
|
||||
#[default]
|
||||
Default,
|
||||
}
|
||||
impl iced::overlay::menu::StyleSheet for Theme {
|
||||
type Style = Overlay;
|
||||
|
||||
fn appearance(&self, _style: &Self::Style) -> iced::overlay::menu::Appearance {
|
||||
iced::overlay::menu::Appearance {
|
||||
text_color: color::BLACK,
|
||||
background: color::LIGHT_GREY.into(),
|
||||
border_width: 1.0,
|
||||
border_radius: 0.0,
|
||||
border_color: color::GREEN,
|
||||
selected_text_color: color::BLACK,
|
||||
selected_background: color::GREEN.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<PickList> for Overlay {
|
||||
fn from(_p: PickList) -> Overlay {
|
||||
Overlay::Default
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub enum Text {
|
||||
#[default]
|
||||
@ -91,7 +119,7 @@ impl container::StyleSheet for Theme {
|
||||
Container::Border => container::Appearance {
|
||||
background: iced::Color::TRANSPARENT.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::LIGHT_BLACK.into(),
|
||||
border_color: color::LIGHT_BLACK,
|
||||
..container::Appearance::default()
|
||||
},
|
||||
Container::Card(c) => c.appearance(self),
|
||||
@ -118,7 +146,7 @@ impl container::StyleSheet for Theme {
|
||||
Container::Border => container::Appearance {
|
||||
background: iced::Color::TRANSPARENT.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::LIGHT_GREY.into(),
|
||||
border_color: color::LIGHT_GREY,
|
||||
..container::Appearance::default()
|
||||
},
|
||||
Container::Card(c) => c.appearance(self),
|
||||
@ -145,7 +173,7 @@ impl container::StyleSheet for Theme {
|
||||
Container::Border => container::Appearance {
|
||||
background: iced::Color::TRANSPARENT.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::legacy::BORDER_GREY.into(),
|
||||
border_color: color::legacy::BORDER_GREY,
|
||||
..container::Appearance::default()
|
||||
},
|
||||
Container::Card(c) => c.appearance(self),
|
||||
@ -160,6 +188,24 @@ impl container::StyleSheet for Theme {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Card> for Container {
|
||||
fn from(c: Card) -> Container {
|
||||
Container::Card(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Badge> for Container {
|
||||
fn from(c: Badge) -> Container {
|
||||
Container::Badge(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Pill> for Container {
|
||||
fn from(c: Pill) -> Container {
|
||||
Container::Pill(c)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub enum Card {
|
||||
#[default]
|
||||
@ -236,7 +282,6 @@ impl Card {
|
||||
border_width: 1.0,
|
||||
border_radius: 10.0,
|
||||
border_color: color::legacy::ALERT,
|
||||
..container::Appearance::default()
|
||||
},
|
||||
Card::Error => container::Appearance {
|
||||
background: color::legacy::FOREGROUND.into(),
|
||||
@ -244,7 +289,6 @@ impl Card {
|
||||
border_width: 1.0,
|
||||
border_radius: 10.0,
|
||||
border_color: color::legacy::ALERT,
|
||||
..container::Appearance::default()
|
||||
},
|
||||
Card::Warning => container::Appearance {
|
||||
border_radius: 0.0,
|
||||
@ -348,6 +392,80 @@ impl radio::StyleSheet for Theme {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Scrollable {}
|
||||
impl scrollable::StyleSheet for Theme {
|
||||
type Style = Scrollable;
|
||||
|
||||
fn active(&self, _style: &Self::Style) -> scrollable::Scrollbar {
|
||||
scrollable::Scrollbar {
|
||||
background: None,
|
||||
border_width: 0.0,
|
||||
border_color: color::legacy::BORDER_GREY,
|
||||
border_radius: 10.0,
|
||||
scroller: scrollable::Scroller {
|
||||
color: color::legacy::BORDER_GREY,
|
||||
border_radius: 10.0,
|
||||
border_width: 0.0,
|
||||
border_color: iced::Color::TRANSPARENT,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, style: &Self::Style) -> scrollable::Scrollbar {
|
||||
let active = self.active(style);
|
||||
scrollable::Scrollbar { ..active }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub enum PickList {
|
||||
#[default]
|
||||
Simple,
|
||||
}
|
||||
impl pick_list::StyleSheet for Theme {
|
||||
type Style = PickList;
|
||||
|
||||
fn active(&self, _style: &Self::Style) -> pick_list::Appearance {
|
||||
pick_list::Appearance {
|
||||
placeholder_color: color::legacy::FOREGROUND,
|
||||
handle_color: color::legacy::FOREGROUND,
|
||||
background: color::legacy::FOREGROUND.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::legacy::BORDER_GREY,
|
||||
border_radius: 10.0,
|
||||
text_color: iced::Color::BLACK,
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, style: &Self::Style) -> pick_list::Appearance {
|
||||
let active = self.active(style);
|
||||
pick_list::Appearance { ..active }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CheckBox {}
|
||||
impl checkbox::StyleSheet for Theme {
|
||||
type Style = CheckBox;
|
||||
|
||||
fn active(&self, _style: &Self::Style, _is_selected: bool) -> checkbox::Appearance {
|
||||
checkbox::Appearance {
|
||||
background: iced::Color::TRANSPARENT.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::GREY,
|
||||
checkmark_color: color::GREEN,
|
||||
text_color: None,
|
||||
border_radius: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, style: &Self::Style, is_selected: bool) -> checkbox::Appearance {
|
||||
let active = self.active(style, is_selected);
|
||||
checkbox::Appearance { ..active }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub enum Button {
|
||||
#[default]
|
||||
@ -644,3 +762,20 @@ impl text_input::StyleSheet for Theme {
|
||||
iced::Color::from_rgb(0.8, 0.8, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub enum ProgressBar {
|
||||
#[default]
|
||||
Simple,
|
||||
}
|
||||
|
||||
impl progress_bar::StyleSheet for Theme {
|
||||
type Style = ProgressBar;
|
||||
fn appearance(&self, _style: &Self::Style) -> progress_bar::Appearance {
|
||||
progress_bar::Appearance {
|
||||
background: iced::Color::TRANSPARENT.into(),
|
||||
bar: color::GREEN.into(),
|
||||
border_radius: 10.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user