iced v0.13

This commit is contained in:
edouardparis 2025-01-20 12:27:31 +01:00
parent b7a51c8141
commit ad297d1ef8
94 changed files with 2986 additions and 2727 deletions

799
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,3 @@ members = [
"liana-ui",
]
default-members = ["liana", "lianad", "liana-gui", "liana-ui"]
[patch.crates-io]
iced_style = { git = "https://github.com/edouardparis/iced", branch = "patch-0.12.3"}
iced_winit = { git = "https://github.com/edouardparis/iced", branch = "patch-0.12.3"}
iced_futures = { git = "https://github.com/edouardparis/iced", branch = "patch-0.12.3"}

View File

@ -22,8 +22,8 @@ liana-ui = { path = "../liana-ui" }
backtrace = "0.3"
hex = "0.4.3"
iced = { version = "0.12.1", default-features = false, features = ["tokio", "svg", "qr_code", "image", "lazy", "wgpu", "advanced"] }
iced_runtime = "0.12.1"
iced = { version = "0.13.1", default-features = false, features = ["tokio", "svg", "qr_code", "image", "lazy", "wgpu", "advanced"] }
iced_runtime = "0.13.1"
# Used to verify RFC-compliance of an email
email_address = "0.2.7"

View File

@ -15,7 +15,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use iced::{clipboard, time, Command, Subscription};
use iced::{clipboard, time, Subscription, Task};
use tokio::runtime::Handle;
use tracing::{error, info, warn};
@ -148,7 +148,7 @@ impl App {
daemon: Arc<dyn Daemon + Sync + Send>,
data_dir: PathBuf,
internal_bitcoind: Option<Bitcoind>,
) -> (App, Command<Message>) {
) -> (App, Task<Message>) {
let mut panels = Panels::new(
&cache,
wallet.clone(),
@ -170,7 +170,7 @@ impl App {
)
}
fn set_current_panel(&mut self, menu: Menu) -> Command<Message> {
fn set_current_panel(&mut self, menu: Menu) -> Task<Message> {
self.panels.current_mut().interrupt();
match &menu {
@ -183,7 +183,7 @@ impl App {
}) {
self.panels.transactions.preselect(tx);
self.panels.current = menu;
return Command::none();
return Task::none();
};
}
menu::Menu::PsbtPreSelected(txid) => {
@ -198,7 +198,7 @@ impl App {
}) {
self.panels.psbts.preselect(spend_tx);
self.panels.current = menu;
return Command::none();
return Task::none();
};
}
menu::Menu::RefreshCoins(preselected) => {
@ -279,14 +279,14 @@ impl App {
}
}
pub fn update(&mut self, message: Message) -> Command<Message> {
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::Tick => {
let daemon = self.daemon.clone();
let datadir_path = self.cache.datadir_path.clone();
let network = self.cache.network;
let last_poll_at_startup = self.cache.last_poll_at_startup;
Command::perform(
Task::perform(
async move {
// we check every 10 second if the daemon poller is alive
// or if the access token is not expired.
@ -331,11 +331,11 @@ impl App {
)
})
.collect();
return Command::batch(commands);
return Task::batch(commands);
}
Err(e) => tracing::error!("Failed to update cache: {}", e),
}
Command::none()
Task::none()
}
Message::LoadDaemonConfig(cfg) => {
let path = self.config.daemon_config_path.clone().expect(

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::sync::Arc;
use std::{cmp::Ordering, collections::HashSet};
use iced::Command;
use iced::Task;
use liana_ui::widget::Element;
use lianad::commands::CoinStatus;
@ -113,7 +113,7 @@ impl State for CoinsPanel {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::Coins(res) => match res {
Err(e) => self.warning = Some(e),
@ -150,18 +150,18 @@ impl State for CoinsPanel {
}
_ => {}
};
Command::none()
Task::none()
}
fn reload(
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
_wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
let daemon1 = daemon.clone();
let daemon2 = daemon.clone();
Command::batch(vec![
Command::perform(
Task::batch(vec![
Task::perform(
async move {
daemon1
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
@ -171,7 +171,7 @@ impl State for CoinsPanel {
},
Message::Coins,
),
Command::perform(
Task::perform(
async move {
let coins = daemon2
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])

View File

@ -3,7 +3,7 @@ use std::{
sync::{Arc, Mutex},
};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana_ui::{component::modal::Modal, widget::Element};
use tokio::task::JoinHandle;
@ -37,13 +37,13 @@ impl ExportModal {
}
}
pub fn launch(&self) -> Command<Message> {
Command::perform(get_path(), |m| {
pub fn launch(&self) -> Task<Message> {
Task::perform(get_path(), |m| {
Message::View(view::Message::Export(ExportMessage::Path(m)))
})
}
pub fn update(&mut self, message: Message) -> Command<Message> {
pub fn update(&mut self, message: Message) -> Task<Message> {
if let Message::View(view::Message::Export(m)) = message {
match m {
ExportMessage::ExportProgress(m) => match m {
@ -73,16 +73,16 @@ impl ExportModal {
self.path = Some(path);
self.start();
} else {
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::View(view::Message::Export(ExportMessage::Close))
});
}
}
ExportMessage::Close | ExportMessage::Open => { /* unreachable */ }
}
Command::none()
Task::none()
} else {
Command::none()
Task::none()
}
}
pub fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<view::Message> {

View File

@ -9,7 +9,7 @@ use crate::{
Daemon,
},
};
use iced::Command;
use iced::Task;
use liana_ui::component::form;
#[derive(Default)]
@ -24,7 +24,7 @@ impl LabelsEdited {
daemon: Arc<dyn Daemon + Sync + Send>,
message: Message,
targets: T,
) -> Result<Command<Message>, Error> {
) -> Result<Task<Message>, Error> {
match message {
Message::View(view::Message::Label(items, msg)) => match msg {
view::LabelMessage::Edited(value) => {
@ -64,7 +64,7 @@ impl LabelsEdited {
}
}
}
return Ok(Command::perform(
return Ok(Task::perform(
async move {
daemon.update_labels(&updated_labels).await?;
Ok(updated_labels_str)
@ -88,7 +88,7 @@ impl LabelsEdited {
},
_ => {}
};
Ok(Command::none())
Ok(Task::none())
}
}

View File

@ -13,7 +13,7 @@ use std::convert::TryInto;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::miniscript::bitcoin::{Amount, OutPoint};
use liana_ui::widget::*;
use lianad::commands::CoinStatus;
@ -50,8 +50,8 @@ pub trait State {
_daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
_message: Message,
) -> Command<Message> {
Command::none()
) -> Task<Message> {
Task::none()
}
fn subscription(&self) -> Subscription<Message> {
Subscription::none()
@ -61,14 +61,14 @@ pub trait State {
&mut self,
_daemon: Arc<dyn Daemon + Sync + Send>,
_wallet: Arc<Wallet>,
) -> Command<Message> {
Command::none()
) -> Task<Message> {
Task::none()
}
}
/// redirect to another state with a message menu
pub fn redirect(menu: Menu) -> Command<Message> {
Command::perform(async { menu }, |menu| {
pub fn redirect(menu: Menu) -> Task<Message> {
Task::perform(async { menu }, |menu| {
Message::View(view::Message::Menu(menu))
})
}
@ -201,7 +201,7 @@ impl State for Home {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::Coins(res) => match res {
Err(e) => self.warning = Some(e),
@ -277,7 +277,7 @@ impl State for Home {
}
},
Message::View(view::Message::SelectPayment(outpoint)) => {
return Command::perform(
return Task::perform(
async move {
let tx = daemon.get_history_txs(&[outpoint.txid]).await?.remove(0);
Ok((tx, outpoint.vout as usize))
@ -318,7 +318,7 @@ impl State for Home {
let daemon = daemon.clone();
let last_event_date = last.time.unwrap();
self.processing = true;
return Command::perform(
return Task::perform(
async move {
let last_event_date = last_event_date.timestamp() as u32;
let mut limit = HISTORY_EVENT_PAGE_SIZE;
@ -359,20 +359,20 @@ impl State for Home {
}
_ => {}
};
Command::none()
Task::none()
}
fn reload(
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
// If the wallet is syncing, we expect it to finish soon and so better to wait for
// updated data before reloading. Besides, if the wallet is syncing, the DB may be
// locked if the poller is running and we wouldn't be able to reload data until
// syncing completes anyway.
if self.sync_status.wallet_is_syncing() {
return Command::none();
return Task::none();
}
self.selected_event = None;
self.wallet = wallet;
@ -383,8 +383,8 @@ impl State for Home {
.as_secs()
.try_into()
.unwrap();
Command::batch(vec![
Command::perform(
Task::batch(vec![
Task::perform(
async move {
let mut payments = daemon
.list_confirmed_payments(0, now, HISTORY_EVENT_PAGE_SIZE)
@ -397,7 +397,7 @@ impl State for Home {
},
Message::Payments,
),
Command::perform(
Task::perform(
async move {
daemon2
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])

View File

@ -5,7 +5,7 @@ use std::sync::Arc;
use iced::Subscription;
use iced::Command;
use iced::Task;
use liana::{
descriptors::LianaPolicy,
miniscript::bitcoin::{bip32::Fingerprint, psbt::Psbt, Network, Txid},
@ -36,8 +36,8 @@ use crate::{
};
pub trait Action {
fn load(&self, _daemon: Arc<dyn Daemon + Sync + Send>) -> Command<Message> {
Command::none()
fn load(&self, _daemon: Arc<dyn Daemon + Sync + Send>) -> Task<Message> {
Task::none()
}
fn subscription(&self) -> Subscription<Message> {
Subscription::none()
@ -47,8 +47,8 @@ pub trait Action {
_daemon: Arc<dyn Daemon + Sync + Send>,
_message: Message,
_tx: &mut SpendTx,
) -> Command<Message> {
Command::none()
) -> Task<Message> {
Task::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message>;
}
@ -120,11 +120,11 @@ impl PsbtState {
}
}
pub fn load(&self, daemon: Arc<dyn Daemon + Sync + Send>) -> Command<Message> {
pub fn load(&self, daemon: Arc<dyn Daemon + Sync + Send>) -> Task<Message> {
if let Some(action) = &self.action {
action.as_ref().load(daemon)
} else {
Command::none()
Task::none()
}
}
@ -133,12 +133,12 @@ impl PsbtState {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Spend(view::SpendTxMessage::Cancel)) => {
if let Some(PsbtAction::Sign(SignAction { display_modal, .. })) = &mut self.action {
*display_modal = false;
return Command::none();
return Task::none();
}
self.action = None;
@ -149,7 +149,7 @@ impl PsbtState {
Message::View(view::Message::Spend(view::SpendTxMessage::Sign)) => {
if let Some(PsbtAction::Sign(SignAction { display_modal, .. })) = &mut self.action {
*display_modal = true;
return Command::none();
return Task::none();
}
let action = SignAction::new(
@ -171,7 +171,7 @@ impl PsbtState {
}
Message::View(view::Message::Spend(view::SpendTxMessage::Broadcast)) => {
let outpoints: Vec<_> = self.tx.coins.keys().cloned().collect();
return Command::perform(
return Task::perform(
async move {
daemon
.list_coins(&[CoinStatus::Spending], &outpoints)
@ -231,7 +231,7 @@ impl PsbtState {
}
}
};
Command::none()
Task::none()
}
pub fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
@ -265,7 +265,7 @@ impl Action for SaveAction {
daemon: Arc<dyn Daemon + Sync + Send>,
message: Message,
tx: &mut SpendTx,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Spend(view::SpendTxMessage::Confirm)) => {
let daemon = daemon.clone();
@ -276,7 +276,7 @@ impl Action for SaveAction {
labels.insert(label_item_from_str(item), Some(label.clone()));
}
}
return Command::perform(
return Task::perform(
async move {
daemon.update_spend_tx(&psbt).await?;
daemon.update_labels(&labels).await.map_err(|e| e.into())
@ -290,7 +290,7 @@ impl Action for SaveAction {
},
_ => {}
}
Command::none()
Task::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message> {
modal::Modal::new(
@ -316,13 +316,13 @@ impl Action for BroadcastAction {
daemon: Arc<dyn Daemon + Sync + Send>,
message: Message,
tx: &mut SpendTx,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Spend(view::SpendTxMessage::Confirm)) => {
let daemon = daemon.clone();
let psbt = tx.psbt.clone();
self.error = None;
return Command::perform(
return Task::perform(
async move {
daemon
.broadcast_spend_tx(&psbt.unsigned_tx.compute_txid())
@ -341,7 +341,7 @@ impl Action for BroadcastAction {
},
_ => {}
}
Command::none()
Task::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message> {
modal::Modal::new(
@ -369,13 +369,13 @@ impl Action for DeleteAction {
daemon: Arc<dyn Daemon + Sync + Send>,
message: Message,
tx: &mut SpendTx,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Spend(view::SpendTxMessage::Confirm)) => {
let daemon = daemon.clone();
let psbt = tx.psbt.clone();
self.error = None;
return Command::perform(
return Task::perform(
async move {
daemon
.delete_spend_tx(&psbt.unsigned_tx.compute_txid())
@ -391,7 +391,7 @@ impl Action for DeleteAction {
},
_ => {}
}
Command::none()
Task::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message> {
modal::Modal::new(
@ -443,7 +443,7 @@ impl Action for SignAction {
daemon: Arc<dyn Daemon + Sync + Send>,
message: Message,
tx: &mut SpendTx,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::SelectHardwareWallet(i)) => {
if let Some(HardwareWallet::Supported {
@ -456,14 +456,14 @@ impl Action for SignAction {
self.signing.insert(*fingerprint);
let psbt = tx.psbt.clone();
let fingerprint = *fingerprint;
return Command::perform(
return Task::perform(
sign_psbt(self.wallet.clone(), device.clone(), psbt),
move |res| Message::Signed(fingerprint, res),
);
}
}
Message::View(view::Message::Spend(view::SpendTxMessage::SelectHotSigner)) => {
return Command::perform(
return Task::perform(
sign_psbt_with_hot_signer(self.wallet.clone(), tx.psbt.clone()),
|(fg, res)| Message::Signed(fg, res),
);
@ -482,7 +482,7 @@ impl Action for SignAction {
let daemon = daemon.clone();
merge_signatures(&mut tx.psbt, &psbt);
if self.is_saved {
return Command::perform(
return Task::perform(
async move { daemon.update_spend_tx(&psbt).await.map_err(|e| e.into()) },
Message::Updated,
);
@ -495,7 +495,7 @@ impl Action for SignAction {
labels.insert(label_item_from_str(item), Some(label.clone()));
}
}
return Command::perform(
return Task::perform(
async move {
daemon.update_spend_tx(&psbt).await?;
daemon.update_labels(&labels).await.map_err(|e| e.into())
@ -524,7 +524,7 @@ impl Action for SignAction {
},
_ => {}
};
Command::none()
Task::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message> {
let content = toast::Manager::new(
@ -683,7 +683,7 @@ impl Action for UpdateAction {
daemon: Arc<dyn Daemon + Sync + Send>,
message: Message,
tx: &mut SpendTx,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::Updated(res) => {
self.processing = false;
@ -715,7 +715,7 @@ impl Action for UpdateAction {
self.processing = true;
self.error = None;
if let Ok(updated) = Psbt::from_str(&self.updated.value) {
return Command::perform(
return Task::perform(
async move { daemon.update_spend_tx(&updated).await.map_err(|e| e.into()) },
Message::Updated,
);
@ -724,7 +724,7 @@ impl Action for UpdateAction {
_ => {}
}
Command::none()
Task::none()
}
}

View File

@ -1,7 +1,7 @@
use std::str::FromStr;
use std::sync::Arc;
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::miniscript::bitcoin::psbt::Psbt;
use liana_ui::{
@ -76,7 +76,7 @@ impl State for PsbtsPanel {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Reload) | Message::View(view::Message::Close) => {
return self.reload(daemon, self.wallet.clone());
@ -122,7 +122,7 @@ impl State for PsbtsPanel {
}
}
}
Command::none()
Task::none()
}
fn subscription(&self) -> Subscription<Message> {
@ -137,12 +137,12 @@ impl State for PsbtsPanel {
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
self.wallet = wallet;
self.selected_tx = None;
self.import_tx = None;
let daemon = daemon.clone();
Command::perform(
Task::perform(
async move {
daemon
.list_spend_transactions(None)
@ -192,7 +192,7 @@ impl ImportPsbtModal {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::Updated(res) => {
self.processing = false;
@ -213,7 +213,7 @@ impl ImportPsbtModal {
self.processing = true;
self.error = None;
let imported = Psbt::from_str(&self.imported.value).expect("Already checked");
return Command::perform(
return Task::perform(
async move {
daemon
.update_spend_tx(&imported)
@ -227,6 +227,6 @@ impl ImportPsbtModal {
_ => {}
}
Command::none()
Task::none()
}
}

View File

@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use std::sync::Arc;
use iced::{widget::qr_code, Command, Subscription};
use iced::{widget::qr_code, Subscription, Task};
use liana::miniscript::bitcoin::{
bip32::{ChildNumber, Fingerprint},
Address, Network,
@ -112,7 +112,7 @@ impl State for ReceivePanel {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Label(_, _)) | Message::LabelsUpdated(_) => {
match self.labels_edited.update(
@ -123,7 +123,7 @@ impl State for ReceivePanel {
Ok(cmd) => cmd,
Err(e) => {
self.warning = Some(e);
Command::none()
Task::none()
}
}
}
@ -136,11 +136,11 @@ impl State for ReceivePanel {
}
Err(e) => self.warning = Some(e),
}
Command::none()
Task::none()
}
Message::View(view::Message::Close) => {
self.modal = Modal::None;
Command::none()
Task::none()
}
Message::View(view::Message::Select(i)) => {
self.modal = Modal::VerifyAddress(VerifyAddressModal::new(
@ -154,11 +154,11 @@ impl State for ReceivePanel {
.get(i)
.expect("Must be present"),
));
Command::none()
Task::none()
}
Message::View(view::Message::Next) => {
let daemon = daemon.clone();
Command::perform(
Task::perform(
async move {
daemon
.get_new_address()
@ -178,13 +178,13 @@ impl State for ReceivePanel {
self.modal = Modal::ShowQrCode(modal);
}
}
Command::none()
Task::none()
}
_ => {
if let Modal::VerifyAddress(ref mut m) = self.modal {
m.update(daemon, cache, message)
} else {
Command::none()
Task::none()
}
}
}
@ -194,10 +194,10 @@ impl State for ReceivePanel {
&mut self,
_daemon: Arc<dyn Daemon + Sync + Send>,
wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
self.wallet = wallet;
self.addresses = Addresses::default();
Command::none()
Task::none()
}
}
@ -253,13 +253,13 @@ impl VerifyAddressModal {
_daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::HardwareWallets(msg) => match self.hws.update(msg) {
Ok(cmd) => cmd.map(Message::HardwareWallets),
Err(e) => {
self.warning = Some(e.into());
Command::none()
Task::none()
}
},
Message::Verified(fg, res) => {
@ -267,7 +267,7 @@ impl VerifyAddressModal {
if let Err(e) = res {
self.warning = Some(e);
}
Command::none()
Task::none()
}
Message::View(view::Message::SelectHardwareWallet(i)) => {
if let Some(HardwareWallet::Supported {
@ -279,15 +279,15 @@ impl VerifyAddressModal {
self.warning = None;
self.chosen_hws.insert(*fingerprint);
let fg = *fingerprint;
Command::perform(
Task::perform(
verify_address(device.clone(), self.derivation_index),
move |res| Message::Verified(fg, res),
)
} else {
Command::none()
Task::none()
}
}
_ => Command::none(),
_ => Task::none(),
}
}
}

View File

@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::str::FromStr;
use std::sync::Arc;
use iced::Command;
use iced::Task;
use liana::miniscript::bitcoin::{
bip32::{DerivationPath, Fingerprint},
@ -101,7 +101,7 @@ impl State for RecoveryPanel {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::Coins(res) => match res {
Err(e) => self.warning = Some(e),
@ -153,7 +153,7 @@ impl State for RecoveryPanel {
.get(self.selected_path.expect("A path must be selected"))
.map(|p| p.sequence);
let network = cache.network;
return Command::perform(
return Task::perform(
async move {
let psbt = daemon
.create_recovery(address, feerate_vb, sequence)
@ -192,14 +192,14 @@ impl State for RecoveryPanel {
}
}
};
Command::none()
Task::none()
}
fn reload(
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
let daemon = daemon.clone();
self.wallet = wallet;
self.selected_path = None;
@ -207,7 +207,7 @@ impl State for RecoveryPanel {
self.feerate = form::Value::default();
self.recipient = form::Value::default();
self.generated = None;
Command::perform(
Task::perform(
async move {
daemon
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])

View File

@ -5,7 +5,7 @@ use std::str::FromStr;
use std::sync::Arc;
use chrono::{NaiveDate, Utc};
use iced::{clipboard, Command};
use iced::{clipboard, Task};
use tracing::info;
use liana::miniscript::bitcoin::Network;
@ -90,7 +90,7 @@ impl State for BitcoindSettingsState {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::DaemonConfigLoaded(res) => match res {
Ok(()) => {
@ -98,7 +98,7 @@ impl State for BitcoindSettingsState {
self.warning = None;
if let Some(settings) = &mut self.bitcoind_settings {
settings.edited(true);
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::View(view::Message::Settings(
view::SettingsMessage::EditBitcoindSettings,
))
@ -106,7 +106,7 @@ impl State for BitcoindSettingsState {
}
if let Some(settings) = &mut self.electrum_settings {
settings.edited(true);
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::View(view::Message::Settings(
view::SettingsMessage::EditBitcoindSettings,
))
@ -158,7 +158,7 @@ impl State for BitcoindSettingsState {
}
_ => {}
};
Command::none()
Task::none()
}
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
@ -303,7 +303,7 @@ impl BitcoindSettings {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: view::SettingsEditMessage,
) -> Command<Message> {
) -> Task<Message> {
match message {
view::SettingsEditMessage::Select => {
if !self.processing {
@ -359,14 +359,14 @@ impl BitcoindSettings {
addr: new_addr.unwrap(),
}));
self.processing = true;
return Command::perform(async move { daemon_config }, |cfg| {
return Task::perform(async move { daemon_config }, |cfg| {
Message::LoadDaemonConfig(Box::new(cfg))
});
}
}
view::SettingsEditMessage::Clipboard(text) => return clipboard::write(text),
};
Command::none()
Task::none()
}
fn view<'a>(&self, cache: &'a Cache, can_edit: bool) -> Element<'a, view::SettingsEditMessage> {
@ -441,7 +441,7 @@ impl ElectrumSettings {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: view::SettingsEditMessage,
) -> Command<Message> {
) -> Task<Message> {
match message {
view::SettingsEditMessage::Select => {
if !self.processing {
@ -467,7 +467,7 @@ impl ElectrumSettings {
addr: self.addr.value.clone(),
}));
self.processing = true;
return Command::perform(async move { daemon_config }, |cfg| {
return Task::perform(async move { daemon_config }, |cfg| {
Message::LoadDaemonConfig(Box::new(cfg))
});
}
@ -475,7 +475,7 @@ impl ElectrumSettings {
view::SettingsEditMessage::Clipboard(text) => return clipboard::write(text),
_ => {}
};
Command::none()
Task::none()
}
fn view<'a>(&self, cache: &'a Cache, can_edit: bool) -> Element<'a, view::SettingsEditMessage> {
@ -537,7 +537,7 @@ impl RescanSetting {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: view::SettingsEditMessage,
) -> Command<Message> {
) -> Task<Message> {
match message {
view::SettingsEditMessage::FieldEdited(field, value) => {
self.invalid_date = false;
@ -601,15 +601,15 @@ impl RescanSetting {
}
} else {
self.invalid_date = true;
return Command::none();
return Task::none();
};
if t > Utc::now().timestamp() {
self.future_date = true;
return Command::none();
return Task::none();
}
self.processing = true;
info!("Asking daemon to rescan with timestamp: {}", t);
return Command::perform(
info!("Asking deamon to rescan with timestamp: {}", t);
return Task::perform(
async move {
daemon.start_rescan(t.try_into().expect("t cannot be inferior to 0 otherwise genesis block timestamp is chosen"))
.await
@ -620,7 +620,7 @@ impl RescanSetting {
}
_ => {}
};
Command::none()
Task::none()
}
fn view<'a>(&self, cache: &'a Cache, can_edit: bool) -> Element<'a, view::SettingsEditMessage> {

View File

@ -5,7 +5,7 @@ use std::convert::From;
use std::path::PathBuf;
use std::sync::Arc;
use iced::Command;
use iced::Task;
use liana_ui::{component::form, widget::Element};
@ -55,7 +55,7 @@ impl State for SettingsState {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match &message {
Message::View(view::Message::Settings(view::SettingsMessage::EditBitcoindSettings)) => {
self.setting = Some(
@ -71,13 +71,13 @@ impl State for SettingsState {
self.setting
.as_mut()
.map(|s| s.reload(daemon, wallet))
.unwrap_or_else(Command::none)
.unwrap_or_else(Task::none)
}
Message::View(view::Message::Settings(
view::SettingsMessage::EditRemoteBackendSettings,
)) => {
self.setting = Some(BackendSettingsState::new().into());
Command::none()
Task::none()
}
Message::View(view::Message::Settings(view::SettingsMessage::AboutSection)) => {
self.setting = Some(AboutSettingsState::default().into());
@ -85,7 +85,7 @@ impl State for SettingsState {
self.setting
.as_mut()
.map(|s| s.reload(daemon, wallet))
.unwrap_or_else(Command::none)
.unwrap_or_else(Task::none)
}
Message::View(view::Message::Settings(view::SettingsMessage::EditWalletSettings)) => {
self.setting = Some(
@ -95,20 +95,20 @@ impl State for SettingsState {
self.setting
.as_mut()
.map(|s| s.reload(daemon, wallet))
.unwrap_or_else(Command::none)
.unwrap_or_else(Task::none)
}
Message::WalletUpdated(Ok(wallet)) => {
self.wallet = wallet.clone();
self.setting
.as_mut()
.map(|s| s.update(daemon, cache, message))
.unwrap_or_else(Command::none)
.unwrap_or_else(Task::none)
}
_ => self
.setting
.as_mut()
.map(|s| s.update(daemon, cache, message))
.unwrap_or_else(Command::none),
.unwrap_or_else(Task::none),
}
}
@ -132,10 +132,10 @@ impl State for SettingsState {
&mut self,
_daemon: Arc<dyn Daemon + Sync + Send>,
wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
self.setting = None;
self.wallet = wallet;
Command::none()
Task::none()
}
}
@ -161,7 +161,7 @@ impl State for AboutSettingsState {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
if let Message::Info(res) = message {
match res {
Ok(info) => {
@ -175,15 +175,15 @@ impl State for AboutSettingsState {
}
}
Command::none()
Task::none()
}
fn reload(
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
_wallet: Arc<Wallet>,
) -> Command<Message> {
Command::perform(
) -> Task<Message> {
Task::perform(
async move { daemon.get_info().await.map_err(|e| e.into()) },
Message::Info,
)
@ -231,20 +231,20 @@ impl State for BackendSettingsState {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Settings(
view::SettingsMessage::RemoteBackendSettings(message),
)) => match message {
view::RemoteBackendSettingsMessage::SendInvitation => {
if !self.email_form.valid {
return Command::none();
return Task::none();
}
let email = self.email_form.value.clone();
self.processing = true;
self.success = false;
self.warning = None;
Command::perform(
Task::perform(
async move {
daemon.send_wallet_invitation(&email).await?;
Ok(())
@ -262,7 +262,7 @@ impl State for BackendSettingsState {
self.email_form.value = email;
self.success = false;
}
Command::none()
Task::none()
}
},
Message::Updated(res) => {
@ -274,9 +274,9 @@ impl State for BackendSettingsState {
self.warning = Some(e);
}
}
Command::none()
Task::none()
}
_ => Command::none(),
_ => Task::none(),
}
}
}

View File

@ -3,7 +3,7 @@ use std::convert::From;
use std::path::PathBuf;
use std::sync::Arc;
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::{
descriptors::LianaDescriptor,
@ -107,7 +107,7 @@ impl State for WalletSettingsState {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::WalletUpdated(res) => {
self.processing = false;
@ -122,7 +122,7 @@ impl State for WalletSettingsState {
}
Err(e) => self.warning = Some(e),
};
Command::none()
Task::none()
}
}
Message::View(view::Message::Settings(
@ -135,13 +135,13 @@ impl State for WalletSettingsState {
{
name.value = value;
}
Command::none()
Task::none()
}
Message::View(view::Message::Settings(view::SettingsMessage::Save)) => {
self.modal = None;
self.processing = true;
self.updated = false;
Command::perform(
Task::perform(
update_keys_aliases(
self.data_dir.clone(),
cache.network,
@ -157,7 +157,7 @@ impl State for WalletSettingsState {
}
Message::View(view::Message::Close) => {
self.modal = None;
Command::none()
Task::none()
}
Message::View(view::Message::Settings(view::SettingsMessage::RegisterWallet)) => {
self.modal = Some(RegisterWalletModal::new(
@ -165,13 +165,13 @@ impl State for WalletSettingsState {
self.wallet.clone(),
cache.network,
));
Command::none()
Task::none()
}
_ => self
.modal
.as_mut()
.map(|m| m.update(daemon, cache, message))
.unwrap_or_else(Command::none),
.unwrap_or_else(Task::none),
}
}
@ -179,11 +179,11 @@ impl State for WalletSettingsState {
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
self.descriptor = wallet.main_descriptor.clone();
self.keys_aliases = Self::keys_aliases(&wallet);
self.wallet = wallet;
Command::perform(
Task::perform(
async move { daemon.get_info().await.map_err(|e| e.into()) },
Message::Info,
)
@ -244,18 +244,18 @@ impl RegisterWalletModal {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::Reload) => {
self.chosen_hw = None;
self.warning = None;
Command::none()
Task::none()
}
Message::HardwareWallets(msg) => match self.hws.update(msg) {
Ok(cmd) => cmd.map(Message::HardwareWallets),
Err(e) => {
self.warning = Some(e.into());
Command::none()
Task::none()
}
},
Message::WalletUpdated(res) => {
@ -275,7 +275,7 @@ impl RegisterWalletModal {
}
}
}
Command::none()
Task::none()
}
Message::View(view::Message::SelectHardwareWallet(i)) => {
if let Some(HardwareWallet::Supported {
@ -286,7 +286,7 @@ impl RegisterWalletModal {
{
self.chosen_hw = Some(i);
self.processing = true;
Command::perform(
Task::perform(
register_wallet(
self.data_dir.clone(),
cache.network,
@ -298,10 +298,10 @@ impl RegisterWalletModal {
Message::WalletUpdated,
)
} else {
Command::none()
Task::none()
}
}
_ => Command::none(),
_ => Task::none(),
}
}
}

View File

@ -3,7 +3,7 @@ mod step;
use std::collections::HashSet;
use std::sync::Arc;
use iced::Command;
use iced::Task;
use liana::miniscript::bitcoin::{Network, OutPoint};
use liana_ui::widget::Element;
@ -88,7 +88,7 @@ impl State for CreateSpendPanel {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
if matches!(message, Message::View(view::Message::Close)) {
return redirect(Menu::PSBTs);
}
@ -114,18 +114,18 @@ impl State for CreateSpendPanel {
return step.update(daemon, cache, message);
}
Command::none()
Task::none()
}
fn reload(
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
_wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
let daemon1 = daemon.clone();
let daemon2 = daemon.clone();
Command::batch(vec![
Command::perform(
Task::batch(vec![
Task::perform(
async move {
daemon1
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
@ -135,7 +135,7 @@ impl State for CreateSpendPanel {
},
Message::Coins,
),
Command::perform(
Task::perform(
async move {
let coins = daemon
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])

View File

@ -6,7 +6,7 @@ use std::{
sync::Arc,
};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::{
descriptors::LianaDescriptor,
miniscript::bitcoin::{
@ -59,7 +59,7 @@ pub trait Step {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message>;
) -> Task<Message>;
fn apply(&self, _draft: &mut TransactionDraft) {}
fn interrupt(&mut self) {}
fn load(&mut self, _draft: &TransactionDraft) {}
@ -394,7 +394,7 @@ impl Step for DefineSpend {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::CreateSpend(msg)) => {
match msg {
@ -413,7 +413,7 @@ impl Step for DefineSpend {
.as_slice(),
self.timelock,
);
return Command::none();
return Task::none();
}
view::CreateSpendMessage::AddRecipient => {
self.recipients.push(Recipient::default());
@ -483,7 +483,7 @@ impl Step for DefineSpend {
}
let feerate_vb = self.feerate.value.parse::<u64>().unwrap_or(0);
self.warning = None;
return Command::perform(
return Task::perform(
async move {
daemon
.create_spend_tx(&inputs, &outputs, feerate_vb, None)
@ -535,7 +535,7 @@ impl Step for DefineSpend {
Message::Psbt(res) => match res {
Ok(psbt) => {
self.generated = Some(psbt);
return Command::perform(async {}, |_| Message::View(view::Message::Next));
return Task::perform(async {}, |_| Message::View(view::Message::Next));
}
Err(e) => self.warning = Some(e),
},
@ -577,7 +577,7 @@ impl Step for DefineSpend {
},
_ => {}
};
Command::none()
Task::none()
}
fn apply(&self, draft: &mut TransactionDraft) {
@ -799,11 +799,11 @@ impl Step for SaveSpend {
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
if let Some((psbt_state, _)) = &mut self.spend {
psbt_state.update(daemon, cache, message)
} else {
Command::none()
Task::none()
}
}

View File

@ -5,7 +5,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH},
};
use iced::Command;
use iced::Task;
use liana::{
miniscript::bitcoin::{OutPoint, Txid},
spend::{SpendCreationError, MAX_FEERATE},
@ -110,7 +110,7 @@ impl State for TransactionsPanel {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::HistoryTransactions(res) => match res {
Err(e) => self.warning = Some(e),
@ -186,9 +186,9 @@ impl State for TransactionsPanel {
)
})
.collect();
return Command::perform(
return Task::perform(
async move {
daemon
let res = daemon
.list_coins(&[CoinStatus::Spending], &outpoints)
.await
.map(|res| {
@ -197,9 +197,10 @@ impl State for TransactionsPanel {
.filter_map(|c| c.spend_info.map(|info| info.txid))
.collect()
})
.map_err(|e| e.into())
.map_err(|e| e.into());
(Box::new(tx), is_cancel, res)
},
move |res| Message::RbfModal(Box::new(tx), is_cancel, res),
|(tx, is_cancel, res)| Message::RbfModal(tx, is_cancel, res),
);
}
}
@ -230,7 +231,7 @@ impl State for TransactionsPanel {
let daemon = daemon.clone();
let last_tx_date = last.time.unwrap();
self.processing = true;
return Command::perform(
return Task::perform(
async move {
let mut limit = HISTORY_EVENT_PAGE_SIZE;
let mut txs =
@ -282,18 +283,18 @@ impl State for TransactionsPanel {
return match &mut self.modal {
TransactionsModal::CreateRbf(modal) => modal.update(daemon, _cache, message),
TransactionsModal::Export(modal) => modal.update(message),
TransactionsModal::None => Command::none(),
TransactionsModal::None => Task::none(),
};
}
};
Command::none()
Task::none()
}
fn reload(
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
_wallet: Arc<Wallet>,
) -> Command<Message> {
) -> Task<Message> {
self.selected_tx = None;
let now: u32 = SystemTime::now()
.duration_since(UNIX_EPOCH)
@ -301,7 +302,7 @@ impl State for TransactionsPanel {
.as_secs()
.try_into()
.unwrap();
Command::batch(vec![Command::perform(
Task::batch(vec![Task::perform(
async move {
let mut txs = daemon
.list_history_txs(0, now, HISTORY_EVENT_PAGE_SIZE)
@ -395,7 +396,7 @@ impl CreateRbfModal {
daemon: Arc<dyn Daemon + Sync + Send>,
_cache: &Cache,
message: Message,
) -> Command<Message> {
) -> Task<Message> {
match message {
Message::View(view::Message::CreateRbf(view::CreateRbfMessage::FeerateEdited(s))) => {
self.warning = None;
@ -424,14 +425,14 @@ impl CreateRbfModal {
Message::View(view::Message::CreateRbf(view::CreateRbfMessage::Confirm)) => {
self.warning = None;
self.processing = true;
return Command::perform(
return Task::perform(
rbf(daemon, self.tx.clone(), self.is_cancel, self.feerate_vb),
Message::RbfPsbt,
);
}
_ => {}
}
Command::none()
Task::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<view::Message> {
let modal = Modal::new(

View File

@ -46,7 +46,7 @@ pub fn coins_view<'a>(
},
)),
)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.spacing(30)
.into()
}
@ -84,7 +84,7 @@ fn coin_list_view<'a>(
// It is not possible to know if a coin is a
// change coin or not so for now, From is
// enough
p1_regular("From").style(color::GREY_3),
p1_regular("From").color(color::GREY_3),
)
.push(p1_regular(label)),
)
@ -101,7 +101,7 @@ fn coin_list_view<'a>(
// It is not possible to know if a coin is a
// change coin or not so for now, From is
// enough
p1_regular("From").style(color::GREY_3),
p1_regular("From").color(color::GREY_3),
)
.push(p1_regular(label)),
)
@ -123,14 +123,14 @@ fn coin_list_view<'a>(
coin_sequence_label(seq, timelock as u32)
})
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(amount(&coin.amount))
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20),
)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.padding(10)
.on_press(Message::Select(index)),
)
@ -156,7 +156,7 @@ fn coin_list_view<'a>(
if blockheight > b as u32 + timelock as u32 {
Some(Container::new(
p1_bold("One of the recovery path is available")
.style(color::RED),
.color(color::RED),
))
} else {
Some(Container::new(p1_bold(format!(
@ -174,72 +174,72 @@ fn coin_list_view<'a>(
Column::new()
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
p2_regular("Address label:")
.bold()
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(if let Some(label) = labels.get(&address) {
p2_regular(label).style(color::GREY_2)
p2_regular(label).color(color::GREY_2)
} else {
p2_regular("No label").style(color::GREY_2)
p2_regular("No label").color(color::GREY_2)
})
.spacing(5),
)
.push(
Row::new()
.align_items(Alignment::Center)
.push(p2_regular("Address:").bold().style(color::GREY_2))
.align_y(Alignment::Center)
.push(p2_regular("Address:").bold().color(color::GREY_2))
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
p2_regular(address.clone())
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(
Button::new(icon::clipboard_icon())
.on_press(Message::Clipboard(
address.clone(),
))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
)
.spacing(5),
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
p2_regular("Deposit transaction label:")
.bold()
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(if let Some(label) = labels.get(&txid) {
p2_regular(label).style(color::GREY_2)
p2_regular(label).color(color::GREY_2)
} else {
p2_regular("No label").style(color::GREY_2)
p2_regular("No label").color(color::GREY_2)
})
.spacing(5),
)
.push(
Row::new()
.align_items(Alignment::Center)
.push(p2_regular("Outpoint:").bold().style(color::GREY_2))
.align_y(Alignment::Center)
.push(p2_regular("Outpoint:").bold().color(color::GREY_2))
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
p2_regular(format!("{}", coin.outpoint))
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(
Button::new(icon::clipboard_icon())
.on_press(Message::Clipboard(
coin.outpoint.to_string(),
))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
)
.spacing(5),
@ -247,9 +247,9 @@ fn coin_list_view<'a>(
.push_maybe(coin.block_height.map(|b| {
Row::new()
.push(
p2_regular("Block height:").bold().style(color::GREY_2),
p2_regular("Block height:").bold().color(color::GREY_2),
)
.push(p2_regular(format!("{}", b)).style(color::GREY_2))
.push(p2_regular(format!("{}", b)).color(color::GREY_2))
.spacing(5)
})),
)
@ -257,7 +257,7 @@ fn coin_list_view<'a>(
Column::new()
.push(
Row::new()
.push(p2_regular("Spend txid:").bold().style(color::GREY_2))
.push(p2_regular("Spend txid:").bold().color(color::GREY_2))
.push(p2_regular(format!("{}", info.txid)))
.spacing(5),
)
@ -266,13 +266,13 @@ fn coin_list_view<'a>(
.push(
p2_regular("Spend block height:")
.bold()
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(p2_regular(format!("{}", height)))
.spacing(5)
} else {
Row::new().push(
p2_regular("Not in a block").bold().style(color::GREY_2),
p2_regular("Not in a block").bold().color(color::GREY_2),
)
})
.spacing(5)
@ -291,7 +291,7 @@ fn coin_list_view<'a>(
None
}),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}
pub fn coin_sequence_label<'a, T: 'a>(seq: u32, timelock: u32) -> Container<'a, T> {
@ -301,30 +301,30 @@ pub fn coin_sequence_label<'a, T: 'a>(seq: u32, timelock: u32) -> Container<'a,
.spacing(5)
.push(icon::clock_icon().width(Length::Fixed(20.0)))
.push(p2_regular("Expired"))
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
.style(theme::Container::Pill(theme::Pill::Warning))
.style(theme::pill::warning)
} else if seq < timelock * 10 / 100 {
Container::new(
Row::new()
.spacing(5)
.push(icon::clock_icon().width(Length::Fixed(20.0)))
.push(p2_regular(expire_message(seq)))
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
.style(theme::Container::Pill(theme::Pill::Simple))
.style(theme::pill::simple)
} else {
Container::new(
Row::new()
.spacing(5)
.push(icon::clock_icon().width(Length::Fixed(20.0)))
.push(p2_regular(expire_message(seq)).style(color::GREY_3))
.align_items(Alignment::Center),
.push(p2_regular(expire_message(seq)).color(color::GREY_3))
.align_y(Alignment::Center),
)
.padding(10)
.style(theme::Container::Pill(theme::Pill::Simple))
.style(theme::pill::simple)
}
}

View File

@ -69,13 +69,13 @@ pub fn home_view<'a>(
SyncStatus::WalletFullScan => text("Syncing"),
_ => text("Checking for new transactions"),
}
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(spinner::typing_text_carousel(
"...",
true,
Duration::from_millis(2000),
|content| text(content).style(color::GREY_2),
|content| text(content).color(color::GREY_2),
)),
)
} else {
@ -86,9 +86,9 @@ pub fn home_view<'a>(
Some(
Row::new()
.spacing(10)
.push(text("+").size(H3_SIZE).style(color::GREY_3))
.push(text("+").size(H3_SIZE).color(color::GREY_3))
.push(unconfirmed_amount_with_size(unconfirmed_balance, H3_SIZE))
.push(text("unconfirmed").size(H3_SIZE).style(color::GREY_3)),
.push(text("unconfirmed").size(H3_SIZE).color(color::GREY_3)),
)
} else {
None
@ -100,7 +100,7 @@ pub fn home_view<'a>(
Container::new(
Row::new()
.spacing(15)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
h4_regular(format!(
"≈ {} left before first recovery path becomes available.",
@ -111,20 +111,20 @@ pub fn home_view<'a>(
.push(
icon::tooltip_icon()
.size(20)
.style(color::GREY_3)
.color(color::GREY_3)
.width(Length::Fixed(20.0)),
)
.width(Length::Fill),
)
.padding(25)
.style(theme::Card::Border)
.style(theme::card::border)
})
} else {
Some(
Container::new(
Row::new()
.spacing(15)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
h4_regular(format!(
"Recovery path is or will soon be available for {} coin(s).",
@ -140,7 +140,7 @@ pub fn home_view<'a>(
),
)
.padding(25)
.style(theme::Card::Invalid),
.style(theme::card::invalid),
)
})
.push(
@ -164,11 +164,11 @@ pub fn home_view<'a>(
"See more"
})
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center),
.align_x(alignment::Horizontal::Center),
)
.width(Length::Fill)
.padding(15)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press_maybe(if !processing {
Some(Message::Next)
} else {
@ -176,7 +176,7 @@ pub fn home_view<'a>(
}),
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
None
@ -193,7 +193,7 @@ fn event_list_view(event: &Payment) -> Element<'_, Message> {
event
.address_label
.as_ref()
.map(|label| p1_regular(format!("address label: {}", label)).style(color::GREY_3))
.map(|label| p1_regular(format!("address label: {}", label)).color(color::GREY_3))
};
if event.kind == PaymentKind::Incoming {
if let Some(t) = event.time {
@ -297,8 +297,8 @@ pub fn payment_view<'a>(
})
.push_maybe(tx.fee_amount.map(|fee_amount| {
Row::new()
.align_items(Alignment::Center)
.push(h3("Miner fee: ").style(color::GREY_3))
.align_y(Alignment::Center)
.push(h3("Miner fee: ").color(color::GREY_3))
.push(amount_with_size(&fee_amount, H3_SIZE))
.push(text(" ").size(H3_SIZE))
.push(
@ -307,7 +307,7 @@ pub fn payment_view<'a>(
fee_amount.to_sat() / tx.tx.vsize() as u64
))
.size(H4_SIZE)
.style(color::GREY_3),
.color(color::GREY_3),
)
}))
.push(card::simple(
@ -325,11 +325,11 @@ pub fn payment_view<'a>(
.push(
Row::new()
.width(Length::Fill)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Container::new(text("Txid:").bold()).width(Length::Fill))
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Container::new(
text(format!("{}", tx.tx.compute_txid())).small(),
))
@ -338,7 +338,7 @@ pub fn payment_view<'a>(
.on_press(Message::Clipboard(
tx.tx.compute_txid().to_string(),
))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.width(Length::Shrink),
),

View File

@ -69,7 +69,7 @@ pub fn hw_list_view(
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
})
.style(theme::Button::Border)
.style(theme::button::container_border)
.width(Length::Fill);
if !signing {
if let HardwareWallet::Supported { registered, .. } = hw {
@ -80,7 +80,7 @@ pub fn hw_list_view(
}
Container::new(bttn)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -137,14 +137,14 @@ pub fn hw_list_view_for_registration(
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
})
.style(theme::Button::Border)
.style(theme::button::container_border)
.width(Length::Fill);
if !processing && hw.is_supported() {
bttn = bttn.on_press(Message::SelectHardwareWallet(i));
}
Container::new(bttn)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -222,13 +222,13 @@ pub fn hw_list_view_verify_address(
),
};
let mut bttn = Button::new(content)
.style(theme::Button::Border)
.style(theme::button::container_border)
.width(Length::Fill);
if selectable && hw.is_supported() {
bttn = bttn.on_press(Message::SelectHardwareWallet(i));
}
Container::new(bttn)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}

View File

@ -28,7 +28,7 @@ pub fn label_editable(
)
)
.spacing(5)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.into();
}
@ -61,7 +61,7 @@ pub fn label_editing(
button::secondary(None, "Cancel").on_press(view::message::LabelMessage::Cancel)
)
.spacing(5)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.into();
e.map(move |msg| view::Message::Label(labelled.clone(), msg))

View File

@ -38,7 +38,7 @@ use crate::app::{cache::Cache, error::Error, menu::Menu};
fn menu_green_bar<'a, T: 'a>() -> Container<'a, T> {
Container::new(Space::with_width(Length::Fixed(2.0)))
.height(Length::Fixed(50.0))
.style(theme::Container::Custom(color::GREEN))
.style(theme::container::custom(color::GREEN))
}
pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> {
@ -77,7 +77,7 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> {
)
} else {
row!(button::menu(Some(coins_icon()), "Coins")
.style(theme::Button::Menu(false))
.style(theme::button::menu)
.on_press(Message::Menu(Menu::Coins))
.width(iced::Length::Fill))
};
@ -161,14 +161,14 @@ pub fn sidebar<'a>(menu: &Menu, cache: &'a Cache) -> Container<'a, Message> {
.push_maybe(cache.rescan_progress.map(|p| {
Container::new(text(format!(" Rescan...{:.2}% ", p * 100.0)))
.padding(5)
.style(theme::Pill::Simple)
.style(theme::pill::simple)
}))
.push(settings_button),
)
.height(Length::Shrink),
),
)
.style(theme::Container::Foreground)
.style(theme::container::foreground)
}
pub fn dashboard<'a, T: Into<Element<'a, Message>>>(
@ -194,9 +194,8 @@ pub fn dashboard<'a, T: Into<Element<'a, Message>>>(
.max_width(1500),
Space::with_width(Length::FillPortion(1)),
)))
.center_x()
.style(theme::Container::Background)
.width(Length::Fill)
.center_x(Length::Fill)
.style(theme::container::background)
.height(Length::Fill),
)
.width(Length::FillPortion(10)),
@ -226,11 +225,11 @@ pub fn modal<'a, T: Into<Element<'a, Message>>, F: Into<Element<'a, Message>>>(
} else {
Column::new().width(Length::Fill)
})
.align_items(iced::Alignment::Center)
.align_y(iced::Alignment::Center)
.push(button::secondary(Some(cross_icon()), "Close").on_press(Message::Close)),
)
.padding(10)
.style(theme::Container::Background),
.style(theme::container::background),
)
.push(modal_section(Container::new(scrollable(content))))
.push_maybe(fixed_footer)
@ -241,8 +240,8 @@ pub fn modal<'a, T: Into<Element<'a, Message>>, F: Into<Element<'a, Message>>>(
fn modal_section<'a, T: 'a>(menu: Container<'a, T>) -> Container<'a, T> {
Container::new(menu.max_width(1500))
.style(theme::Container::Background)
.center_x()
.style(theme::container::background)
.center_x(Length::Fill)
.width(Length::Fill)
.height(Length::Fill)
}

View File

@ -56,7 +56,7 @@ pub fn psbt_view<'a>(
.spacing(20)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(Container::new(h3("PSBT")).width(Length::Fill))
.push_maybe(if !tx.sigs.recovery_paths().is_empty() {
@ -198,14 +198,14 @@ pub fn broadcast_action<'a>(
Row::new()
.padding([0, 30])
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text(txid.to_string()))
.push(
Button::new(
icon::clipboard_icon().style(color::GREY_3),
icon::clipboard_icon().color(color::GREY_3),
)
.on_press(Message::Clipboard(txid.to_string()))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
)
},
@ -233,7 +233,7 @@ pub fn delete_action<'a>(warning: Option<&Error>, deleted: bool) -> Element<'a,
card::simple(
Column::new()
.spacing(20)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(text("Successfully deleted this transaction."))
.push(button::secondary(None, "Go back to PSBTs").on_press(Message::Close)),
)
@ -296,8 +296,8 @@ pub fn spend_header<'a>(
})
.push(
Row::new()
.align_items(Alignment::Center)
.push(h3("Miner fee: ").style(color::GREY_3))
.align_y(Alignment::Center)
.push(h3("Miner fee: ").color(color::GREY_3))
.push_maybe(if tx.fee_amount.is_none() {
Some(text("Missing information about transaction inputs"))
} else {
@ -308,7 +308,7 @@ pub fn spend_header<'a>(
.push_maybe(tx.min_feerate_vb().map(|rate| {
text(format!("(~{} sats/vbyte)", &rate))
.size(H4_SIZE)
.style(color::GREY_3)
.color(color::GREY_3)
})),
),
)
@ -331,7 +331,7 @@ pub fn spend_overview_view<'a>(
.spacing(10)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text("PSBT").bold().width(Length::Fill))
.push(
Row::new()
@ -351,28 +351,28 @@ pub fn spend_overview_view<'a>(
.on_press(Message::Spend(SpendTxMessage::EditPsbt)),
),
)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.push(
Row::new()
.push(p1_bold("Tx ID").width(Length::Fill))
.push(
p2_regular(tx.psbt.unsigned_tx.compute_txid().to_string())
.style(color::GREY_3),
.color(color::GREY_3),
)
.push(
Button::new(icon::clipboard_icon().style(color::GREY_3))
Button::new(icon::clipboard_icon().color(color::GREY_3))
.on_press(Message::Clipboard(
tx.psbt.unsigned_tx.compute_txid().to_string(),
))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
),
)
.push(signatures(tx, desc_info, key_aliases)),
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
.push_maybe(if tx.status == SpendStatus::Pending {
Some(
@ -391,7 +391,7 @@ pub fn spend_overview_view<'a>(
.width(Length::Fixed(150.0)),
)
})
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20),
)
} else {
@ -411,11 +411,11 @@ pub fn signatures<'a>(
scrollable(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(p1_bold("Status"))
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Ready").bold().style(color::GREEN))
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Ready").bold().color(color::GREEN))
.push(text(" signed by"))
.push(sigs.signed_pubkeys.keys().fold(
Row::new().spacing(5),
@ -425,22 +425,22 @@ pub fn signatures<'a>(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(10)
.style(theme::Container::Pill(theme::Pill::Simple)),
.style(theme::pill::simple),
text(value.to_string()),
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(value.to_string()))
.padding(10)
.style(theme::Container::Pill(theme::Pill::Simple))
.style(theme::pill::simple)
})
},
)),
)
.direction(scrollable::Direction::Horizontal(
scrollable::Properties::new().width(2).scroller_width(2),
scrollable::Scrollbar::new().width(2).scroller_width(2),
)),
)
.padding(15)
@ -449,42 +449,42 @@ pub fn signatures<'a>(
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20)
.push(p1_bold("Status"))
.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon().style(color::RED))
.push(text("Not ready").style(color::RED))
.align_y(Alignment::Center)
.push(icon::circle_cross_icon().color(color::RED))
.push(text("Not ready").color(color::RED))
.width(Length::Fill),
)
.push(icon::collapse_icon()),
)
.padding(15)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20)
.push(p1_bold("Status"))
.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon().style(color::RED))
.push(text("Not ready").style(color::RED))
.align_y(Alignment::Center)
.push(icon::circle_cross_icon().color(color::RED))
.push(text("Not ready").color(color::RED))
.width(Length::Fill),
)
.push(icon::collapsed_icon()),
)
.padding(15)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
Into::<Element<'a, Message>>::into(
@ -521,16 +521,16 @@ fn container_from_fg(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(10)
.style(theme::Container::Pill(theme::Pill::Simple)),
.style(theme::pill::simple),
liana_ui::widget::Text::new(fg.to_string()),
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(fg.to_string()))
.padding(10)
.style(theme::Container::Pill(theme::Pill::Simple))
.style(theme::pill::simple)
}
}
@ -565,13 +565,13 @@ pub fn path_view<'a>(
scrollable(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Row::new()
.push(if missing_signatures == 0 {
icon::circle_check_icon().style(color::GREEN)
icon::circle_check_icon().color(color::GREEN)
} else {
icon::circle_cross_icon().style(color::GREY_3)
icon::circle_cross_icon().color(color::GREY_3)
})
.push(Space::with_width(Length::Fixed(20.0))),
)
@ -587,17 +587,17 @@ pub fn path_view<'a>(
" from "
}
))
.style(color::GREY_3),
.color(color::GREY_3),
)
.push_maybe(row_unsigned)
.push_maybe(
(!sigs.signed_pubkeys.is_empty())
.then_some(p1_regular(", already signed by ").style(color::GREY_3)),
.then_some(p1_regular(", already signed by ").color(color::GREY_3)),
)
.push(row_signed),
)
.direction(scrollable::Direction::Horizontal(
scrollable::Properties::new().width(2).scroller_width(2),
scrollable::Scrollbar::new().width(2).scroller_width(2),
))
.into()
}
@ -612,7 +612,7 @@ pub fn inputs_view<'a>(
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
h4_bold(format!(
"{} coin{} spent",
@ -625,12 +625,12 @@ pub fn inputs_view<'a>(
)
.padding(20)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
h4_bold(format!(
"{} coin{} spent",
@ -643,7 +643,7 @@ pub fn inputs_view<'a>(
)
.padding(20)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
tx.input
@ -662,7 +662,7 @@ pub fn inputs_view<'a>(
.into()
},
))
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -695,7 +695,7 @@ pub fn outputs_view<'a>(
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
h4_bold(format!(
"{} payment{}",
@ -708,12 +708,12 @@ pub fn outputs_view<'a>(
)
.padding(20)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
h4_bold(format!(
"{} payment{}",
@ -726,7 +726,7 @@ pub fn outputs_view<'a>(
)
.padding(20)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
tx.output
@ -756,12 +756,14 @@ pub fn outputs_view<'a>(
.into()
},
))
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
} else {
Container::new(h4_bold("0 payment"))
.padding(20)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
Container::new(h4_bold("0 payment").style(|t| {
theme::text::custom(t.colors.buttons.transparent_border.active.text)
}))
.padding(20)
.width(Length::Fill)
.style(theme::card::simple)
}
})
.push_maybe(
@ -775,24 +777,24 @@ pub fn outputs_view<'a>(
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(h4_bold("Change").width(Length::Fill))
.push(icon::collapse_icon()),
)
.padding(20)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(h4_bold("Change").width(Length::Fill))
.push(icon::collapsed_icon()),
)
.padding(20)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
tx.output
@ -808,7 +810,7 @@ pub fn outputs_view<'a>(
.into()
},
))
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
None
@ -829,7 +831,7 @@ fn input_view<'a>(
.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(if let Some(label) = labels_editing.get(&outpoint) {
label::label_editing(vec![outpoint.clone()], label, text::P1_SIZE)
@ -848,47 +850,47 @@ fn input_view<'a>(
Column::new()
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(5)
.push(p1_bold("Outpoint:").style(color::GREY_3))
.push(p2_regular(outpoint.clone()).style(color::GREY_3))
.push(p1_bold("Outpoint:").color(color::GREY_3))
.push(p2_regular(outpoint.clone()).color(color::GREY_3))
.push(
Button::new(icon::clipboard_icon().style(color::GREY_3))
Button::new(icon::clipboard_icon().color(color::GREY_3))
.on_press(Message::Clipboard(outpoint.clone()))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
)
.push_maybe(coin.map(|c| {
let addr = c.address.to_string();
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.spacing(5)
.push(p1_bold("Address:").style(color::GREY_3))
.push(p2_regular(addr.clone()).style(color::GREY_3))
.push(p1_bold("Address:").color(color::GREY_3))
.push(p2_regular(addr.clone()).color(color::GREY_3))
.push(
Button::new(icon::clipboard_icon().style(color::GREY_3))
Button::new(icon::clipboard_icon().color(color::GREY_3))
.on_press(Message::Clipboard(addr))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
)
}))
.push_maybe(coin.and_then(|c| {
labels.get(&c.address.to_string()).map(|label| {
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.spacing(5)
.push(p1_bold("Address label:").style(color::GREY_3))
.push(p2_regular(label).style(color::GREY_3)),
.push(p1_bold("Address label:").color(color::GREY_3))
.push(p2_regular(label).color(color::GREY_3)),
)
})
})),
@ -927,7 +929,7 @@ fn payment_view<'a>(
.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(if let Some(label) = labels_editing.get(&outpoint) {
label::label_editing(change_labels, label, text::P1_SIZE)
@ -942,33 +944,33 @@ fn payment_view<'a>(
Column::new()
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.spacing(5)
.push(p1_bold("Address:").style(color::GREY_3))
.push(p2_regular(addr.clone()).style(color::GREY_3))
.push(p1_bold("Address:").color(color::GREY_3))
.push(p2_regular(addr.clone()).color(color::GREY_3))
.push(
Button::new(icon::clipboard_icon().style(color::GREY_3))
Button::new(icon::clipboard_icon().color(color::GREY_3))
.on_press(Message::Clipboard(addr.clone()))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
),
)
.push_maybe(labels.get(&addr).map(|label| {
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.spacing(5)
.push(p1_bold("Address label:").style(color::GREY_3))
.push(p2_regular(label).style(color::GREY_3)),
.push(p1_bold("Address label:").color(color::GREY_3))
.push(p2_regular(label).color(color::GREY_3)),
)
}))
}))
@ -989,19 +991,19 @@ fn change_view(output: &TxOut, network: Network) -> Element<Message> {
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill)
.spacing(5)
.push(p1_bold("Address:").style(color::GREY_3))
.push(p2_regular(addr.clone()).style(color::GREY_3))
.push(p1_bold("Address:").color(color::GREY_3))
.push(p2_regular(addr.clone()).color(color::GREY_3))
.push(
Button::new(icon::clipboard_icon().style(color::GREY_3))
Button::new(icon::clipboard_icon().color(color::GREY_3))
.on_press(Message::Clipboard(addr))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
),
)
@ -1051,14 +1053,14 @@ pub fn sign_action<'a>(
})
.on_press(Message::Spend(SpendTxMessage::SelectHotSigner))
.padding(10)
.style(theme::Button::Border)
.style(theme::button::container_border)
.width(Length::Fill)
}))
.width(Length::Fill),
)
.spacing(20)
.width(Length::Fill)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
))
.width(Length::Fixed(500.0))
.into()
@ -1086,7 +1088,7 @@ pub fn sign_action_toasts<'a>(
kind,
version.as_ref(),
fingerprint,
alias.as_ref(),
alias.as_ref().map(|x| x.as_str()),
)
.max_width(400.0)
.into(),
@ -1131,7 +1133,7 @@ pub fn update_spend_view<'a>(
button::secondary(Some(icon::clipboard_icon()), "Copy")
.on_press(Message::Clipboard(psbt)),
)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.push(separation().width(Length::Fill))
.push(
@ -1166,11 +1168,11 @@ pub fn update_spend_success_view<'a>() -> Element<'a, Message> {
Column::new()
.push(
card::simple(Container::new(
text("Spend transaction is updated").style(color::GREEN),
text("Spend transaction is updated").color(color::GREEN),
))
.padding(50),
)
.width(Length::Fixed(400.0))
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.into()
}

View File

@ -51,10 +51,10 @@ pub fn import_psbt_view<'a>(
pub fn import_psbt_success_view<'a>() -> Element<'a, Message> {
Column::new()
.push(
card::simple(Container::new(text("PSBT is imported").style(color::GREEN))).padding(50),
card::simple(Container::new(text("PSBT is imported").color(color::GREEN))).padding(50),
)
.width(Length::Fixed(400.0))
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.into()
}
@ -62,7 +62,7 @@ pub fn psbts_view(spend_txs: &[SpendTx]) -> Element<'_, Message> {
Column::new()
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(Container::new(h3("PSBTs")).width(Length::Fill))
.push(
@ -84,7 +84,7 @@ pub fn psbts_view(spend_txs: &[SpendTx]) -> Element<'_, Message> {
}),
),
)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.spacing(25)
.into()
}
@ -107,7 +107,7 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> {
Container::new(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
p2_regular(format!(
"{}/{}",
@ -118,9 +118,9 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> {
},
sigs.threshold
))
.style(color::GREY_3),
.color(color::GREY_3),
)
.push(icon::key_icon().style(color::GREY_3)),
.push(icon::key_icon().color(color::GREY_3)),
)
})
.push_maybe(
@ -129,7 +129,7 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> {
.map(p1_regular),
)
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push_maybe(if tx.is_batch() {
@ -145,7 +145,7 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> {
})
.push(
Column::new()
.align_items(Alignment::End)
.align_x(Alignment::End)
.push(if !tx.is_send_to_self() {
Container::new(amount(&tx.spend_amount))
} else {
@ -154,13 +154,13 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> {
.push_maybe(tx.fee_amount.map(|fee| amount_with_size(&fee, P2_SIZE)))
.width(Length::Fixed(140.0)),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20),
)
.padding(10)
.on_press(Message::Select(i))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}

View File

@ -42,7 +42,7 @@ pub fn receive<'a>(
Column::new()
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Container::new(h3("Receive")).width(Length::Fill))
.push(
button::secondary(Some(icon::plus_icon()), "Generate address")
@ -85,7 +85,7 @@ pub fn receive<'a>(
.push(
p2_regular(addr)
.small()
.style(color::GREY_3),
.color(color::GREY_3),
)
// Space between the address and the scrollbar
.push(Space::with_height(
@ -93,7 +93,7 @@ pub fn receive<'a>(
)),
)
.direction(scrollable::Direction::Horizontal(
scrollable::Properties::new()
scrollable::Scrollbar::new()
.width(2)
.scroller_width(2),
)),
@ -102,12 +102,12 @@ pub fn receive<'a>(
)
.push(
Button::new(
icon::clipboard_icon().style(color::GREY_3),
icon::clipboard_icon().color(color::GREY_3),
)
.on_press(Message::Clipboard(address.to_string()))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.push(
Row::new()
@ -153,14 +153,14 @@ pub fn verify_address_modal<'a>(
.push(
Row::new()
.width(Length::Fill)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(text("Address:").bold())
.width(Length::Fill),
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Container::new(
text(address.to_string()).small(),
))
@ -169,7 +169,7 @@ pub fn verify_address_modal<'a>(
.on_press(Message::Clipboard(
address.to_string(),
))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.width(Length::Shrink),
),
@ -177,7 +177,7 @@ pub fn verify_address_modal<'a>(
.push(
Row::new()
.width(Length::Fill)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(text("Derivation index:").bold())
.width(Length::Fill),
@ -211,7 +211,7 @@ pub fn verify_address_modal<'a>(
)
.spacing(20)
.width(Length::Fill)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
))
.width(Length::Fill)
.max_width(750)
@ -225,17 +225,12 @@ pub fn qr_modal<'a>(qr: &'a qr_code::Data, address: &'a String) -> Element<'a, M
.push(Space::with_width(Length::Fill))
.push(
Container::new(QRCode::<liana_ui::theme::Theme>::new(qr).cell_size(8))
.padding(10)
.style(theme::Container::QrCode),
.padding(10),
)
.push(Space::with_width(Length::Fill)),
)
.push(Space::with_height(Length::Fixed(15.0)))
.push(
Container::new(text(address).size(15))
.width(Length::Fill)
.center_x(),
)
.push(Container::new(text(address).size(15)).center_x(Length::Fill))
.width(Length::Fill)
.max_width(400)
.into()

View File

@ -44,16 +44,16 @@ pub fn recovery<'a>(
.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Button::new(text("Settings").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Menu(Menu::Settings)),
)
.push(icon::chevron_right().size(30))
.push(
Button::new(text("Recovery").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Menu(Menu::Recovery)),
),
)
@ -61,7 +61,7 @@ pub fn recovery<'a>(
.push(
Row::new()
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text("Destination").bold())
.push(
Container::new(
@ -102,7 +102,7 @@ pub fn recovery<'a>(
)))
.push(Column::with_children(recovery_paths).spacing(20)),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.padding(20)
})
.push_maybe(if no_recovery_paths {
@ -126,7 +126,7 @@ pub fn recovery<'a>(
},
)
.spacing(20)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
})
.spacing(20),
@ -151,7 +151,7 @@ pub fn recovery_path_view<'a>(
Column::new()
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(
text(format!(
@ -162,23 +162,23 @@ pub fn recovery_path_view<'a>(
.bold(),
)
.push(origins.iter().fold(
Row::new().align_items(Alignment::Center).spacing(5),
Row::new().align_y(Alignment::Center).spacing(5),
|row, (fg, _)| {
row.push(if let Some(alias) = key_aliases.get(fg) {
Container::new(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(5)
.style(theme::Container::Pill(theme::Pill::Simple)),
.style(theme::pill::simple),
liana_ui::widget::Text::new(fg.to_string()),
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(fg.to_string()))
.padding(5)
.style(theme::Container::Pill(theme::Pill::Simple))
.style(theme::pill::simple)
})
},
)),
@ -197,7 +197,7 @@ pub fn recovery_path_view<'a>(
.spacing(5),
)
.width(Length::Fill)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20)
.into()
}

View File

@ -46,99 +46,99 @@ pub fn list(cache: &Cache, is_remote_backend: bool) -> Element<Message> {
.width(Length::Fill)
.push(
Button::new(text("Settings").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Menu(Menu::Settings)))
.push(
if !is_remote_backend {
Container::new(
Button::new(
Row::new()
.push(badge::Badge::new(icon::bitcoin_icon()))
.push(badge::badge(icon::bitcoin_icon()))
.push(text("Node").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(Message::Settings(SettingsMessage::EditBitcoindSettings))
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
} else {
Container::new(
Button::new(
Row::new()
.push(badge::Badge::new(icon::bitcoin_icon()))
.push(badge::badge(icon::bitcoin_icon()))
.push(text("Backend").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(Message::Settings(SettingsMessage::EditRemoteBackendSettings))
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}
)
.push(
Container::new(
Button::new(
Row::new()
.push(badge::Badge::new(icon::wallet_icon()))
.push(badge::badge(icon::wallet_icon()))
.push(text("Wallet").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(Message::Settings(SettingsMessage::EditWalletSettings))
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
)
.push(
Container::new(
Button::new(
Row::new()
.push(badge::Badge::new(icon::recovery_icon()))
.push(badge::badge(icon::recovery_icon()))
.push(text("Recovery").bold())
.push(tooltip("In case of loss of the main key, the recovery key can move the funds after a certain time."))
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(Message::Menu(Menu::Recovery))
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
)
.push(
Container::new(
Button::new(
Row::new()
.push(badge::Badge::new(icon::tooltip_icon()))
.push(badge::badge(icon::tooltip_icon()))
.push(text("About").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(Message::Settings(SettingsMessage::AboutSection))
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
)
)
}
@ -156,16 +156,16 @@ pub fn bitcoind_settings<'a>(
.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Button::new(text("Settings").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Menu(Menu::Settings)),
)
.push(icon::chevron_right().size(30))
.push(
Button::new(text("Node").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Settings(SettingsMessage::EditBitcoindSettings)),
),
)
@ -187,16 +187,16 @@ pub fn about_section<'a>(
.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Button::new(text("Settings").size(30).bold())
.style(theme::Button::Transparent)
.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(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Settings(SettingsMessage::AboutSection)),
),
)
@ -205,11 +205,11 @@ pub fn about_section<'a>(
Column::new()
.push(
Row::new()
.push(badge::Badge::new(icon::tooltip_icon()))
.push(badge::badge(icon::tooltip_icon()))
.push(text("Version").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(separation().width(Length::Fill))
@ -246,16 +246,16 @@ pub fn remote_backend_section<'a>(
.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Button::new(text("Settings").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Menu(Menu::Settings)),
)
.push(icon::chevron_right().size(30))
.push(
Button::new(text("Backend").size(30).bold())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Settings(
SettingsMessage::EditRemoteBackendSettings,
)),
@ -279,7 +279,7 @@ pub fn remote_backend_section<'a>(
.push(
Row::new()
.push_maybe(if success {
Some(text("Invitation was sent").style(color::GREEN))
Some(text("Invitation was sent").color(color::GREEN))
} else {
None
})
@ -318,7 +318,7 @@ pub fn bitcoind_edit<'a>(
Row::new()
.push(
Row::new()
.push(badge::Badge::new(icon::network_icon()))
.push(badge::badge(icon::network_icon()))
.push(
Column::new()
.push(text("Network:"))
@ -329,7 +329,7 @@ pub fn bitcoind_edit<'a>(
)
.push(
Row::new()
.push(badge::Badge::new(icon::block_icon()))
.push(badge::badge(icon::block_icon()))
.push(
Column::new()
.push(text("Block Height:"))
@ -358,7 +358,7 @@ pub fn bitcoind_edit<'a>(
SettingsEditMessage::BitcoindRpcAuthTypeSelected,
))
.spacing(30)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
},
),
)
@ -423,11 +423,11 @@ pub fn bitcoind_edit<'a>(
Column::new()
.push(
Row::new()
.push(badge::Badge::new(icon::bitcoin_icon()))
.push(badge::badge(icon::bitcoin_icon()))
.push(text("Bitcoin Core").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(separation().width(Length::Fill))
@ -438,7 +438,7 @@ pub fn bitcoind_edit<'a>(
.push(cancel_button)
.push(confirm_button)
.spacing(10)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.width(Length::Fill)
.align_x(alignment::Horizontal::Right),
@ -464,7 +464,7 @@ pub fn bitcoind<'a>(
Row::new()
.push(
Row::new()
.push(badge::Badge::new(icon::network_icon()))
.push(badge::badge(icon::network_icon()))
.push(
Column::new()
.push(text("Network:"))
@ -475,7 +475,7 @@ pub fn bitcoind<'a>(
)
.push(
Row::new()
.push(badge::Badge::new(icon::block_icon()))
.push(badge::badge(icon::block_icon()))
.push(
Column::new()
.push(text("Block Height:"))
@ -516,10 +516,10 @@ pub fn bitcoind<'a>(
.push(Space::with_width(10))
.push(
Button::new(icon::clipboard_icon())
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(SettingsEditMessage::Clipboard(v.to_string())),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
});
}
@ -529,7 +529,7 @@ pub fn bitcoind<'a>(
Row::new()
.push(
Row::new()
.push(badge::Badge::new(icon::bitcoin_icon()))
.push(badge::badge(icon::bitcoin_icon()))
.push(text("Bitcoin Core").bold())
.push_maybe(if is_configured_node_type {
Some(is_running_label(is_running))
@ -537,17 +537,17 @@ pub fn bitcoind<'a>(
None
})
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(if can_edit {
Button::new(icon::pencil_icon())
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(SettingsEditMessage::Select)
} else {
Button::new(icon::pencil_icon()).style(theme::Button::TransparentBorder)
Button::new(icon::pencil_icon()).style(theme::button::transparent_border)
})
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.push(separation().width(Length::Fill))
.push(col.push(col_fields))
@ -571,7 +571,7 @@ pub fn electrum_edit<'a>(
Row::new()
.push(
Row::new()
.push(badge::Badge::new(icon::network_icon()))
.push(badge::badge(icon::network_icon()))
.push(
Column::new()
.push(text("Network:"))
@ -582,7 +582,7 @@ pub fn electrum_edit<'a>(
)
.push(
Row::new()
.push(badge::Badge::new(icon::block_icon()))
.push(badge::badge(icon::block_icon()))
.push(
Column::new()
.push(text("Block Height:"))
@ -621,11 +621,11 @@ pub fn electrum_edit<'a>(
Column::new()
.push(
Row::new()
.push(badge::Badge::new(icon::bitcoin_icon()))
.push(badge::badge(icon::bitcoin_icon()))
.push(text("Electrum").bold())
.padding(10)
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(separation().width(Length::Fill))
@ -636,7 +636,7 @@ pub fn electrum_edit<'a>(
.push(cancel_button)
.push(confirm_button)
.spacing(10)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.width(Length::Fill)
.align_x(alignment::Horizontal::Right),
@ -662,7 +662,7 @@ pub fn electrum<'a>(
Row::new()
.push(
Row::new()
.push(badge::Badge::new(icon::network_icon()))
.push(badge::badge(icon::network_icon()))
.push(
Column::new()
.push(text("Network:"))
@ -673,7 +673,7 @@ pub fn electrum<'a>(
)
.push(
Row::new()
.push(badge::Badge::new(icon::block_icon()))
.push(badge::badge(icon::block_icon()))
.push(
Column::new()
.push(text("Block Height:"))
@ -701,10 +701,10 @@ pub fn electrum<'a>(
.push(Space::with_width(10))
.push(
Button::new(icon::clipboard_icon())
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(SettingsEditMessage::Clipboard(v.to_string())),
)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
);
}
@ -714,7 +714,7 @@ pub fn electrum<'a>(
Row::new()
.push(
Row::new()
.push(badge::Badge::new(icon::bitcoin_icon()))
.push(badge::badge(icon::bitcoin_icon()))
.push(text("Electrum").bold())
.push_maybe(if is_configured_node_type {
Some(is_running_label(is_running))
@ -722,17 +722,17 @@ pub fn electrum<'a>(
None
})
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(if can_edit {
Button::new(icon::pencil_icon())
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press(SettingsEditMessage::Select)
} else {
Button::new(icon::pencil_icon()).style(theme::Button::TransparentBorder)
Button::new(icon::pencil_icon()).style(theme::button::transparent_border)
})
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.push(separation().width(Length::Fill))
.push(col.push(col_fields))
@ -747,16 +747,16 @@ pub fn is_running_label<'a, T: 'a>(is_running: Option<bool>) -> Container<'a, T>
if running {
Container::new(
Row::new()
.push(icon::dot_icon().size(5).style(color::GREEN))
.push(text("Running").small().style(color::GREEN))
.align_items(Alignment::Center),
.push(icon::dot_icon().size(5).color(color::GREEN))
.push(text("Running").small().color(color::GREEN))
.align_y(Alignment::Center),
)
} else {
Container::new(
Row::new()
.push(icon::dot_icon().size(5).style(color::RED))
.push(text("Not running").small().style(color::RED))
.align_items(Alignment::Center),
.push(icon::dot_icon().size(5).color(color::RED))
.push(text("Not running").small().color(color::RED))
.align_y(Alignment::Center),
)
}
} else {
@ -781,15 +781,15 @@ pub fn rescan<'a>(
Column::new()
.push(
Row::new()
.push(badge::Badge::new(icon::block_icon()))
.push(badge::badge(icon::block_icon()))
.push(text("Blockchain rescan").bold().width(Length::Fill))
.push_maybe(if success {
Some(text("Successfully rescanned the blockchain").style(color::GREEN))
Some(text("Successfully rescanned the blockchain").color(color::GREEN))
} else {
None
})
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(separation().width(Length::Fill))
@ -830,24 +830,24 @@ pub fn rescan<'a>(
.size(P1_SIZE)
.padding(5),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10),
)
.push_maybe(if invalid_date {
Some(p1_regular("Provided date is invalid").style(color::RED))
Some(p1_regular("Provided date is invalid").color(color::RED))
} else {
None
})
.push_maybe(if past_possible_height {
Some(
p1_regular("Provided date earlier than the node prune height")
.style(color::RED),
.color(color::RED),
)
} else {
None
})
.push_maybe(if future_date {
Some(p1_regular("Provided date is in the future").style(color::RED))
Some(p1_regular("Provided date is in the future").color(color::RED))
} else {
None
})
@ -910,16 +910,16 @@ pub fn wallet_settings<'a>(
.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Button::new(text("Settings").size(30).bold())
.style(theme::Button::Transparent)
.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(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(Message::Settings(SettingsMessage::EditWalletSettings)),
),
)
@ -935,7 +935,7 @@ pub fn wallet_settings<'a>(
)
.direction(
scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
scrollable::Scrollbar::new().width(5).scroller_width(5),
),
),
)
@ -973,7 +973,7 @@ pub fn wallet_settings<'a>(
col.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
text(fg.to_string()).bold().width(Length::Fixed(100.0)),
)
@ -994,14 +994,14 @@ pub fn wallet_settings<'a>(
))
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Space::with_width(Length::Fill))
.push_maybe(if updated {
Some(
Row::new()
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Updated").style(color::GREEN)),
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Updated").color(color::GREEN)),
)
} else {
None
@ -1063,7 +1063,7 @@ fn display_policy(
text(k.to_string()),
iced_tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(format!("[{}]", k)).bold())
@ -1116,7 +1116,7 @@ fn display_policy(
text(k.to_string()),
iced_tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(format!("[{}]", k)).bold())
@ -1146,7 +1146,7 @@ fn display_policy(
.spacing(10)
.push(text("The wallet policy:").bold())
.push(scrollable(col).direction(scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
scrollable::Scrollbar::new().width(5).scroller_width(5),
)))
.into()
}
@ -1228,7 +1228,7 @@ pub fn register_wallet_modal<'a>(
)
.spacing(20)
.width(Length::Fill)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
))
.width(Length::Fixed(500.0))
.into()

View File

@ -57,8 +57,8 @@ pub fn spend_view<'a>(
col.push(
Row::new()
.spacing(5)
.push(icon::warning_icon().style(color::ORANGE))
.push(text(warning).style(color::ORANGE)),
.push(icon::warning_icon().color(color::ORANGE))
.push(text(warning).color(color::ORANGE)),
)
},
))
@ -154,7 +154,7 @@ pub fn create_spend_tx<'a>(
Some(
Container::new(
text("Two payment addresses are the same")
.style(color::RED),
.color(color::RED),
)
.padding(10),
)
@ -206,7 +206,7 @@ pub fn create_spend_tx<'a>(
.spacing(10)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(p1_bold("Coins selection").width(Length::Fill))
.push(if is_self_send {
Row::new()
@ -226,7 +226,7 @@ pub fn create_spend_tx<'a>(
),
P2_SIZE,
))
.push(p2_regular("selected").style(color::GREY_3))
.push(p2_regular("selected").color(color::GREY_3))
} else if let Some(amount_left) = amount_left {
if amount_left.to_sat() == 0 && !is_valid {
// If amount left is set, the current configuration must be redraftable.
@ -237,20 +237,20 @@ pub fn create_spend_tx<'a>(
// and it has the max selected.
Row::new().push(
text("Select at least one coin.")
.style(color::GREY_3),
.color(color::GREY_3),
)
} else {
// There must be a recipient with max selected and value 0.
Row::new().push(
text("Check max amount for recipient.")
.style(color::GREY_3),
.color(color::GREY_3),
)
}
} else {
Row::new()
.spacing(5)
.push(amount_with_size(amount_left, P2_SIZE))
.push(p2_regular("left to select").style(color::GREY_3))
.push(p2_regular("left to select").color(color::GREY_3))
}
} else {
Row::new().push(
@ -259,7 +259,7 @@ pub fn create_spend_tx<'a>(
} else {
"Add recipient details."
})
.style(color::GREY_3),
.color(color::GREY_3),
)
})
.width(Length::Fill),
@ -282,12 +282,12 @@ pub fn create_spend_tx<'a>(
),
)
.padding(20)
.style(theme::Card::Simple),
.style(theme::card::simple),
)
.push(
Row::new()
.spacing(20)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Space::with_width(Length::Fill))
.push(
button::secondary(None, "Clear")
@ -325,14 +325,14 @@ pub fn recipient_view<'a>(
.push(
Row::new().push(Space::with_width(Length::Fill)).push(
Button::new(icon::cross_icon())
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.on_press(CreateSpendMessage::DeleteRecipient(index))
.width(Length::Shrink),
),
)
.push(
Row::new()
.align_items(Alignment::Start)
.align_y(Alignment::Start)
.spacing(10)
.push(
Container::new(p1_bold("Address"))
@ -351,7 +351,7 @@ pub fn recipient_view<'a>(
)
.push(
Row::new()
.align_items(Alignment::Start)
.align_y(Alignment::Start)
.spacing(10)
.push(
Container::new(p1_bold("Description"))
@ -370,7 +370,7 @@ pub fn recipient_view<'a>(
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(
Container::new(p1_bold("Amount"))
@ -384,7 +384,7 @@ pub fn recipient_view<'a>(
.map(amount_as_string)
.unwrap_or(amount.value.clone());
Some(
Container::new(text(amount_txt).size(P1_SIZE).style(color::GREY_2))
Container::new(text(amount_txt).size(P1_SIZE).color(color::GREY_2))
.padding(10)
.width(Length::Fill),
)
@ -414,7 +414,7 @@ pub fn recipient_view<'a>(
),
)
.padding(20)
.style(theme::Card::Simple)
.style(theme::card::simple)
.into()
}
@ -445,7 +445,7 @@ fn coin_list_view<'a>(
// It is not possible to know if a coin is a
// change coin or not so for now, From is
// enough
p1_regular("From").style(color::GREY_3),
p1_regular("From").color(color::GREY_3),
)
.push(p1_regular(label)),
)
@ -463,13 +463,13 @@ fn coin_list_view<'a>(
coins::coin_sequence_label(seq, timelock as u32)
})
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push(amount(&coin.amount))
// give some space for the scroll bar without using padding
.push(Space::with_width(Length::Fixed(0.0)))
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20)
.into()
}

View File

@ -67,11 +67,11 @@ pub fn transactions_view<'a>(
"See more"
})
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center),
.align_x(alignment::Horizontal::Center),
)
.width(Length::Fill)
.padding(15)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.on_press_maybe(if !processing {
Some(Message::Next)
} else {
@ -79,13 +79,13 @@ pub fn transactions_view<'a>(
}),
)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
None
}),
)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.spacing(30),
)
}
@ -121,13 +121,13 @@ fn tx_list_view(i: usize, tx: &HistoryTransaction) -> Element<'_, Message> {
.format("%b. %d, %Y - %T")
.to_string(),
)
.style(color::GREY_3)
.color(color::GREY_3)
.small(),
)
})),
)
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
)
.push_maybe(if tx.time.is_none() {
@ -145,24 +145,24 @@ fn tx_list_view(i: usize, tx: &HistoryTransaction) -> Element<'_, Message> {
.spacing(5)
.push(text("+"))
.push(amount(&tx.incoming_amount))
.align_items(Alignment::Center)
.align_y(Alignment::Center)
} else if tx.outgoing_amount != Amount::from_sat(0) {
Row::new()
.spacing(5)
.push(text("-"))
.push(amount(&tx.outgoing_amount))
.align_items(Alignment::Center)
.align_y(Alignment::Center)
} else {
Row::new().push(text("Self-transfer"))
})
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20),
)
.padding(10)
.on_press(Message::Select(i))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -235,12 +235,12 @@ pub fn create_rbf_modal<'a>(
Row::new()
.padding([0, 30])
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text(txid.to_string()))
.push(
Button::new(icon::clipboard_icon().style(color::GREY_3))
Button::new(icon::clipboard_icon().color(color::GREY_3))
.on_press(Message::Clipboard(txid.to_string()))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
),
)
},
@ -274,11 +274,11 @@ pub fn create_rbf_modal<'a>(
} else {
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(
text("Replacement PSBT created successfully and ready to be signed")
.style(color::GREEN),
.color(color::GREEN),
)
}))
.push_maybe(replacement_txid.map(|id| {
@ -342,8 +342,8 @@ pub fn tx_view<'a>(
})
.push_maybe(tx.fee_amount.map(|fee_amount| {
Row::new()
.align_items(Alignment::Center)
.push(h3("Miner fee: ").style(color::GREY_3))
.align_y(Alignment::Center)
.push(h3("Miner fee: ").color(color::GREY_3))
.push(amount_with_size(&fee_amount, H3_SIZE))
.push(text(" ").size(H3_SIZE))
.push(
@ -352,7 +352,7 @@ pub fn tx_view<'a>(
fee_amount.to_sat() / tx.tx.vsize() as u64
))
.size(H4_SIZE)
.style(color::GREY_3),
.color(color::GREY_3),
)
})),
),
@ -396,16 +396,16 @@ pub fn tx_view<'a>(
.push(
Row::new()
.width(Length::Fill)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Container::new(text("Txid:").bold()).width(Length::Fill))
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(Container::new(text(txid.clone()).small()))
.push(
Button::new(icon::clipboard_icon())
.on_press(Message::Clipboard(txid.clone()))
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.width(Length::Shrink),
),

View File

@ -1,4 +1,4 @@
use iced::Command;
use iced::Task;
use std::{
collections::HashMap,
path::PathBuf,
@ -215,7 +215,7 @@ impl HardwareWallets {
pub fn update(
&mut self,
message: HardwareWalletMessage,
) -> Result<Command<HardwareWalletMessage>, async_hwi::Error> {
) -> Result<Task<HardwareWalletMessage>, async_hwi::Error> {
match message {
HardwareWalletMessage::Error(e) => Err(async_hwi::Error::Device(e)),
HardwareWalletMessage::List(ConnectedList { still, mut new }) => {
@ -237,7 +237,7 @@ impl HardwareWallets {
let id = id.to_string();
let network = self.network;
let wallet = self.wallet.clone();
cmds.push(Command::perform(
cmds.push(Task::perform(
async move {
(
id.clone(),
@ -252,7 +252,7 @@ impl HardwareWallets {
let id_cloned = id.clone();
let network = self.network;
let wallet = self.wallet.clone();
cmds.push(Command::perform(
cmds.push(Task::perform(
async move {
if let Err(e) = device.auth().await {
return (id_cloned, Err(e.into()));
@ -278,9 +278,9 @@ impl HardwareWallets {
}
}
if cmds.is_empty() {
Ok(Command::none())
Ok(Task::none())
} else {
Ok(Command::batch(cmds))
Ok(Task::batch(cmds))
}
}
HardwareWalletMessage::Unlocked(id, res) => {
@ -307,7 +307,7 @@ impl HardwareWallets {
}
}
}
Ok(Command::none())
Ok(Task::none())
}
}
}

View File

@ -4,7 +4,7 @@ mod prompt;
mod step;
mod view;
use iced::{clipboard, Command, Subscription};
use iced::{clipboard, Subscription, Task};
use liana::miniscript::bitcoin::{self, Network};
use liana_ui::{
component::network_banner,
@ -64,13 +64,13 @@ pub struct Installer {
}
impl Installer {
fn previous(&mut self) -> Command<Message> {
fn previous(&mut self) -> Task<Message> {
self.hws.reset_watch_list();
let network = self.network;
if self.current > 0 {
self.current -= 1;
} else {
return Command::perform(async move { network }, Message::BackToLauncher);
return Task::perform(async move { network }, Message::BackToLauncher);
}
// skip the previous step according to the current context.
while self
@ -82,14 +82,14 @@ impl Installer {
if self.current > 0 {
self.current -= 1;
} else {
return Command::perform(async move { network }, Message::BackToLauncher);
return Task::perform(async move { network }, Message::BackToLauncher);
}
}
if let Some(step) = self.steps.get(self.current) {
step.revert(&mut self.context)
}
Command::none()
Task::none()
}
pub fn new(
@ -97,7 +97,7 @@ impl Installer {
network: bitcoin::Network,
remote_backend: Option<BackendClient>,
user_flow: UserFlow,
) -> (Installer, Command<Message>) {
) -> (Installer, Task<Message>) {
let signer = Arc::new(Mutex::new(Signer::generate(network).unwrap()));
let context = Context::new(
network,
@ -197,7 +197,7 @@ impl Installer {
}
}
fn next(&mut self) -> Command<Message> {
fn next(&mut self) -> Task<Message> {
self.hws.reset_watch_list();
let current_step = self
.steps
@ -209,7 +209,7 @@ impl Installer {
} else {
// The step is already the last current step.
// No need to reload the current step.
return Command::none();
return Task::none();
}
// skip the step according to the current context.
self.skip_steps();
@ -222,16 +222,16 @@ impl Installer {
current_step.load_context(&self.context);
return current_step.load();
}
Command::none()
Task::none()
}
pub fn update(&mut self, message: Message) -> Command<Message> {
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::HardwareWallets(msg) => match self.hws.update(msg) {
Ok(cmd) => cmd.map(Message::HardwareWallets),
Err(e) => {
error!("{}", e);
Command::none()
Task::none()
}
},
Message::Clibpboard(s) => clipboard::write(s),
@ -244,7 +244,7 @@ impl Installer {
.expect("There is always a step")
.update(&mut self.hws, message);
match &self.context.remote_backend {
RemoteBackend::WithoutWallet(backend) => Command::perform(
RemoteBackend::WithoutWallet(backend) => Task::perform(
create_remote_wallet(
self.context.clone(),
self.signer.clone(),
@ -252,11 +252,11 @@ impl Installer {
),
Message::Installed,
),
RemoteBackend::WithWallet(backend) => Command::perform(
RemoteBackend::WithWallet(backend) => Task::perform(
import_remote_wallet(self.context.clone(), backend.clone()),
Message::Installed,
),
RemoteBackend::None => Command::perform(
RemoteBackend::None => Task::perform(
install_local_wallet(self.context.clone(), self.signer.clone()),
Message::Installed,
),

View File

@ -1,6 +1,6 @@
use std::str::FromStr;
use iced::Command;
use iced::Task;
use liana::{descriptors::LianaDescriptor, miniscript::bitcoin::Network};
use liana_ui::{component::form, widget::Element};
@ -44,15 +44,15 @@ impl Step for ChooseBackend {
fn skip(&self, _ctx: &Context) -> bool {
self.network != Network::Bitcoin && self.network != Network::Signet
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::SelectBackend(message::SelectBackend::ContinueWithLocalWallet(
local_wallet,
)) = message
{
self.remote_backend_is_selected = !local_wallet;
Command::perform(async move {}, |_| Message::Next)
Task::perform(async move {}, |_| Message::Next)
} else {
Command::none()
Task::none()
}
}
@ -128,7 +128,7 @@ impl Step for RemoteBackendLogin {
matches!(ctx.remote_backend, RemoteBackend::None)
|| (self.network != Network::Bitcoin && self.network != Network::Signet)
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
match &mut self.step {
ConnectionStep::EnterEmail { email } => match message {
Message::SelectBackend(message::SelectBackend::EmailEdited(value)) => {
@ -149,7 +149,7 @@ impl Step for RemoteBackendLogin {
self.processing = true;
self.connection_error = None;
self.auth_error = None;
return Command::perform(
return Task::perform(
async move {
let config =
client::get_service_config(network).await.map_err(|e| {
@ -211,7 +211,7 @@ impl Step for RemoteBackendLogin {
self.processing = true;
self.connection_error = None;
self.auth_error = None;
return Command::perform(
return Task::perform(
async move {
client.resend_otp().await?;
Ok(())
@ -236,7 +236,7 @@ impl Step for RemoteBackendLogin {
self.connection_error = None;
self.auth_error = None;
let network = self.network;
return Command::perform(
return Task::perform(
async move { connect(client, otp, backend_api_url, network).await },
message::SelectBackend::Connected,
)
@ -252,7 +252,7 @@ impl Step for RemoteBackendLogin {
email: email.clone(),
remote_backend,
};
return Command::perform(async move {}, |_| Message::Next);
return Task::perform(async move {}, |_| Message::Next);
}
Err(e) => {
if let Error::Auth(AuthError { http_status, .. }) = e {
@ -278,7 +278,7 @@ impl Step for RemoteBackendLogin {
}
}
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {
@ -377,9 +377,9 @@ impl Step for ImportRemoteWallet {
fn load_context(&mut self, ctx: &Context) {
self.backend = ctx.remote_backend.clone();
}
fn load(&self) -> Command<Message> {
fn load(&self) -> Task<Message> {
let backend = self.backend.clone();
Command::perform(
Task::perform(
async move {
let wallets = match backend {
context::RemoteBackend::WithoutWallet(backend) => {
@ -398,7 +398,7 @@ impl Step for ImportRemoteWallet {
}
// form value is set as valid each time it is edited.
// Verification of the values is happening when the user click on Next button.
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
match message {
Message::ImportRemoteWallet(message::ImportRemoteWallet::ImportDescriptor(desc)) => {
self.imported_descriptor.value = desc;
@ -430,7 +430,7 @@ impl Step for ImportRemoteWallet {
context::RemoteBackend::WithoutWallet(backend.into_inner());
}
self.descriptor = Some(desc);
return Command::perform(async {}, |_| Message::Next);
return Task::perform(async {}, |_| Message::Next);
}
} else {
self.imported_descriptor.valid = false;
@ -455,7 +455,7 @@ impl Step for ImportRemoteWallet {
};
let token = self.invitation_token.value.clone();
self.error = None;
return Command::perform(
return Task::perform(
async move {
let invitation = backend.get_wallet_invitation(&token).await?;
Ok(invitation)
@ -481,7 +481,7 @@ impl Step for ImportRemoteWallet {
};
let invitation = self.invitation.clone().expect("Invitation was fetched");
self.error = None;
return Command::perform(
return Task::perform(
async move {
backend.accept_wallet_invitation(&invitation.id).await?;
let wallets = backend.list_wallets().await?;
@ -531,13 +531,13 @@ impl Step for ImportRemoteWallet {
// ensure that no descriptor is imported.
self.imported_descriptor = form::Value::default();
self.descriptor = Some(wallet.descriptor);
return Command::perform(async {}, |_| Message::Next);
return Task::perform(async {}, |_| Message::Next);
}
}
_ => {}
}
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {

View File

@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::miniscript::bitcoin::bip32::Xpub;
use liana::miniscript::{
bitcoin::{
@ -137,8 +137,8 @@ impl EditXpubModal {
}
}
pub fn load(&self) -> Command<Message> {
Command::none()
pub fn load(&self) -> Task<Message> {
Task::none()
}
}
@ -147,7 +147,7 @@ impl super::DescriptorEditModal for EditXpubModal {
self.processing
}
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Task<Message> {
// Reset these fields.
// the function will setup them again if something is wrong
self.duplicate_master_fg = false;
@ -167,10 +167,19 @@ impl super::DescriptorEditModal for EditXpubModal {
let device_version = version.clone();
let fingerprint = *fingerprint;
let device_kind = *kind;
let device_cloned = device.clone();
let network = self.network;
return Command::perform(
get_extended_pubkey(device.clone(), fingerprint, self.network),
move |res| {
return Task::perform(
async move {
(
device_version,
device_kind,
fingerprint,
network,
get_extended_pubkey(device_cloned, fingerprint, network).await,
)
},
|(device_version, device_kind, fingerprint, network, res)| {
Message::DefineDescriptor(message::DefineDescriptor::KeyModal(
message::ImportKeyModal::FetchedKey(match res {
Err(e) => Err(e),
@ -306,7 +315,7 @@ impl super::DescriptorEditModal for EditXpubModal {
self.duplicate_master_fg = true;
} else {
let coordinate = self.keys_coordinate.clone();
return Command::perform(
return Task::perform(
async move { (coordinate, key) },
move |(coordinate, key)| {
message::DefineDescriptor::KeysEdited(coordinate, key)
@ -326,7 +335,7 @@ impl super::DescriptorEditModal for EditXpubModal {
},
_ => {}
};
Command::none()
Task::none()
}
fn subscription(&self, hws: &HardwareWallets) -> Subscription<Message> {

View File

@ -6,7 +6,7 @@ use std::iter::FromIterator;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::{
descriptors::{LianaDescriptor, LianaPolicy, PathInfo},
miniscript::{
@ -38,8 +38,8 @@ pub trait DescriptorEditModal {
fn processing(&self) -> bool {
false
}
fn update(&mut self, _hws: &mut HardwareWallets, _message: Message) -> Command<Message> {
Command::none()
fn update(&mut self, _hws: &mut HardwareWallets, _message: Message) -> Task<Message> {
Task::none()
}
fn view<'a>(&'a self, _hws: &'a HardwareWallets) -> Element<'a, Message>;
fn subscription(&self, _hws: &HardwareWallets) -> Subscription<Message> {
@ -202,7 +202,7 @@ impl Step for DefineDescriptor {
}
// form value is set as valid each time it is edited.
// Verification of the values is happening when the user click on Next button.
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Task<Message> {
self.error = None;
match message {
Message::Close => {
@ -294,7 +294,7 @@ impl Step for DefineDescriptor {
}
message::DefinePath::Key(j, msg) => match msg {
message::DefineKey::Clipboard(key) => {
return Command::perform(async move { key }, Message::Clibpboard);
return Task::perform(async move { key }, Message::Clibpboard);
}
message::DefineKey::Edit => {
@ -347,7 +347,7 @@ impl Step for DefineDescriptor {
}
}
};
Command::none()
Task::none()
}
fn subscription(&self, hws: &HardwareWallets) -> Subscription<Message> {
@ -553,7 +553,7 @@ impl DescriptorEditModal for EditSequenceModal {
false
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::DefineDescriptor(message::DefineDescriptor::ThresholdSequenceModal(msg)) =
message
{
@ -570,7 +570,7 @@ impl DescriptorEditModal for EditSequenceModal {
if self.sequence.valid {
if let Ok(sequence) = u16::from_str(&self.sequence.value) {
let path_index = self.path_index;
return Command::perform(
return Task::perform(
async move { (path_index, sequence) },
|(path_index, sequence)| {
message::DefineDescriptor::Path(
@ -586,7 +586,7 @@ impl DescriptorEditModal for EditSequenceModal {
_ => {}
}
}
Command::none()
Task::none()
}
fn view(&self, _hws: &HardwareWallets) -> Element<Message> {
@ -613,7 +613,7 @@ impl DescriptorEditModal for EditThresholdModal {
false
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::DefineDescriptor(message::DefineDescriptor::ThresholdSequenceModal(msg)) =
message
{
@ -626,7 +626,7 @@ impl DescriptorEditModal for EditThresholdModal {
message::ThresholdSequenceModal::Confirm => {
let path_index = self.path_index;
let threshold = self.threshold.0;
return Command::perform(
return Task::perform(
async move { (path_index, threshold) },
|(path_index, threshold)| {
message::DefineDescriptor::Path(
@ -640,7 +640,7 @@ impl DescriptorEditModal for EditThresholdModal {
_ => {}
}
}
Command::none()
Task::none()
}
fn view(&self, _hws: &HardwareWallets) -> Element<Message> {

View File

@ -1,4 +1,4 @@
use iced::Command;
use iced::Task;
use liana_ui::widget::Element;
@ -23,12 +23,12 @@ impl From<ChooseDescriptorTemplate> for Box<dyn Step> {
}
}
impl Step for ChooseDescriptorTemplate {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::SelectDescriptorTemplate(template) = message {
self.template = template;
Command::perform(async move {}, |_| Message::Next)
Task::perform(async move {}, |_| Message::Next)
} else {
Command::none()
Task::none()
}
}

View File

@ -5,7 +5,7 @@ use std::{
str::FromStr,
};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::{
descriptors::LianaDescriptor,
miniscript::bitcoin::{bip32::Fingerprint, Network},
@ -77,14 +77,14 @@ impl Step for ImportDescriptor {
}
// form value is set as valid each time it is edited.
// Verification of the values is happening when the user click on Next button.
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::DefineDescriptor(message::DefineDescriptor::ImportDescriptor(desc)) =
message
{
self.imported_descriptor.value = desc;
self.check_descriptor(self.network);
}
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {
@ -173,7 +173,7 @@ impl Step for RegisterDescriptor {
map.insert(key.master_fingerprint, key.name.clone());
}
}
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Task<Message> {
match message {
Message::Select(i) => {
if let Some(HardwareWallet::Supported {
@ -188,7 +188,7 @@ impl Step for RegisterDescriptor {
self.chosen_hw = Some(i);
self.processing = true;
self.error = None;
return Command::perform(
return Task::perform(
register_wallet(
device.clone(),
*fingerprint,
@ -229,7 +229,7 @@ impl Step for RegisterDescriptor {
}
_ => {}
};
Command::none()
Task::none()
}
fn skip(&self, ctx: &Context) -> bool {
!ctx.hw_is_used
@ -243,8 +243,8 @@ impl Step for RegisterDescriptor {
fn subscription(&self, hws: &HardwareWallets) -> Subscription<Message> {
hws.refresh().map(Message::HardwareWallets)
}
fn load(&self) -> Command<Message> {
Command::none()
fn load(&self) -> Task<Message> {
Task::none()
}
fn view<'a>(
&'a self,
@ -295,11 +295,11 @@ pub struct BackupDescriptor {
}
impl Step for BackupDescriptor {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::UserActionDone(done) = message {
self.done = done;
}
Command::none()
Task::none()
}
fn load_context(&mut self, ctx: &Context) {
if self.descriptor != ctx.descriptor {

View File

@ -1,7 +1,7 @@
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use iced::Command;
use iced::Task;
use liana::{bip39, signer::HotSigner};
use liana_ui::widget::Element;
@ -36,11 +36,11 @@ impl From<BackupMnemonic> for Box<dyn Step> {
}
impl Step for BackupMnemonic {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::UserActionDone(done) = message {
self.done = done;
}
Command::none()
Task::none()
}
fn skip(&self, ctx: &Context) -> bool {
if let Some(descriptor) = &ctx.descriptor {
@ -92,7 +92,7 @@ impl From<RecoverMnemonic> for Box<dyn Step> {
}
impl Step for RecoverMnemonic {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
match message {
Message::MnemonicWord(index, value) => {
if let Some((word, valid)) = self.words.get_mut(index) {
@ -116,11 +116,11 @@ impl Step for RecoverMnemonic {
Message::ImportMnemonic(recover) => self.recover = recover,
Message::Skip => {
self.skip = true;
return Command::perform(async {}, |_| Message::Next);
return Task::perform(async {}, |_| Message::Next);
}
_ => {}
}
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {

View File

@ -22,7 +22,7 @@ pub use share_xpubs::ShareXpubs;
use std::path::PathBuf;
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana_ui::widget::*;
@ -33,8 +33,8 @@ use crate::{
};
pub trait Step {
fn update(&mut self, _hws: &mut HardwareWallets, _message: Message) -> Command<Message> {
Command::none()
fn update(&mut self, _hws: &mut HardwareWallets, _message: Message) -> Task<Message> {
Task::none()
}
fn subscription(&self, _hws: &HardwareWallets) -> Subscription<Message> {
Subscription::none()
@ -47,8 +47,8 @@ pub trait Step {
) -> Element<'a, Message>;
fn load_context(&mut self, _ctx: &Context) {}
fn load(&self) -> Command<Message> {
Command::none()
fn load(&self) -> Task<Message> {
Task::none()
}
fn skip(&self, _ctx: &Context) -> bool {
false
@ -88,14 +88,14 @@ impl Step for Final {
fn load_context(&mut self, ctx: &Context) {
self.internal_bitcoind.clone_from(&ctx.internal_bitcoind);
}
fn load(&self) -> Command<Message> {
fn load(&self) -> Task<Message> {
if !self.generating && self.config_path.is_none() {
Command::perform(async {}, |_| Message::Install)
Task::perform(async {}, |_| Message::Install)
} else {
Command::none()
Task::none()
}
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
match message {
Message::Installed(res) => {
self.generating = false;
@ -107,9 +107,11 @@ impl Step for Final {
Ok(path) => {
self.config_path = Some(path.clone());
let internal_bitcoind = self.internal_bitcoind.clone();
return Command::perform(async {}, move |_| {
Message::Exit(path.clone(), internal_bitcoind)
});
let path = path.clone();
return Task::perform(
async { (path, internal_bitcoind) },
|(path, internal_bitcoind)| Message::Exit(path, internal_bitcoind),
);
}
}
}
@ -120,7 +122,7 @@ impl Step for Final {
}
_ => {}
};
Command::none()
Task::none()
}
fn view<'a>(

View File

@ -7,7 +7,7 @@ use std::str::FromStr;
use bitcoin_hashes::{sha256, Hash};
#[cfg(any(target_os = "macos", target_os = "linux"))]
use flate2::read::GzDecoder;
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::miniscript::bitcoin::Network;
use lianad::config::{BitcoinBackend, BitcoindConfig, BitcoindRpcAuth};
#[cfg(any(target_os = "macos", target_os = "linux"))]
@ -303,16 +303,16 @@ impl Step for SelectBitcoindTypeStep {
fn skip(&self, ctx: &Context) -> bool {
ctx.remote_backend.is_some()
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::SelectBitcoindType(msg) = message {
match msg {
message::SelectBitcoindTypeMsg::UseExternal(selected) => {
self.use_external = selected;
}
};
return Command::perform(async {}, |_| Message::Next);
return Task::perform(async {}, |_| Message::Next);
};
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {
@ -410,7 +410,7 @@ impl DefineBitcoind {
self.network = Some(ctx.bitcoin_config.network);
}
pub fn update(&mut self, message: message::DefineNode) -> Command<Message> {
pub fn update(&mut self, message: message::DefineNode) -> Task<Message> {
if let message::DefineNode::DefineBitcoind(msg) = message {
match msg {
message::DefineBitcoind::ConfigFieldEdited(field, value) => match field {
@ -443,7 +443,7 @@ impl DefineBitcoind {
}
};
};
Command::none()
Task::none()
}
pub fn apply(&mut self, ctx: &mut Context) -> bool {
@ -552,7 +552,7 @@ impl Step for InternalBitcoindStep {
}
}
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::InternalBitcoind(msg) = message {
match msg {
message::InternalBitcoindMsg::Previous => {
@ -568,7 +568,7 @@ impl Step for InternalBitcoindStep {
}
}
self.started = None; // clear both Ok and Err
return Command::perform(async {}, |_| Message::Previous);
return Task::perform(async {}, |_| Message::Previous);
}
message::InternalBitcoindMsg::Reload => {
return self.load();
@ -583,7 +583,7 @@ impl Step for InternalBitcoindStep {
}
Err(e) => {
self.error = Some(e.to_string());
return Command::none();
return Task::none();
}
};
let (rpc_port, p2p_port) = if let Some(network_conf) =
@ -599,18 +599,18 @@ impl Step for InternalBitcoindStep {
"Could not get distinct ports. Please try again."
.to_string(),
);
return Command::none();
return Task::none();
}
(rpc_port, p2p_port)
}
(Ok(_), Err(e)) | (Err(e), Ok(_)) => {
self.error = Some(format!("Could not get available port: {}.", e));
return Command::none();
return Task::none();
}
(Err(e1), Err(e2)) => {
self.error =
Some(format!("Could not get available ports: {}; {}.", e1, e2));
return Command::none();
return Task::none();
}
}
};
@ -618,7 +618,7 @@ impl Step for InternalBitcoindStep {
Ok((rpc_auth, password)) => (rpc_auth, password),
Err(e) => {
self.error = Some(e.to_string());
return Command::none();
return Task::none();
}
};
let bitcoind_config = BitcoindConfig {
@ -637,12 +637,12 @@ impl Step for InternalBitcoindStep {
&self.bitcoind_datadir,
)) {
self.error = Some(e.to_string());
return Command::none();
return Task::none();
};
self.error = None;
self.internal_bitcoind_config = Some(conf);
self.bitcoind_config = Some(bitcoind_config);
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::InternalBitcoind(message::InternalBitcoindMsg::Reload)
});
}
@ -659,7 +659,7 @@ impl Step for InternalBitcoindStep {
download.progress(progress);
if let DownloadState::Finished(_) = &download.state {
info!("Download of bitcoind complete.");
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::InternalBitcoind(message::InternalBitcoindMsg::Install)
});
}
@ -681,7 +681,7 @@ impl Step for InternalBitcoindStep {
&self.liana_datadir,
VERSION,
));
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::InternalBitcoind(
message::InternalBitcoindMsg::Start,
)
@ -691,7 +691,7 @@ impl Step for InternalBitcoindStep {
info!("Installation of bitcoind failed.");
self.install_state = Some(InstallState::Errored(e.clone()));
self.error = Some(e.to_string());
return Command::none();
return Task::none();
}
};
}
@ -702,7 +702,7 @@ impl Step for InternalBitcoindStep {
self.started = Some(Err(
StartInternalBitcoindError::CouldNotCanonicalizeDataDir(e.to_string()),
));
return Command::none();
return Task::none();
};
let bitcoind_config = self
.bitcoind_config
@ -713,7 +713,7 @@ impl Step for InternalBitcoindStep {
Err(e) => {
self.started =
Some(Err(StartInternalBitcoindError::CommandError(e.to_string())));
return Command::none();
return Task::none();
}
Ok(bitcoind) => {
self.error = None;
@ -724,7 +724,7 @@ impl Step for InternalBitcoindStep {
}
};
};
Command::none()
Task::none()
}
fn subscription(&self, _hws: &HardwareWallets) -> Subscription<Message> {
@ -734,25 +734,25 @@ impl Step for InternalBitcoindStep {
Subscription::none()
}
fn load(&self) -> Command<Message> {
fn load(&self) -> Task<Message> {
if self.internal_bitcoind_config.is_none() {
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::InternalBitcoind(message::InternalBitcoindMsg::DefineConfig)
});
}
if let Some(download) = &self.exe_download {
if let DownloadState::Idle = download.state {
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::InternalBitcoind(message::InternalBitcoindMsg::Download)
});
}
}
if self.started.is_none() {
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::InternalBitcoind(message::InternalBitcoindMsg::Start)
});
}
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {

View File

@ -1,4 +1,4 @@
use iced::Command;
use iced::Task;
use liana_ui::{component::form, widget::*};
use lianad::{
config::ElectrumConfig,
@ -28,7 +28,7 @@ impl DefineElectrum {
!self.address.value.is_empty() && self.address.valid
}
pub fn update(&mut self, message: message::DefineNode) -> Command<Message> {
pub fn update(&mut self, message: message::DefineNode) -> Task<Message> {
if let message::DefineNode::DefineElectrum(msg) = message {
match msg {
message::DefineElectrum::ConfigFieldEdited(field, value) => match field {
@ -40,7 +40,7 @@ impl DefineElectrum {
},
};
};
Command::none()
Task::none()
}
pub fn apply(&mut self, ctx: &mut Context) -> bool {

View File

@ -15,7 +15,7 @@ use crate::{
node::NodeType,
};
use iced::Command;
use iced::Task;
use liana_ui::widget::Element;
#[derive(Clone)]
@ -62,7 +62,7 @@ impl NodeDefinition {
}
}
fn update(&mut self, message: message::DefineNode) -> Command<Message> {
fn update(&mut self, message: message::DefineNode) -> Task<Message> {
match self {
NodeDefinition::Bitcoind(def) => def.update(message),
NodeDefinition::Electrum(def) => def.update(message),
@ -154,11 +154,7 @@ impl DefineNode {
.find(|node| node.definition.node_type() == node_type)
}
fn update_node(
&mut self,
node_type: NodeType,
message: message::DefineNode,
) -> Command<Message> {
fn update_node(&mut self, node_type: NodeType, message: message::DefineNode) -> Task<Message> {
if let Some(node) = self.get_mut(node_type) {
// Don't make changes while waiting for a ping result so that we
// know which values the ping result applies to.
@ -167,7 +163,7 @@ impl DefineNode {
return node.definition.update(message);
}
}
Command::none()
Task::none()
}
}
@ -183,7 +179,7 @@ impl Step for DefineNode {
node.definition.load_context(ctx);
}
}
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
if let Message::DefineNode(msg) = message {
match msg {
message::DefineNode::NodeTypeSelected(node_type) => {
@ -198,7 +194,7 @@ impl Step for DefineNode {
selected.is_running = None;
let def = selected.definition.clone();
let node_type = def.node_type();
return Command::perform(async move { def.ping() }, move |res| {
return Task::perform(async move { def.ping() }, move |res| {
Message::DefineNode(message::DefineNode::PingResult((node_type, res)))
});
}
@ -222,7 +218,7 @@ impl Step for DefineNode {
}
}
}
Command::none()
Task::none()
}
fn apply(&mut self, ctx: &mut Context) -> bool {

View File

@ -1,6 +1,6 @@
use std::sync::{Arc, Mutex};
use iced::{Command, Subscription};
use iced::{Subscription, Task};
use liana::miniscript::bitcoin::{
bip32::{ChildNumber, Fingerprint},
Network,
@ -85,7 +85,7 @@ impl ShareXpubs {
impl Step for ShareXpubs {
// form value is set as valid each time it is edited.
// Verification of the values is happening when the user click on Next button.
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Command<Message> {
fn update(&mut self, hws: &mut HardwareWallets, message: Message) -> Task<Message> {
match message {
Message::ImportXpub(fg, res) => {
if let Some(hw_xpubs) = self.hw_xpubs.iter_mut().find(|x| x.fingerprint == fg) {
@ -133,7 +133,7 @@ impl Step for ShareXpubs {
error: None,
});
}
return Command::perform(
return Task::perform(
async move {
(
fingerprint,
@ -146,7 +146,7 @@ impl Step for ShareXpubs {
}
_ => {}
};
Command::none()
Task::none()
}
fn subscription(&self, hws: &HardwareWallets) -> Subscription<Message> {

View File

@ -1,3 +1,5 @@
#![allow(deprecated)]
pub mod template;
use iced::widget::{container, pick_list, scrollable, slider, Button, Space};
@ -7,6 +9,7 @@ use liana::miniscript::bitcoin::Network;
use liana_ui::component::text::{self, h3, p1_bold, p2_regular, H3_SIZE};
use liana_ui::image;
use std::borrow::Cow;
use std::fmt::Display;
use std::str::FromStr;
use liana::miniscript::bitcoin::{self, bip32::Fingerprint};
@ -62,7 +65,7 @@ pub fn define_descriptor_advanced_settings<'a>(use_taproot: bool) -> Element<'a,
}),
|kind| Message::CreateTaprootDescriptor(kind == DescriptorKind::Taproot),
)
.style(theme::PickList::Secondary)
.style(theme::pick_list::primary)
.padding(10),
));
@ -75,7 +78,7 @@ pub fn define_descriptor_advanced_settings<'a>(use_taproot: bool) -> Element<'a,
.push_maybe(if use_taproot {
Some(
p1_regular("Taproot is only supported by Liana version 5.0 and above")
.style(color::GREY_2),
.color(color::GREY_2),
)
} else {
None
@ -102,7 +105,7 @@ pub fn path(
.push(
Column::new()
.spacing(5)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(Column::with_children(keys).spacing(5)),
)
.push_maybe(if fixed {
@ -124,22 +127,22 @@ pub fn path(
}),
)
.padding(10)
.style(theme::Container::Card(theme::Card::Border))
.style(theme::card::border)
.into()
}
pub fn uneditable_defined_key<'a>(
alias: &'a str,
color: iced::Color,
title: impl Into<Cow<'a, str>>,
title: impl Into<Cow<'a, str>> + std::fmt::Display,
warning: Option<&'static str>,
) -> Element<'a, message::DefineKey> {
card::simple(
Row::new()
.spacing(10)
.width(Length::Fill)
.align_items(Alignment::Center)
.push(icon::round_key_icon().size(H3_SIZE).style(color))
.align_y(Alignment::Center)
.push(icon::round_key_icon().size(H3_SIZE).color(color))
.push(
Column::new()
.width(Length::Fill)
@ -147,13 +150,13 @@ pub fn uneditable_defined_key<'a>(
.push(
Row::new()
.spacing(10)
.push(p1_regular(title).style(color::GREY_2))
.push(p1_regular(title).color(color::GREY_2))
.push(p1_bold(alias)),
)
.push_maybe(warning.map(|w| p2_regular(w).style(color::RED))),
.push_maybe(warning.map(|w| p2_regular(w).color(color::RED))),
)
.push_maybe(if warning.is_none() {
Some(icon::check_icon().style(color::GREEN))
Some(icon::check_icon().color(color::GREEN))
} else {
None
}),
@ -164,7 +167,7 @@ pub fn uneditable_defined_key<'a>(
pub fn defined_key<'a>(
alias: &'a str,
color: iced::Color,
title: impl Into<Cow<'a, str>>,
title: impl Display,
warning: Option<&'static str>,
fixed: bool,
) -> Element<'a, message::DefineKey> {
@ -172,8 +175,8 @@ pub fn defined_key<'a>(
Row::new()
.spacing(10)
.width(Length::Fill)
.align_items(Alignment::Center)
.push(icon::round_key_icon().size(H3_SIZE).style(color))
.align_y(Alignment::Center)
.push(icon::round_key_icon().size(H3_SIZE).color(color))
.push(
Column::new()
.width(Length::Fill)
@ -181,13 +184,13 @@ pub fn defined_key<'a>(
.push(
Row::new()
.spacing(10)
.push(p1_regular(title).style(color::GREY_2))
.push(p1_regular(format!("{}", title)).color(color::GREY_2))
.push(p1_bold(alias)),
)
.push_maybe(warning.map(|w| p2_regular(w).style(color::RED))),
.push_maybe(warning.map(|w| p2_regular(w).color(color::RED))),
)
.push_maybe(if warning.is_none() {
Some(icon::check_icon().style(color::GREEN))
Some(icon::check_icon().color(color::GREEN))
} else {
None
})
@ -200,7 +203,7 @@ pub fn defined_key<'a>(
} else {
Some(
Button::new(icon::trash_icon())
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.padding(5)
.on_press(message::DefineKey::Delete),
)
@ -211,7 +214,7 @@ pub fn defined_key<'a>(
pub fn undefined_key<'a>(
color: iced::Color,
title: impl Into<Cow<'a, str>>,
title: impl Into<Cow<'a, str>> + std::fmt::Display,
active: bool,
fixed: bool,
) -> Element<'a, message::DefineKey> {
@ -219,8 +222,8 @@ pub fn undefined_key<'a>(
Row::new()
.spacing(10)
.width(Length::Fill)
.align_items(Alignment::Center)
.push(icon::round_key_icon().size(H3_SIZE).style(color))
.align_y(Alignment::Center)
.push(icon::round_key_icon().size(H3_SIZE).color(color))
.push(
Column::new()
.width(Length::Fill)
@ -240,7 +243,7 @@ pub fn undefined_key<'a>(
} else {
Some(
Button::new(icon::trash_icon())
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.padding(5)
.on_press(message::DefineKey::Delete),
)
@ -274,7 +277,7 @@ pub fn edit_key_modal<'a>(
.push(h3(title))
.push(Space::with_width(Length::Fill))
.push(button::transparent(Some(icon::cross_icon().size(40)), "").on_press(Message::Close))
.align_items(Alignment::Center)
.align_y(Alignment::Center)
)
.push(
Column::new()
@ -294,14 +297,14 @@ pub fn edit_key_modal<'a>(
})
.width(Length::Fill)
.on_press(Message::UseHotSigner)
.style(theme::Button::Border),
.style(theme::button::container_border),
)
.push(if manually_imported_xpub {
card::simple(Column::new()
.spacing(10)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(p1_regular("Enter an extended public key:").width(Length::Fill))
.push(image::success_mark_icon().width(Length::Fixed(50.0)))
)
@ -329,7 +332,7 @@ pub fn edit_key_modal<'a>(
Container::new(
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(icon::import_icon())
.push(p1_regular("Enter an extended public key"))
@ -339,7 +342,7 @@ pub fn edit_key_modal<'a>(
.on_press(Message::DefineDescriptor(
message::DefineDescriptor::KeyModal(message::ImportKeyModal::ManuallyImportXpub)
))
.style(theme::Button::Secondary),
.style(theme::button::secondary),
)
}
)
@ -355,7 +358,7 @@ pub fn edit_key_modal<'a>(
.push(text("Key name:").bold())
.push(tooltip(prompt::DEFINE_DESCRIPTOR_FINGERPRINT_TOOLTIP)),
)
.push(p1_regular("Give this key a friendly name. It helps you identify it later").style(color::GREY_2))
.push(p1_regular("Give this key a friendly name. It helps you identify it later").color(color::GREY_2))
.push(
form::Form::new("Name", form_name, |msg| {
Message::DefineDescriptor(message::DefineDescriptor::KeyModal(
@ -372,7 +375,7 @@ pub fn edit_key_modal<'a>(
)
.push_maybe(
if duplicate_master_fg {
Some(text("A single signing device may not be used more than once per path. (It can still be used in other paths.)").style(color::RED))
Some(text("A single signing device may not be used more than once per path. (It can still be used in other paths.)").color(color::RED))
} else {
None
}
@ -390,7 +393,7 @@ pub fn edit_key_modal<'a>(
} else {None})
.width(Length::Fixed(200.0))
)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
))
.width(Length::Fixed(800.0));
scrollable(content).into()
@ -421,7 +424,7 @@ pub fn edit_sequence_modal<'a>(sequence: &form::Value<String>) -> Element<'a, Me
let mut col = Column::new()
.width(Length::Fill)
.spacing(20)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(text("Keys can move the funds after inactivity of:"))
.push(
Row::new()
@ -502,7 +505,7 @@ pub fn edit_threshold_modal<'a>(threshold: (usize, usize)) -> Element<'a, Messag
Column::new()
.width(Length::Fill)
.spacing(20)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(threshsold_input::threshsold_input(
threshold.0,
threshold.1,
@ -592,7 +595,7 @@ mod threshsold_input {
fn view(&self, _state: &Self::State) -> Element<Self::Event> {
let button = |label, on_press| {
Button::new(label)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
.width(Length::Fixed(50.0))
.on_press(on_press)
};
@ -606,7 +609,7 @@ mod threshsold_input {
.align_y(alignment::Vertical::Center),
)
.push(button(icon::down_icon().size(30), Event::DecrementPressed))
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.into()
}
}

View File

@ -25,18 +25,18 @@ pub fn custom_template_description(progress: (usize, usize)) -> Element<'static,
None,
"Introduction",
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(h3("Build your own"))
.max_width(800.0)
.push(Container::new(
p1_regular("For this setup you will need to define your primary and recovery spending policies. For security reasons, we suggest you use a separate Hardware Wallet for each key belonging to them.")
.style(color::GREY_2)
.horizontal_alignment(alignment::Horizontal::Left)
.color(color::GREY_2)
.align_x(alignment::Horizontal::Left)
).align_x(alignment::Horizontal::Left).width(Length::Fill))
.push(Container::new(
p1_regular("The keys belonging to your primary policy can always spend. Those belonging to the recovery policies will be able to spend only after a defined time of wallet inactivity, allowing for secure recovery and advanced spending policies.")
.style(color::GREY_2)
.horizontal_alignment(alignment::Horizontal::Left)
.color(color::GREY_2)
.align_x(alignment::Horizontal::Left)
).align_x(alignment::Horizontal::Left).width(Length::Fill))
.push(image::custom_template_description().width(Length::Fill))
.push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next)))
@ -66,28 +66,28 @@ pub fn custom_template<'a>(
None,
"Set keys",
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.max_width(1000.0)
.push(collapse::Collapse::new(
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Advanced settings").small().bold())
.push(icon::collapse_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Advanced settings").small().bold())
.push(icon::collapsed_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || define_descriptor_advanced_settings(use_taproot),
))

View File

@ -26,34 +26,34 @@ pub fn inheritance_template_description(progress: (usize, usize)) -> Element<'st
None,
"Introduction",
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(h3("Simple inheritance wallet"))
.max_width(800.0)
.push(Container::new(
p1_regular("For this setup you will need 2 Keys: Your Primary Key (for yourself) and an Inheritance Key (for your heir). For security reasons, we suggest you use a separate Hardware Wallet for each key.")
.style(color::GREY_2)
.horizontal_alignment(alignment::Horizontal::Left)
.color(color::GREY_2)
.align_x(alignment::Horizontal::Left)
).align_x(alignment::Horizontal::Left).width(Length::Fill))
.push(Row::new()
.spacing(30)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(icon::round_key_icon().size(H3_SIZE).style(color::GREEN))
.push(icon::round_key_icon().size(H3_SIZE).color(color::GREEN))
.push(p1_regular("Primary key").bold())
).push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(icon::round_key_icon().size(H3_SIZE).style(color::WHITE))
.push(icon::round_key_icon().size(H3_SIZE).color(color::WHITE))
.push(p1_regular("Inheritance key").bold())
))
.push(Container::new(
p1_regular("You will always be able to spend using your Primary Key.
After a period of inactivity (but not before that) your Inheritance Key will become able to recover your funds.")
.style(color::GREY_2)
.horizontal_alignment(alignment::Horizontal::Left)
.color(color::GREY_2)
.align_x(alignment::Horizontal::Left)
).align_x(alignment::Horizontal::Left).width(Length::Fill))
.push(image::inheritance_template_description().width(Length::Fill))
.push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next)))
@ -77,28 +77,28 @@ pub fn inheritance_template<'a>(
None,
"Set keys",
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.max_width(1000.0)
.push(collapse::Collapse::new(
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Advanced settings").small().bold())
.push(icon::collapse_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Advanced settings").small().bold())
.push(icon::collapsed_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || define_descriptor_advanced_settings(use_taproot),
))

View File

@ -21,13 +21,13 @@ pub fn choose_descriptor_template(progress: (usize, usize)) -> Element<'static,
"Choose wallet type",
Column::new()
.max_width(800.0)
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(
Button::new(
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(h3("Simple inheritance"))
.push(p2_regular("Two keys required, one for yourself to spend and another for your heir.").style(color::GREY_2))
.push(p2_regular("Two keys required, one for yourself to spend and another for your heir.").color(color::GREY_2))
.width(Length::Fill)
)
.padding(15)
@ -35,15 +35,15 @@ pub fn choose_descriptor_template(progress: (usize, usize)) -> Element<'static,
Message::SelectDescriptorTemplate(
context::DescriptorTemplate::SimpleInheritance,
)
).style(theme::Button::Secondary)
).style(theme::button::secondary)
.width(Length::Fill),
)
.push(
Button::new(
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(h3("Expanding multisig"))
.push(p2_regular("Two keys required to spend, with an extra key as a backup.").style(color::GREY_2))
.push(p2_regular("Two keys required to spend, with an extra key as a backup.").color(color::GREY_2))
.width(Length::Fill)
)
.padding(15)
@ -51,15 +51,15 @@ pub fn choose_descriptor_template(progress: (usize, usize)) -> Element<'static,
Message::SelectDescriptorTemplate(
context::DescriptorTemplate::MultisigSecurity,
)
).style(theme::Button::Secondary)
).style(theme::button::secondary)
.width(Length::Fill),
)
.push(
Button::new(
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(h3("Build your own"))
.push(p2_regular("Create a custom setup that fits all your needs.").style(color::GREY_2))
.push(p2_regular("Create a custom setup that fits all your needs.").color(color::GREY_2))
.width(Length::Fill)
)
.padding(15)
@ -67,7 +67,7 @@ pub fn choose_descriptor_template(progress: (usize, usize)) -> Element<'static,
Message::SelectDescriptorTemplate(
context::DescriptorTemplate::Custom,
)
).style(theme::Button::Secondary)
).style(theme::button::secondary)
.width(Length::Fill),
)
.spacing(20),

View File

@ -31,39 +31,39 @@ pub fn multisig_security_template_description(
None,
"Introduction",
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(h3("Expanding multisig wallet"))
.max_width(800.0)
.push(Container::new(
p1_regular("For this setup you will need 3 keys: two Primary Keys and a Recovery Key. For security reasons, we suggest you use a separate Hardware Wallet for each key.")
.style(color::GREY_2)
.horizontal_alignment(alignment::Horizontal::Left)
.color(color::GREY_2)
.align_x(alignment::Horizontal::Left)
).align_x(alignment::Horizontal::Left).width(Length::Fill))
.push(Row::new()
.spacing(30)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(icon::round_key_icon().size(H3_SIZE).style(color::GREEN))
.push(icon::round_key_icon().size(H3_SIZE).color(color::GREEN))
.push(p1_regular("Primary key #1").bold())
).push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(icon::round_key_icon().size(H3_SIZE).style(color::GREEN))
.push(icon::round_key_icon().size(H3_SIZE).color(color::GREEN))
.push(p1_regular("Primary key #2").bold())
).push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(icon::round_key_icon().size(H3_SIZE).style(color::ORANGE))
.push(icon::round_key_icon().size(H3_SIZE).color(color::ORANGE))
.push(p1_regular("Recovery key").bold())
))
.push(Container::new(
p1_regular("The Primary Keys will compose a 2-of-2 multisig which will always be able to spend. In case one of your keys becomes unavailable, after a period of inactivity you will be able to recover your funds using the Recovery Key together with one of your Primary Keys (2-of-3 multisig):")
.style(color::GREY_2)
.horizontal_alignment(alignment::Horizontal::Left)
.color(color::GREY_2)
.align_x(alignment::Horizontal::Left)
).align_x(alignment::Horizontal::Left).width(Length::Fill))
.push(image::multisig_security_template_description().width(Length::Fill))
.push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next)))
@ -88,28 +88,28 @@ pub fn multisig_security_template<'a>(
None,
"Set keys",
Column::new()
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.max_width(1000.0)
.push(collapse::Collapse::new(
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Advanced settings").small().bold())
.push(icon::collapse_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Advanced settings").small().bold())
.push(icon::collapsed_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || define_descriptor_advanced_settings(use_taproot),
))

View File

@ -1,7 +1,7 @@
pub mod editor;
use async_hwi::utils::extract_keys_and_template;
use iced::widget::{checkbox, radio, scrollable, scrollable::Properties, Button, Space, TextInput};
use iced::widget::{checkbox, radio, scrollable, scrollable::Scrollbar, Button, Space, TextInput};
use iced::{
alignment,
widget::{progress_bar, tooltip as iced_tooltip},
@ -60,7 +60,7 @@ pub fn import_wallet_or_descriptor<'a>(
for (i, wallet) in wallets.into_iter().enumerate() {
col_wallets = col_wallets.push(
Button::new(h5_regular(wallet).width(Length::Fill))
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.padding(10)
.on_press(Message::Select(i)),
);
@ -76,29 +76,29 @@ pub fn import_wallet_or_descriptor<'a>(
Button::new(
Column::new()
.spacing(5)
.push(h4_bold("Load a shared wallet").style(color::WHITE))
.push(h4_bold("Load a shared wallet").color(color::WHITE))
.push(
text("If you received an invitation to join a shared wallet")
.style(color::GREY_3),
.color(color::GREY_3),
),
)
.padding(15)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
|| {
Button::new(
Column::new()
.spacing(5)
.push(h4_bold("Load a shared wallet").style(color::WHITE))
.push(h4_bold("Load a shared wallet").color(color::WHITE))
.push(
text("Type the invitation token you received by email")
.style(color::GREY_3),
.color(color::GREY_3),
),
)
.padding(15)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
if let Some(wallet) = invitation_wallet {
@ -170,23 +170,23 @@ pub fn import_wallet_or_descriptor<'a>(
Button::new(
Column::new()
.spacing(5)
.push(h4_bold("Load a wallet from descriptor").style(color::WHITE))
.push(text("Creates a new wallet from the descriptor").style(color::GREY_3)),
.push(h4_bold("Load a wallet from descriptor").color(color::WHITE))
.push(text("Creates a new wallet from the descriptor").color(color::GREY_3)),
)
.padding(15)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
|| {
Button::new(
Column::new()
.spacing(5)
.push(h4_bold("Load a wallet from descriptor").style(color::WHITE))
.push(text("Creates a new wallet from the descriptor").style(color::GREY_3)),
.push(h4_bold("Load a wallet from descriptor").color(color::WHITE))
.push(text("Creates a new wallet from the descriptor").color(color::GREY_3)),
)
.padding(15)
.width(Length::Fill)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
},
move || {
Element::<'a, Message>::from(
@ -316,17 +316,17 @@ pub fn signer_xpubs<'a>(
Column::new()
.push(
Button::new(
Row::new().align_items(Alignment::Center).push(
Row::new().align_y(Alignment::Center).push(
Column::new()
.push(text("Generate a new mnemonic").bold())
.push(text(BACKUP_WARNING).small().style(color::ORANGE))
.push(text(BACKUP_WARNING).small().color(color::ORANGE))
.spacing(5)
.width(Length::Fill),
),
)
.on_press(Message::UseHotSigner)
.padding(10)
.style(theme::Button::TransparentBorder)
.style(theme::button::transparent_border)
.width(Length::Fill),
)
.push_maybe(if xpubs.is_empty() {
@ -343,7 +343,7 @@ pub fn signer_xpubs<'a>(
|acc, (i, w)| {
acc.push(
Row::new()
.align_items(Alignment::End)
.align_y(Alignment::End)
.push(
Container::new(text(format!("#{}", i + 1)).small())
.width(Length::Fixed(50.0)),
@ -374,12 +374,12 @@ pub fn signer_xpubs<'a>(
col.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(
scrollable(Container::new(text(xpub).small()).padding(10))
.direction(scrollable::Direction::Horizontal(
Properties::new().width(5).scroller_width(5),
Scrollbar::new().width(5).scroller_width(5),
)),
)
.width(Length::Fill),
@ -398,7 +398,7 @@ pub fn signer_xpubs<'a>(
None
}),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -448,7 +448,7 @@ pub fn hardware_wallet_xpubs<'a>(
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
})
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.width(Length::Fill);
if !processing && hw.is_supported() {
bttn = bttn.on_press(Message::Select(i));
@ -467,12 +467,12 @@ pub fn hardware_wallet_xpubs<'a>(
col.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(
scrollable(Container::new(text(xpub).small()).padding(10))
.direction(scrollable::Direction::Horizontal(
Properties::new().width(5).scroller_width(5),
Scrollbar::new().width(5).scroller_width(5),
)),
)
.width(Length::Fill),
@ -489,7 +489,7 @@ pub fn hardware_wallet_xpubs<'a>(
})
})),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -510,7 +510,7 @@ pub fn share_xpubs<'a>(
.width(Length::Fill),
)
.push_maybe(if hws.is_empty() {
Some(p1_regular("No signing device connected").style(color::GREY_3))
Some(p1_regular("No signing device connected").color(color::GREY_3))
} else {
None
})
@ -538,47 +538,22 @@ pub fn register_descriptor<'a>(
done: bool,
created_desc: bool,
) -> Element<'a, Message> {
let displayed_descriptor = if let Ok((template, keys)) =
extract_keys_and_template::<String>(&descriptor)
{
let mut col = Column::new()
.push(
card::simple(
Column::new()
.push(text("Descriptor template:").small().bold())
.push(
scrollable(
Column::new()
.push(text(template).small())
.push(Space::with_height(Length::Fixed(5.0))),
)
.direction(
scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
),
),
)
.spacing(10),
)
.width(Length::Fill),
)
.push(Space::with_height(5));
for (index, key) in keys.into_iter().enumerate() {
col = col
let displayed_descriptor =
if let Ok((template, keys)) = extract_keys_and_template::<String>(&descriptor) {
let mut col = Column::new()
.push(
card::simple(
Column::new()
.push(text(format!("Key @{}:", index)).small().bold())
.push(text("Descriptor template:").small().bold())
.push(
scrollable(
Column::new()
.push(text(key.to_owned()).small())
.push(text(template).small())
.push(Space::with_height(Length::Fixed(5.0))),
)
.direction(
scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
scrollable::Scrollbar::new().width(5).scroller_width(5),
),
),
)
@ -587,32 +562,56 @@ pub fn register_descriptor<'a>(
.width(Length::Fill),
)
.push(Space::with_height(5));
}
col
} else {
Column::new().push(card::simple(
Column::new()
.push(text("The descriptor:").small().bold())
.push(
scrollable(
Column::new()
.push(text(descriptor.to_owned()).small())
.push(Space::with_height(Length::Fixed(5.0))),
for (index, key) in keys.into_iter().enumerate() {
col = col
.push(
card::simple(
Column::new()
.push(text(format!("Key @{}:", index)).small().bold())
.push(
scrollable(
Column::new()
.push(text(key.to_owned()).small())
.push(Space::with_height(Length::Fixed(5.0))),
)
.direction(
scrollable::Direction::Horizontal(
scrollable::Scrollbar::new().width(5).scroller_width(5),
),
),
)
.spacing(10),
)
.width(Length::Fill),
)
.direction(scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
)),
)
.push(
Row::new().push(Column::new().width(Length::Fill)).push(
button::secondary(Some(icon::clipboard_icon()), "Copy")
.on_press(Message::Clibpboard(descriptor)),
),
)
.spacing(10),
))
};
.push(Space::with_height(5));
}
col
} else {
Column::new().push(card::simple(
Column::new()
.push(text("The descriptor:").small().bold())
.push(
scrollable(
Column::new()
.push(text(descriptor.to_owned()).small())
.push(Space::with_height(Length::Fixed(5.0))),
)
.direction(scrollable::Direction::Horizontal(
scrollable::Scrollbar::new().width(5).scroller_width(5),
)),
)
.push(
Row::new().push(Column::new().width(Length::Fill)).push(
button::secondary(Some(icon::clipboard_icon()), "Copy")
.on_press(Message::Clibpboard(descriptor)),
),
)
.spacing(10),
))
};
layout(
progress,
email,
@ -697,22 +696,22 @@ pub fn backup_descriptor<'a>(
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Learn more").small().bold())
.push(icon::collapse_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
|| {
Button::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text("Learn more").small().bold())
.push(icon::collapsed_icon()),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
help_backup,
))
@ -730,7 +729,7 @@ pub fn backup_descriptor<'a>(
)
.direction(
scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
scrollable::Scrollbar::new().width(5).scroller_width(5),
),
),
)
@ -803,7 +802,7 @@ fn display_policy(
text(k.to_string()),
iced_tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(format!("[{}]", k)).bold())
@ -850,7 +849,7 @@ fn display_policy(
text(k.to_string()),
iced_tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
} else {
Container::new(text(format!("[{}]", k)).bold())
@ -880,7 +879,7 @@ fn display_policy(
.spacing(10)
.push(text("The wallet policy:").bold())
.push(scrollable(col).direction(scrollable::Direction::Horizontal(
scrollable::Properties::new().width(5).scroller_width(5),
scrollable::Scrollbar::new().width(5).scroller_width(5),
)))
.into()
}
@ -957,7 +956,7 @@ pub fn define_bitcoin_node<'a>(
},
))
.spacing(30)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
},
),
)
@ -966,7 +965,7 @@ pub fn define_bitcoin_node<'a>(
Some(Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text("Checking connection...")),
))
} else if is_running.is_some() {
@ -975,17 +974,17 @@ pub fn define_bitcoin_node<'a>(
Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Connection checked").style(color::GREEN)),
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Connection checked").color(color::GREEN)),
)
} else {
Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon().style(color::RED))
.push(text("Connection failed").style(color::RED)),
.align_y(Alignment::Center)
.push(icon::circle_cross_icon().color(color::RED))
.push(text("Connection failed").color(color::RED)),
)
}
})
@ -1059,7 +1058,7 @@ pub fn define_bitcoind<'a>(
is not supported. Insert an IP address bound to the same machine \
running Liana (ignore this warning if that's already the case)",
)
.style(color::ORANGE)
.color(color::ORANGE)
.size(text::CAPTION_SIZE),
)
} else {
@ -1087,7 +1086,7 @@ pub fn define_bitcoind<'a>(
},
))
.spacing(30)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
},
),
)
@ -1164,7 +1163,7 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message
Column::new()
.push(
Row::new()
.align_items(Alignment::Start)
.align_y(Alignment::Start)
.spacing(20)
.push(
Container::new(
@ -1190,14 +1189,14 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message
)
.push(
Row::new()
.align_items(Alignment::Start)
.align_y(Alignment::Start)
.spacing(20)
.push(
Container::new(
Column::new()
.spacing(20)
.width(Length::Fixed(300.0))
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(text(
"Select this option if you already have \
a Bitcoin node running locally or remotely. \
@ -1211,7 +1210,7 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message
Column::new()
.spacing(20)
.width(Length::Fixed(300.0))
.align_items(Alignment::Start)
.align_x(Alignment::Start)
.push(text(
"Liana will install a pruned node \
on your computer. You won't need to do anything \
@ -1227,14 +1226,14 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message
)
.push(
Row::new()
.align_items(Alignment::End)
.align_y(Alignment::End)
.spacing(20)
.push(
Container::new(
Column::new()
.spacing(20)
.width(Length::Fixed(300.0))
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(
button::secondary(None, "Select")
.width(Length::Fixed(300.0))
@ -1250,7 +1249,7 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message
Column::new()
.spacing(20)
.width(Length::Fixed(300.0))
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(
button::secondary(None, "Select")
.width(Length::Fixed(300.0))
@ -1285,53 +1284,53 @@ pub fn start_internal_bitcoind<'a>(
match s {
DownloadState::Finished(_) => Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Download complete").style(color::GREEN)),
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Download complete").color(color::GREEN)),
DownloadState::Downloading { progress } => Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text(format!(
"Downloading Bitcoin Core {version}... {progress:.2}%"
))),
DownloadState::Errored(e) => Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon().style(color::RED))
.push(text(format!("Download failed: '{}'.", e)).style(color::RED)),
_ => Row::new().spacing(10).align_items(Alignment::Center),
.align_y(Alignment::Center)
.push(icon::circle_cross_icon().color(color::RED))
.push(text(format!("Download failed: '{}'.", e)).color(color::RED)),
_ => Row::new().spacing(10).align_y(Alignment::Center),
}
}))
.push(Container::new(if let Some(state) = install_state {
match state {
InstallState::InProgress => Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push("Installing bitcoind..."),
InstallState::Finished => Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Installation complete").style(color::GREEN)),
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Installation complete").color(color::GREEN)),
InstallState::Errored(e) => Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon().style(color::RED))
.push(text(format!("Installation failed: '{}'.", e)).style(color::RED)),
.align_y(Alignment::Center)
.push(icon::circle_cross_icon().color(color::RED))
.push(text(format!("Installation failed: '{}'.", e)).color(color::RED)),
}
} else if exe_path.is_some() {
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Liana-managed bitcoind already installed").style(color::GREEN))
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Liana-managed bitcoind already installed").color(color::GREEN))
} else if let Some(DownloadState::Downloading { progress }) = download_state {
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(progress_bar(0.0..=100.0, *progress))
} else {
Row::new().spacing(10).align_items(Alignment::Center)
Row::new().spacing(10).align_y(Alignment::Center)
}))
.push_maybe(if started.is_some() {
started.map(|res| {
@ -1339,18 +1338,18 @@ pub fn start_internal_bitcoind<'a>(
Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Started").style(color::GREEN)),
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Started").color(color::GREEN)),
)
} else {
Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon().style(color::RED))
.align_y(Alignment::Center)
.push(icon::circle_cross_icon().color(color::RED))
.push(
text(res.as_ref().err().unwrap().to_string()).style(color::RED),
text(res.as_ref().err().unwrap().to_string()).color(color::RED),
),
)
}
@ -1361,7 +1360,7 @@ pub fn start_internal_bitcoind<'a>(
(Some(InstallState::Finished), _) | (None, Some(_)) => Some(Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text("Starting...")),
)),
_ => Some(Container::new(Space::with_height(Length::Fixed(25.0)))),
@ -1411,9 +1410,9 @@ pub fn install<'a>(
Container::new(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Installed").style(color::GREEN)),
.align_y(Alignment::Center)
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Installed").color(color::GREEN)),
)
} else {
Container::new(Space::with_height(Length::Fixed(25.0)))
@ -1436,7 +1435,7 @@ pub fn defined_threshold<'a>(
.spacing(10)
.push((0..threshold.1).fold(Row::new(), |row, i| {
if i < threshold.0 {
row.push(icon::round_key_icon().style(color))
row.push(icon::round_key_icon().color(color))
} else {
row.push(icon::round_key_icon())
}
@ -1451,7 +1450,7 @@ pub fn defined_threshold<'a>(
)
.padding(10)
.on_press(message::DefinePath::EditThreshold)
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.into()
} else {
card::simple(
@ -1459,7 +1458,7 @@ pub fn defined_threshold<'a>(
.spacing(10)
.push((0..threshold.1).fold(Row::new(), |row, i| {
if i < threshold.0 {
row.push(icon::round_key_icon().style(color))
row.push(icon::round_key_icon().color(color))
} else {
row.push(icon::round_key_icon())
}
@ -1485,21 +1484,21 @@ pub fn defined_sequence<'a>(
Column::new()
.spacing(5)
.push(if sequence != 0 {
Row::new().align_items(Alignment::Center).push(
Row::new().align_y(Alignment::Center).push(
Container::new(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(5)
.push(
text::p1_regular("Available after inactivity of ~")
.style(color::GREY_2),
.color(color::GREY_2),
)
.push(
Button::new(
Row::new()
.padding(5)
.spacing(5)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(text(
[
(n_years, "y"),
@ -1521,7 +1520,7 @@ pub fn defined_sequence<'a>(
))
.push(icon::pencil_icon()),
)
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.on_press(message::DefinePath::EditSequence),
),
)
@ -1531,14 +1530,14 @@ pub fn defined_sequence<'a>(
)
} else {
Row::new()
.push(p1_regular("Able to move the funds at any time.").style(color::GREY_2))
.push(p1_regular("Able to move the funds at any time.").color(color::GREY_2))
.padding(5)
})
.push_maybe(if duplicate_sequence {
Some(
text("No two recovery options may become available at the very same date.")
.small()
.style(color::RED),
.color(color::RED),
)
} else {
None
@ -1614,14 +1613,14 @@ pub fn hw_list_view(
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
})
.style(theme::Button::Border)
.style(theme::button::container_border)
.width(Length::Fill);
if !processing && hw.is_supported() {
bttn = bttn.on_press(Message::Select(i));
}
Container::new(bttn)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -1666,14 +1665,14 @@ pub fn key_list_view<'a>(
Some(name),
)
})
.style(theme::Button::Border)
.style(theme::button::secondary)
.width(Length::Fill)
.on_press(Message::DefineDescriptor(
message::DefineDescriptor::KeyModal(message::ImportKeyModal::SelectKey(i)),
));
Container::new(bttn)
.width(Length::Fill)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()
}
@ -1696,7 +1695,7 @@ pub fn backup_mnemonic<'a>(
.fold(Column::new().spacing(5), |acc, (i, w)| {
acc.push(
Row::new()
.align_items(Alignment::End)
.align_y(Alignment::End)
.push(
Container::new(text(format!("#{}", i + 1)).small())
.width(Length::Fixed(50.0)),
@ -1738,13 +1737,13 @@ pub fn recover_mnemonic<'a>(
.push_maybe(if recover {
Some(
Column::new()
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(
Container::new(if !suggestions.is_empty() {
suggestions.iter().fold(Row::new().spacing(5), |row, sugg| {
row.push(
Button::new(text(sugg))
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.on_press(Message::MnemonicWord(
current,
sugg.to_string(),
@ -1763,7 +1762,7 @@ pub fn recover_mnemonic<'a>(
acc.push(
Row::new()
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
Container::new(text(format!("#{}", i + 1)).small())
.width(Length::Fixed(50.0)),
@ -1775,7 +1774,7 @@ pub fn recover_mnemonic<'a>(
.width(Length::Fixed(100.0)),
)
.push_maybe(if *valid {
Some(icon::circle_check_icon().style(color::GREEN))
Some(icon::circle_check_icon().color(color::GREEN))
} else {
None
}),
@ -1783,7 +1782,7 @@ pub fn recover_mnemonic<'a>(
},
))
.push(Space::with_height(Length::Fixed(50.0)))
.push_maybe(error.map(|e| card::invalid(text(e).style(color::RED)))),
.push_maybe(error.map(|e| card::invalid(text(e).color(color::RED)))),
)
} else {
None
@ -1839,14 +1838,14 @@ pub fn choose_backend(progress: (usize, usize)) -> Element<'static, Message> {
.spacing(20)
.width(Length::FillPortion(1))
.push(h3("Use your own node"))
.push(text::p2_medium(LOCAL_WALLET_DESC).style(color::GREY_3)),
.push(text::p2_medium(LOCAL_WALLET_DESC).color(color::GREY_3)),
)
.push(
Column::new()
.spacing(20)
.width(Length::FillPortion(1))
.push(h3("Use Liana Connect"))
.push(text::p2_medium(REMOTE_BACKEND_DESC).style(color::GREY_3)),
.push(text::p2_medium(REMOTE_BACKEND_DESC).color(color::GREY_3)),
),
)
.push(
@ -1888,13 +1887,12 @@ pub fn login(progress: (usize, usize), connection_step: Element<Message>) -> Ele
Column::new()
.spacing(50)
.max_width(700)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.width(Length::FillPortion(1))
.push(h2("Liana Connect"))
.push(connection_step),
)
.width(Length::Fill)
.center_x(),
.center_x(Length::Fill),
true,
Some(Message::Previous),
)
@ -1908,8 +1906,8 @@ pub fn connection_step_enter_email<'a>(
) -> Element<'a, Message> {
Column::new()
.spacing(20)
.push_maybe(connection_error.map(|e| text(e.to_string()).style(color::ORANGE)))
.push_maybe(auth_error.map(|e| text(e.to_string()).style(color::ORANGE)))
.push_maybe(connection_error.map(|e| text(e.to_string()).color(color::ORANGE)))
.push_maybe(auth_error.map(|e| text(e.to_string()).color(color::ORANGE)))
.push(text(
"Enter the email you want to associate with the wallet:",
))
@ -1942,10 +1940,10 @@ pub fn connection_step_enter_otp<'a>(
) -> Element<'a, Message> {
Column::new()
.spacing(20)
.push(text(email).style(color::GREEN))
.push(text(email).color(color::GREEN))
.push(text("An authentication token has been emailed to you"))
.push_maybe(connection_error.map(|e| text(e.to_string()).style(color::ORANGE)))
.push_maybe(auth_error.map(|e| text(e.to_string()).style(color::ORANGE)))
.push_maybe(connection_error.map(|e| text(e.to_string()).color(color::ORANGE)))
.push_maybe(auth_error.map(|e| text(e.to_string()).color(color::ORANGE)))
.push(
form::Form::new_trimmed("Token", otp, |msg| {
Message::SelectBackend(message::SelectBackend::OTPEdited(msg))
@ -1980,9 +1978,9 @@ pub fn connection_step_connected<'a>(
) -> Element<'a, Message> {
Column::new()
.spacing(20)
.push(text(email).style(color::GREEN))
.push_maybe(connection_error.map(|e| text(e.to_string()).style(color::ORANGE)))
.push_maybe(auth_error.map(|e| text(e.to_string()).style(color::ORANGE)))
.push(text(email).color(color::GREEN))
.push_maybe(connection_error.map(|e| text(e.to_string()).color(color::ORANGE)))
.push_maybe(auth_error.map(|e| text(e.to_string()).color(color::ORANGE)))
.push(Container::new(
Row::new()
.spacing(10)
@ -2021,23 +2019,18 @@ fn layout<'a>(
Column::new()
.width(Length::Fill)
.push(Row::new().push(Space::with_width(Length::Fill)).push_maybe(
email.map(|e| Container::new(p1_regular(e).style(color::GREEN)).padding(20)),
email.map(|e| Container::new(p1_regular(e).color(color::GREEN)).padding(20)),
))
.push(Space::with_height(Length::Fixed(100.0)))
.push(
Row::new()
.align_items(Alignment::Center)
.push(
Container::new(prev_button)
.width(Length::FillPortion(2))
.center_x(),
)
.align_y(Alignment::Center)
.push(Container::new(prev_button).center_x(Length::FillPortion(2)))
.push(Container::new(h3(title)).width(Length::FillPortion(8)))
.push_maybe(if progress.1 > 0 {
Some(
Container::new(text(format!("{} | {}", progress.0, progress.1)))
.width(Length::FillPortion(2))
.center_x(),
.center_x(Length::FillPortion(2)),
)
} else {
None
@ -2065,9 +2058,9 @@ fn layout<'a>(
}),
),
))
.center_x()
.center_x(Length::Fill)
.height(Length::Fill)
.width(Length::Fill)
.style(theme::Container::Background)
.style(theme::container::background)
.into()
}

View File

@ -3,7 +3,7 @@ use std::path::PathBuf;
use iced::{
alignment::Horizontal,
widget::{pick_list, scrollable, Button, Space},
Alignment, Command, Length, Subscription,
Alignment, Length, Subscription, Task,
};
use liana::miniscript::bitcoin::Network;
@ -44,7 +44,7 @@ pub struct Launcher {
}
impl Launcher {
pub fn new(datadir_path: PathBuf, network: Option<Network>) -> (Self, Command<Message>) {
pub fn new(datadir_path: PathBuf, network: Option<Network>) -> (Self, Task<Message>) {
let network = network.unwrap_or(
NETWORKS
.iter()
@ -60,7 +60,7 @@ impl Launcher {
error: None,
delete_wallet_modal: None,
},
Command::perform(
Task::perform(
check_network_datadir(datadir_path.clone(), network),
Message::Checked,
),
@ -73,26 +73,26 @@ impl Launcher {
Subscription::none()
}
pub fn update(&mut self, message: Message) -> Command<Message> {
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::View(ViewMessage::ImportWallet) => {
let datadir_path = self.datadir_path.clone();
let network = self.network;
Command::perform(async move { (datadir_path, network) }, |(d, n)| {
Task::perform(async move { (datadir_path, network) }, |(d, n)| {
Message::Install(d, n, UserFlow::AddWallet)
})
}
Message::View(ViewMessage::CreateWallet) => {
let datadir_path = self.datadir_path.clone();
let network = self.network;
Command::perform(async move { (datadir_path, network) }, |(d, n)| {
Task::perform(async move { (datadir_path, network) }, |(d, n)| {
Message::Install(d, n, UserFlow::CreateWallet)
})
}
Message::View(ViewMessage::ShareXpubs) => {
let datadir_path = self.datadir_path.clone();
let network = self.network;
Command::perform(async move { (datadir_path, network) }, |(d, n)| {
Task::perform(async move { (datadir_path, network) }, |(d, n)| {
Message::Install(d, n, UserFlow::ShareXpubs)
})
}
@ -109,31 +109,31 @@ impl Launcher {
wallet_datadir,
internal_bitcoind,
));
Command::none()
Task::none()
}
Message::View(ViewMessage::SelectNetwork(network)) => {
self.network = network;
Command::perform(
Task::perform(
check_network_datadir(self.datadir_path.clone(), self.network),
Message::Checked,
)
}
Message::View(ViewMessage::DeleteWallet(DeleteWalletMessage::Deleted)) => {
self.state = State::NoWallet;
Command::none()
Task::none()
}
Message::View(ViewMessage::DeleteWallet(DeleteWalletMessage::CloseModal)) => {
self.delete_wallet_modal = None;
Command::none()
Task::none()
}
Message::Checked(res) => match res {
Err(e) => {
self.error = Some(e);
Command::none()
Task::none()
}
Ok(state) => {
self.state = state;
Command::none()
Task::none()
}
},
Message::View(ViewMessage::Run) => {
@ -144,18 +144,18 @@ impl Launcher {
path.push(app::config::DEFAULT_FILE_NAME);
let cfg = app::Config::from_file(&path).expect("Already checked");
let network = self.network;
Command::perform(async move { (datadir_path.clone(), cfg, network) }, |m| {
Task::perform(async move { (datadir_path.clone(), cfg, network) }, |m| {
Message::Run(m.0, m.1, m.2)
})
} else {
Command::none()
Task::none()
}
}
_ => {
if let Some(modal) = &mut self.delete_wallet_modal {
return modal.update(message);
}
Command::none()
Task::none()
}
}
}
@ -180,16 +180,16 @@ impl Launcher {
Some(self.network),
ViewMessage::SelectNetwork,
)
.style(theme::PickList::default())
.style(theme::pick_list::primary)
.padding(10),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(100),
)
.push(
Container::new(
Column::new()
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.spacing(30)
.push(if matches!(self.state, State::Wallet { .. }) {
text("Welcome back").size(50).bold()
@ -203,7 +203,7 @@ impl Launcher {
email, checksum, ..
} => Column::new().push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(20)
.push(
Button::new(
@ -220,25 +220,25 @@ impl Launcher {
)))
.push_maybe(checksum.as_ref().map(|checksum| {
p1_regular(format!("Liana-{}", checksum))
.style(color::GREY_3)
.color(color::GREY_3)
}))
.push_maybe(email.as_ref().map(|email| {
Row::new()
.push(Space::with_width(Length::Fill))
.push(
p1_regular(email)
.style(color::GREEN),
.color(color::GREEN),
)
})),
)
.on_press(ViewMessage::Run)
.style(theme::Button::Border)
.style(theme::button::container_border)
.padding(10)
.width(Length::Fill),
)
.push(
Button::new(icon::trash_icon())
.style(theme::Button::Secondary)
.style(theme::button::secondary)
.padding(10)
.on_press(ViewMessage::DeleteWallet(
DeleteWalletMessage::ShowModal,
@ -248,20 +248,20 @@ impl Launcher {
State::NoWallet => Column::new()
.push(
Row::new()
.align_items(Alignment::End)
.align_y(Alignment::End)
.spacing(20)
.push(
Container::new(
Column::new()
.spacing(20)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(
image::create_new_wallet_icon()
.width(Length::Fixed(100.0)),
)
.push(
p1_regular("Create a new Liana wallet")
.style(color::GREY_3),
.color(color::GREY_3),
)
.push(
button::secondary(None, "Select")
@ -270,7 +270,7 @@ impl Launcher {
ViewMessage::CreateWallet,
),
)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
)
.padding(20),
)
@ -278,7 +278,7 @@ impl Launcher {
Container::new(
Column::new()
.spacing(20)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(
image::restore_wallet_icon()
.width(Length::Fixed(100.0)),
@ -287,7 +287,7 @@ impl Launcher {
p1_regular(
"Add an existing Liana wallet",
)
.style(color::GREY_3),
.color(color::GREY_3),
)
.push(
button::secondary(None, "Select")
@ -296,17 +296,16 @@ impl Launcher {
ViewMessage::ImportWallet,
),
)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
)
.padding(20),
),
)
.align_items(Alignment::Center),
.align_x(Alignment::Center),
})
.max_width(500),
)
.width(Length::Fill)
.center_x(),
.center_x(Length::Fill),
)
.push(Space::with_height(Length::Fixed(100.0))),
))
@ -376,24 +375,24 @@ impl DeleteWalletModal {
}
}
fn update(&mut self, message: Message) -> Command<Message> {
fn update(&mut self, message: Message) -> Task<Message> {
if let Message::View(ViewMessage::DeleteWallet(DeleteWalletMessage::Confirm)) = message {
self.warning = None;
if let Err(e) = std::fs::remove_dir_all(&self.wallet_datadir) {
self.warning = Some(e);
} else {
self.deleted = true;
return Command::perform(async {}, |_| {
return Task::perform(async {}, |_| {
Message::View(ViewMessage::DeleteWallet(DeleteWalletMessage::Deleted))
});
};
}
Command::none()
Task::none()
}
fn view(&self) -> Element<Message> {
let mut confirm_button = button::secondary(None, "Delete wallet")
.width(Length::Fixed(200.0))
.style(theme::Button::Destructive);
.style(theme::button::destructive);
if self.warning.is_none() {
confirm_button =
confirm_button.on_press(ViewMessage::DeleteWallet(DeleteWalletMessage::Confirm));
@ -416,12 +415,12 @@ impl DeleteWalletModal {
.spacing(10)
.push(Container::new(
h4_bold(format!("Delete configuration for {}", &self.network))
.style(color::RED)
.color(color::RED)
.width(Length::Fill),
))
.push(Row::new().push(text(help_text_1)))
.push_maybe(
help_text_2.map(|t| Row::new().push(p1_regular(t).style(color::GREY_3))),
help_text_2.map(|t| Row::new().push(p1_regular(t).color(color::GREY_3))),
)
.push(Row::new())
.push(Row::new().push(text(help_text_3)))
@ -434,8 +433,8 @@ impl DeleteWalletModal {
} else {
Row::new()
.spacing(10)
.push(icon::circle_check_icon().style(color::GREEN))
.push(text("Wallet successfully deleted").style(color::GREEN))
.push(icon::circle_check_icon().color(color::GREEN))
.push(text("Wallet successfully deleted").color(color::GREEN))
})
.align_x(Horizontal::Center)
.width(Length::Fill),

View File

@ -1,6 +1,6 @@
use std::{path::PathBuf, sync::Arc};
use iced::{Alignment, Command, Length};
use iced::{Alignment, Length, Task};
use liana::miniscript::bitcoin::Network;
use liana_ui::{
@ -116,7 +116,7 @@ pub enum ConnectionStep {
}
impl LianaLiteLogin {
pub fn new(datadir: PathBuf, network: Network, settings: Settings) -> (Self, Command<Message>) {
pub fn new(datadir: PathBuf, network: Network, settings: Settings) -> (Self, Task<Message>) {
match settings
.wallets
.first()
@ -137,7 +137,7 @@ impl LianaLiteLogin {
auth_error: None,
processing: true,
},
Command::none(),
Task::none(),
),
Ok(auth_config) => (
Self {
@ -149,7 +149,7 @@ impl LianaLiteLogin {
auth_error: None,
processing: true,
},
Command::perform(
Task::perform(
async move {
let service_config = super::client::get_service_config(network)
.await
@ -174,7 +174,7 @@ impl LianaLiteLogin {
}
}
pub fn update(&mut self, message: Message) -> Command<Message> {
pub fn update(&mut self, message: Message) -> Task<Message> {
match &mut self.step {
ConnectionStep::CheckingAuthFile => {
if let Message::Connected(res) = message {
@ -184,7 +184,7 @@ impl LianaLiteLogin {
self.auth_error = Some("No wallet found for the given email");
}
Ok(BackendState::WalletExists(client, wallet)) => {
return Command::perform(async move { (client, wallet) }, |(c, w)| {
return Task::perform(async move { (client, wallet) }, |(c, w)| {
Message::Run(Ok((c, w)))
});
}
@ -216,7 +216,7 @@ impl LianaLiteLogin {
self.processing = true;
self.connection_error = None;
self.auth_error = None;
return Command::perform(
return Task::perform(
async move {
let config = super::client::get_service_config(network)
.await
@ -279,7 +279,7 @@ impl LianaLiteLogin {
self.processing = true;
self.connection_error = None;
self.auth_error = None;
return Command::perform(
return Task::perform(
async move {
client.resend_otp().await?;
Ok(())
@ -309,7 +309,7 @@ impl LianaLiteLogin {
self.auth_error = None;
let wallet_id = self.wallet_id.clone();
let network = self.network;
return Command::perform(
return Task::perform(
async move {
connect(client, otp, wallet_id, backend_api_url, network).await
},
@ -322,12 +322,12 @@ impl LianaLiteLogin {
self.processing = false;
match res {
Ok(BackendState::NoWallet(client)) => {
return Command::perform(async move { Some(client) }, Message::Install);
return Task::perform(async move { Some(client) }, Message::Install);
}
Ok(BackendState::WalletExists(client, wallet)) => {
let datadir = self.datadir.clone();
let network = self.network;
return Command::perform(
return Task::perform(
async move {
update_wallet_auth_settings(
datadir,
@ -366,7 +366,7 @@ impl LianaLiteLogin {
},
}
Command::none()
Task::none()
}
pub fn view(&self) -> Element<Message> {
@ -374,10 +374,10 @@ impl LianaLiteLogin {
Container::new(
Column::new()
.spacing(100)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(
Column::new()
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.spacing(20)
.width(Length::Fill)
.push(h2("Liana Connect"))
@ -391,7 +391,7 @@ impl LianaLiteLogin {
.spacing(20)
.push_maybe(
self.auth_error
.map(|e| text(e).style(color::ORANGE)),
.map(|e| text(e).color(color::ORANGE)),
)
.push(
form::Form::new_trimmed("email", email, |msg| {
@ -412,7 +412,7 @@ impl LianaLiteLogin {
.push(text("An authentication was send to your email"))
.push_maybe(
self.auth_error
.map(|e| text(e).style(color::ORANGE)),
.map(|e| text(e).color(color::ORANGE)),
)
.spacing(20)
.push(
@ -456,10 +456,8 @@ impl LianaLiteLogin {
}),
)
.padding(50)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y(),
.center_x(Length::Fill)
.center_y(Length::Fill),
)
.map(Message::View);

View File

@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
use iced::{Alignment, Command, Length, Subscription};
use iced::{Alignment, Length, Subscription, Task};
use tokio::runtime::Handle;
use tracing::{debug, info, warn};
@ -99,7 +99,7 @@ impl Loader {
gui_config: GUIConfig,
network: bitcoin::Network,
internal_bitcoind: Option<Bitcoind>,
) -> (Self, Command<Message>) {
) -> (Self, Task<Message>) {
let path = gui_config
.daemon_rpc_path
.clone()
@ -114,7 +114,7 @@ impl Loader {
internal_bitcoind,
waiting_daemon_bitcoind: false,
},
Command::perform(connect(path), Message::Loaded),
Task::perform(connect(path), Message::Loaded),
)
}
@ -122,11 +122,11 @@ impl Loader {
&mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
info: GetInfoResult,
) -> Command<Message> {
) -> Task<Message> {
// If the wallet was previously synced (blockheight > 0), load the
// application directly.
if info.block_height > 0 {
return Command::perform(
return Task::perform(
load_application(
daemon,
info,
@ -143,13 +143,13 @@ impl Loader {
progress: 0.0,
bitcoind_logs: String::new(),
};
Command::perform(sync(daemon, false), Message::Syncing)
Task::perform(sync(daemon, false), Message::Syncing)
}
fn on_load(
&mut self,
res: Result<(Arc<dyn Daemon + Sync + Send>, GetInfoResult), Error>,
) -> Command<Message> {
) -> Task<Message> {
match res {
Ok((daemon, info)) => {
if self.gui_config.start_internal_bitcoind {
@ -168,7 +168,7 @@ impl Loader {
self.step = Step::StartingDaemon;
self.daemon_started = true;
self.waiting_daemon_bitcoind = true;
return Command::perform(
return Task::perform(
start_bitcoind_and_daemon(
daemon_config_path,
self.datadir_path.clone(),
@ -186,19 +186,19 @@ impl Loader {
}
},
}
Command::none()
Task::none()
}
fn on_log(&mut self, log: Option<String>) -> Command<Message> {
fn on_log(&mut self, log: Option<String>) -> Task<Message> {
if let Step::Syncing { bitcoind_logs, .. } = &mut self.step {
if let Some(l) = log {
*bitcoind_logs = l;
}
}
Command::none()
Task::none()
}
fn on_start(&mut self, res: StartedResult) -> Command<Message> {
fn on_start(&mut self, res: StartedResult) -> Task<Message> {
match res {
Ok((daemon, bitcoind, info)) => {
// bitcoind may have been already started and given to the loader
@ -211,12 +211,12 @@ impl Loader {
}
Err(e) => {
self.step = Step::Error(Box::new(e));
Command::none()
Task::none()
}
}
}
fn on_sync(&mut self, res: Result<GetInfoResult, DaemonError>) -> Command<Message> {
fn on_sync(&mut self, res: Result<GetInfoResult, DaemonError>) -> Task<Message> {
match &mut self.step {
Step::Syncing {
daemon, progress, ..
@ -224,7 +224,7 @@ impl Loader {
match res {
Ok(info) => {
if (info.sync - 1.0_f64).abs() < f64::EPSILON {
return Command::perform(
return Task::perform(
load_application(
daemon.clone(),
info,
@ -240,12 +240,12 @@ impl Loader {
}
Err(e) => {
self.step = Step::Error(Box::new(e.into()));
return Command::none();
return Task::none();
}
};
Command::perform(sync(daemon.clone(), true), Message::Syncing)
Task::perform(sync(daemon.clone(), true), Message::Syncing)
}
_ => Command::none(),
_ => Task::none(),
}
}
@ -281,7 +281,7 @@ impl Loader {
}
}
pub fn update(&mut self, message: Message) -> Command<Message> {
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::View(ViewMessage::Retry) => {
let (loader, cmd) = Self::new(
@ -299,21 +299,21 @@ impl Loader {
Message::BitcoindLog(log) => self.on_log(log),
Message::Synced(Err(e)) => {
self.step = Step::Error(Box::new(e));
Command::none()
Task::none()
}
Message::Failure(_) => {
self.daemon_started = false;
Command::none()
Task::none()
}
Message::None => Command::none(),
_ => Command::none(),
Message::None => Task::none(),
_ => Task::none(),
}
}
pub fn subscription(&self) -> Subscription<Message> {
if self.internal_bitcoind.is_some() {
let log_path = internal_bitcoind_debug_log_path(&self.datadir_path, self.network);
iced::subscription::unfold(0, log_path, move |log_path| async move {
iced::Subscription::unfold(0, log_path, move |log_path| async move {
// Reduce the io load.
tokio::time::sleep(Duration::from_millis(500)).await;
@ -456,14 +456,14 @@ pub fn view(step: &Step) -> Element<ViewMessage> {
} else {
SYNCING_PROGRESS_1
}))
.push(p2_regular(bitcoind_logs).style(color::GREY_3)),
.push(p2_regular(bitcoind_logs).color(color::GREY_3)),
),
Step::Error(error) => cover(
Some(("Error while starting the internal daemon", error)),
Column::new()
.spacing(20)
.width(Length::Fill)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.push(icon::plug_icon().size(100).width(Length::Fixed(300.0)))
.push(
if matches!(
@ -500,10 +500,8 @@ pub fn cover<'a, T: 'a + Clone, C: Into<Element<'a, T>>>(
.push_maybe(warn.map(|w| notification::warning(w.0.to_string(), w.1.to_string())))
.push(
Container::new(content)
.width(iced::Length::Fill)
.height(iced::Length::Fill)
.center_x()
.center_y()
.center_x(iced::Length::Fill)
.center_y(iced::Length::Fill)
.padding(50),
)
.into()

View File

@ -10,7 +10,7 @@ use iced::{
event::{self, Event},
executor, keyboard,
widget::{focus_next, focus_previous},
Application, Command, Settings, Size, Subscription,
Application, Settings, Size, Subscription, Task,
};
use tracing::{error, info};
use tracing_subscriber::filter::LevelFilter;
@ -152,10 +152,10 @@ impl Application for GUI {
}
}
fn new((config, log_level): (Config, Option<LevelFilter>)) -> (GUI, Command<Self::Message>) {
fn new((config, log_level): (Config, Option<LevelFilter>)) -> (GUI, Task<Self::Message>) {
let logger = Logger::setup(log_level.unwrap_or(LevelFilter::INFO));
let mut cmds = font::loads();
cmds.push(Command::perform(ctrl_c(), |_| Message::CtrlC));
cmds.push(Task::perform(ctrl_c(), |_| Message::CtrlC));
let state = match config {
Config::Launcher(datadir_path) => {
let (launcher, command) = Launcher::new(datadir_path, None);
@ -179,11 +179,11 @@ impl Application for GUI {
logger,
log_level,
},
Command::batch(cmds),
Task::batch(cmds),
)
}
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
match (&mut self.state, message) {
(_, Message::CtrlC)
| (_, Message::Event(iced::Event::Window(_, iced::window::Event::CloseRequested))) => {
@ -374,7 +374,7 @@ impl Application for GUI {
(State::App(i), Message::Run(msg)) => {
i.update(*msg).map(|msg| Message::Run(Box::new(msg)))
}
_ => Command::none(),
_ => Task::none(),
}
}
@ -433,7 +433,7 @@ pub fn create_app_with_remote_backend(
datadir: PathBuf,
network: bitcoin::Network,
config: app::Config,
) -> (app::App, iced::Command<app::Message>) {
) -> (app::App, iced::Task<app::Message>) {
let hws: Vec<HardwareWalletConfig> = wallet
.metadata
.ledger_hmacs

View File

@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
iced = { version = "0.12.1", default-features = false, features = ["svg", "image", "lazy", "qr_code", "advanced", "webgl"] }
iced = { version = "0.13.1", default-features = false, features = ["svg", "image", "lazy", "qr_code", "advanced"] }
bitcoin = "0.32"
chrono = "0.4"

View File

@ -102,18 +102,18 @@ fn render_amount<'a, T: 'a>(
let mut child_after = text(after).size(size).bold();
if let Some(color_after) = color_after {
child_after = child_after.style(color_after);
child_after = child_after.color(color_after);
}
let row = Row::new()
.push(text(before).size(size).style(color_before))
.push(text(before).size(size).color(color_before))
.push(child_after);
Row::with_children(vec![
row.into(),
text("BTC").size(size).style(color_before).into(),
text("BTC").size(size).color(color_before).into(),
])
.spacing(spacing)
.align_items(iced::Alignment::Center)
.align_y(iced::Alignment::Center)
}
// Build the rendering elements for displaying a Bitcoin amount.
@ -121,11 +121,11 @@ fn render_unconfirmed_amount<'a, T: 'a>(amount: String, size: u16) -> Row<'a, T>
let spacing = if size > P1_SIZE { 10 } else { 5 };
Row::with_children(vec![
text(amount).size(size).style(color::GREY_3).into(),
text("BTC").size(size).style(color::GREY_3).into(),
text(amount).size(size).color(color::GREY_3).into(),
text("BTC").size(size).color(color::GREY_3).into(),
])
.spacing(spacing)
.align_items(iced::Alignment::Center)
.align_y(iced::Alignment::Center)
}
#[cfg(test)]

View File

@ -2,63 +2,33 @@ use iced::{widget::tooltip, Length};
use crate::{component::text, icon, image, theme, widget::*};
pub struct Badge {
icon: crate::widget::Text<'static>,
style: theme::Badge,
}
impl Badge {
pub fn new(icon: crate::widget::Text<'static>) -> Self {
Self {
icon,
style: theme::Badge::Standard,
}
}
pub fn style(self, style: theme::Badge) -> 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::Fixed(20.0)))
.width(Length::Fixed(40.0))
.height(Length::Fixed(40.0))
.style(theme::Container::Badge(badge.style))
.center_x()
.center_y()
.into()
}
pub fn badge<T>(icon: crate::widget::Text<'static>) -> Container<'static, T> {
Container::new(icon.width(Length::Fixed(20.0)))
.style(theme::badge::simple)
.center_x(Length::Fixed(40.0))
.center_y(Length::Fixed(40.0))
}
pub fn receive<T>() -> Container<'static, T> {
Container::new(icon::receive_icon().width(Length::Fixed(20.0)))
.width(Length::Fixed(40.0))
.height(Length::Fixed(40.0))
.style(theme::Container::Badge(theme::Badge::Standard))
.center_x()
.center_y()
.style(theme::badge::simple)
.style(theme::badge::simple)
.center_x(Length::Fixed(40.0))
.center_y(Length::Fixed(40.0))
}
pub fn cycle<T>() -> Container<'static, T> {
Container::new(icon::arrow_repeat().width(Length::Fixed(20.0)))
.width(Length::Fixed(40.0))
.height(Length::Fixed(40.0))
.style(theme::Container::Badge(theme::Badge::Standard))
.center_x()
.center_y()
.style(theme::badge::simple)
.center_x(Length::Fixed(40.0))
.center_y(Length::Fixed(40.0))
}
pub fn spend<T>() -> Container<'static, T> {
Container::new(icon::send_icon().width(Length::Fixed(20.0)))
.width(Length::Fixed(40.0))
.height(Length::Fixed(40.0))
.style(theme::Container::Badge(theme::Badge::Standard))
.center_x()
.center_y()
.style(theme::badge::simple)
.center_x(Length::Fixed(40.0))
.center_y(Length::Fixed(40.0))
}
pub fn coin<T>() -> Container<'static, T> {
@ -67,11 +37,9 @@ pub fn coin<T>() -> Container<'static, T> {
.height(Length::Fixed(25.0))
.width(Length::Fixed(25.0)),
)
.width(Length::Fixed(40.0))
.height(Length::Fixed(40.0))
.style(theme::Container::Badge(theme::Badge::Standard))
.center_x()
.center_y()
.style(theme::badge::simple)
.center_x(Length::Fixed(40.0))
.center_y(Length::Fixed(40.0))
}
pub fn recovery<'a, T: 'a>() -> Container<'a, T> {
@ -108,11 +76,10 @@ pub fn badge_pill<'a, T: 'a>(label: &'a str, tooltip: &'a str) -> Container<'a,
tooltip::Tooltip::new(
Container::new(text::p2_regular(label))
.padding(10)
.center_x()
.style(theme::Container::Pill(theme::Pill::Simple)),
.center_x(Length::Shrink)
.style(theme::pill::simple),
tooltip,
tooltip::Position::Top,
)
.style(theme::Container::Card(theme::Card::Simple))
})
}

View File

@ -1,57 +1,55 @@
use crate::{color, theme, widget::*};
use iced::alignment::{Horizontal, Vertical};
use iced::widget::{button, container, row};
use iced::Alignment;
use super::text::text;
pub fn menu<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
button::Button::new(content_menu(icon.map(|i| i.style(color::GREY_3)), t).padding(10))
.style(theme::Button::Menu(false))
button::Button::new(content_menu(icon.map(|i| i.color(color::GREY_3)), t).padding(10))
.style(theme::button::menu)
}
pub fn menu_active<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
button::Button::new(content_menu(icon.map(|i| i.style(color::GREY_3)), t).padding(10))
.style(theme::Button::Menu(true))
button::Button::new(content_menu(icon.map(|i| i.color(color::GREY_3)), t).padding(10))
.style(theme::button::menu_pressed)
}
fn content_menu<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Container<'a, T> {
match icon {
None => container(text(t)).padding(5),
Some(i) => {
container(row![i, text(t)].spacing(10).align_items(Alignment::Center)).padding(5)
}
Some(i) => container(row![i, text(t)].spacing(10).align_y(Vertical::Center)).padding(5),
}
}
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)
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)
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)
button::Button::new(content(icon, t)).style(theme::button::container)
}
pub fn secondary<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Button<'a, T> {
button::Button::new(content(icon, t)).style(theme::Button::Secondary)
button::Button::new(content(icon, t)).style(theme::button::secondary)
}
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::Border)
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)
button(content(icon, t)).style(theme::button::container_border)
}
fn content<'a, T: 'a>(icon: Option<Text<'a>>, t: &'static str) -> Container<'a, T> {
match icon {
None => container(text(t)).center_x().padding(5),
Some(i) => container(row![i, text(t)].spacing(10).align_items(Alignment::Center))
.center_x()
None => container(text(t)).align_x(Horizontal::Center).padding(5),
Some(i) => container(row![i, text(t)].spacing(10).align_y(Vertical::Center))
.align_x(Horizontal::Center)
.padding(5),
}
}

View File

@ -3,19 +3,19 @@ use crate::{color, component::text::text, icon, theme, widget::*};
pub fn modal<'a, T: 'a, C: Into<Element<'a, T>>>(content: C) -> Container<'a, T> {
Container::new(content)
.padding(15)
.style(theme::Container::Card(theme::Card::Modal))
.style(theme::card::modal)
}
pub fn simple<'a, T: 'a, C: Into<Element<'a, T>>>(content: C) -> Container<'a, T> {
Container::new(content)
.padding(15)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}
pub fn invalid<'a, T: 'a, C: Into<Element<'a, T>>>(content: C) -> Container<'a, T> {
Container::new(content)
.padding(15)
.style(theme::Container::Card(theme::Card::Invalid))
.style(theme::card::invalid)
}
/// display an error card with the message and the error in a tooltip.
@ -23,12 +23,12 @@ pub fn warning<'a, T: 'a>(message: String) -> Container<'a, T> {
Container::new(
Row::new()
.spacing(20)
.align_items(iced::Alignment::Center)
.align_y(iced::Alignment::Center)
.push(icon::warning_icon())
.push(text(message)),
)
.padding(15)
.style(theme::Container::Card(theme::Card::Warning))
.style(theme::card::warning)
}
/// display an error card with the message and the error in a tooltip.
@ -37,14 +37,14 @@ pub fn error<'a, T: 'a>(message: &'static str, error: String) -> Container<'a, T
iced::widget::tooltip::Tooltip::new(
Row::new()
.spacing(20)
.align_items(iced::Alignment::Center)
.push(icon::warning_icon().style(color::RED))
.push(text(message).style(color::RED)),
.align_y(iced::Alignment::Center)
.push(icon::warning_icon().color(color::RED))
.push(text(message).color(color::RED)),
Text::new(error),
iced::widget::tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Error)),
.style(theme::card::error),
)
.padding(15)
.style(theme::Container::Card(theme::Card::Error))
.style(theme::card::error)
}

View File

@ -1,3 +1,5 @@
#![allow(deprecated)]
use iced::{
advanced,
widget::{column, component, Button, Component},
@ -16,7 +18,7 @@ pub struct Collapse<'a, M, H, F, C> {
impl<'a, Message, T, H, F, C, Theme, Renderer> Collapse<'a, Message, H, F, C>
where
Renderer: advanced::Renderer,
Theme: iced::widget::button::StyleSheet,
Theme: iced::widget::button::Catalog,
Message: 'a,
T: Into<Message> + Clone + 'a,
H: Fn() -> Button<'a, Event<T>, Theme, Renderer> + 'a,
@ -53,7 +55,7 @@ where
F: Fn() -> Button<'a, Event<T>, Theme, Renderer>,
C: Fn() -> Element<'a, T, Theme, Renderer>,
Renderer: 'a + advanced::Renderer,
Theme: 'a + iced::widget::button::StyleSheet,
Theme: 'a + iced::widget::button::Catalog,
{
type State = Option<bool>;
type Event = Event<T>;
@ -96,7 +98,7 @@ impl<'a, Message, T, H: 'a, F: 'a, C: 'a, Theme, Renderer> From<Collapse<'a, Mes
where
Message: 'a,
Renderer: 'a + advanced::Renderer,
Theme: 'a + iced::widget::button::StyleSheet,
Theme: 'a + iced::widget::button::Catalog,
T: Into<Message> + Clone + 'a,
H: Fn() -> Button<'a, Event<T>, Theme, Renderer>,
F: Fn() -> Button<'a, Event<T>, Theme, Renderer>,

View File

@ -12,39 +12,39 @@ use iced::{
use chrono::{DateTime, Local, Utc};
pub fn unconfirmed_outgoing_event<'a, T: Clone + 'a>(
label: Option<Text<'a>>,
pub fn unconfirmed_outgoing_event<T: Clone + 'static>(
label: Option<Text<'static>>,
amount: &Amount,
msg: T,
) -> Container<'a, T> {
) -> Container<'static, T> {
Container::new(
button(
row!(
row!(badge::spend(), Column::new().push_maybe(label),)
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
badge::unconfirmed(),
row!(text::p1_regular("-"), amount::amount(amount))
.spacing(5)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(5)
.spacing(20),
)
.on_press(msg)
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}
pub fn confirmed_outgoing_event<'a, T: Clone + 'a>(
label: Option<Text<'a>>,
pub fn confirmed_outgoing_event<T: Clone + 'static>(
label: Option<Text<'static>>,
date: DateTime<Utc>,
amount: &Amount,
msg: T,
) -> Container<'a, T> {
) -> Container<'static, T> {
Container::new(
button(
row!(
@ -56,59 +56,59 @@ pub fn confirmed_outgoing_event<'a, T: Clone + 'a>(
.format("%b. %d, %Y - %T")
.to_string()
)
.style(color::GREY_3)
.color(color::GREY_3)
)
)
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
row!(text::p1_regular("-"), amount::amount(amount))
.spacing(5)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(5)
.spacing(20),
)
.on_press(msg)
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}
pub fn unconfirmed_incoming_event<'a, T: Clone + 'a>(
label: Option<Text<'a>>,
pub fn unconfirmed_incoming_event<T: Clone + 'static>(
label: Option<Text<'static>>,
amount: &Amount,
msg: T,
) -> Container<'a, T> {
) -> Container<'static, T> {
Container::new(
button(
row!(
row!(badge::receive(), Column::new().push_maybe(label))
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
badge::unconfirmed(),
row!(text::p1_regular("+"), amount::amount(amount))
.spacing(5)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(5)
.spacing(20),
)
.on_press(msg)
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}
pub fn confirmed_incoming_event<'a, T: Clone + 'a>(
label: Option<Text<'a>>,
pub fn confirmed_incoming_event<T: Clone + 'static>(
label: Option<Text<'static>>,
date: DateTime<Utc>,
amount: &Amount,
msg: T,
) -> Container<'a, T> {
) -> Container<'static, T> {
Container::new(
button(
row!(
@ -120,22 +120,22 @@ pub fn confirmed_incoming_event<'a, T: Clone + 'a>(
.format("%b. %d, %Y - %T")
.to_string()
)
.style(color::GREY_3)
.color(color::GREY_3)
)
)
.spacing(10)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.width(Length::Fill),
row!(text::p1_regular("+"), amount::amount(amount))
.spacing(5)
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(5)
.spacing(20),
)
.on_press(msg)
.style(theme::Button::TransparentBorder),
.style(theme::button::transparent_border),
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
}

View File

@ -110,13 +110,13 @@ impl<'a, Message: 'a + Clone> From<Form<'a, Message>> for Element<'a, Message> {
Container::new(
Column::new()
.push(if !form.valid {
form.input.style(theme::Form::Invalid)
form.input.style(theme::text_input::invalid)
} else {
form.input
})
.push_maybe(if !form.valid {
form.warning
.map(|message| text::caption(message).style(color::RED))
.map(|message| text::caption(message).color(color::RED))
} else {
None
})

View File

@ -8,7 +8,7 @@ use std::fmt::Display;
pub fn locked_hardware_wallet<'a, T: 'a, K: Display>(
kind: K,
pairing_code: Option<impl Into<Cow<'a, str>>>,
pairing_code: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
Container::new(
column(vec![
@ -38,7 +38,7 @@ pub fn supported_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
Container::new(
column(vec![
@ -58,12 +58,12 @@ pub fn supported_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
.padding(10)
}
pub fn warning_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
pub fn warning_hardware_wallet<'a, T: 'static, K: Display, V: Display, F: Display>(
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
warning: &'static str,
alias: Option<impl Into<Cow<'a, str>> + Display>,
warning: &'a str,
) -> Container<'a, T> {
container(
row(vec![
@ -83,14 +83,14 @@ pub fn warning_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
.into(),
column(vec![tooltip::Tooltip::new(
icon::warning_icon(),
warning,
iced::widget::text!("{}", warning),
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into()])
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
@ -119,7 +119,7 @@ pub fn unimplemented_method_hardware_wallet<'a, T: 'a, K: Display, V: Display, F
message,
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
.width(Length::Fill)
}
@ -147,7 +147,7 @@ pub fn unrelated_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
"This signer does not have a key in this wallet.",
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
.width(Length::Fill)
}
@ -156,7 +156,7 @@ pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
container(
row(vec![
@ -180,41 +180,48 @@ pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>
])
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn selected_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
pub fn selected_hardware_wallet<'a, T: 'static, K: Display, V: Display, F: Display>(
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
warning: Option<&'static str>,
) -> Container<'a, T> {
container(
Row::new()
.push(
column(vec![
Row::new()
.spacing(5)
.push_maybe(alias.map(|a| text::p1_bold(a)))
.push(text::p1_regular(format!("#{}", fingerprint)))
.into(),
Row::new()
.spacing(5)
.push(text::caption(kind.to_string()))
.push_maybe(version.map(|v| text::caption(v.to_string())))
.into(),
])
.width(Length::Fill),
)
.push_maybe(warning.map(|w| {
tooltip::Tooltip::new(icon::warning_icon(), w, tooltip::Position::Bottom)
.style(theme::Container::Card(theme::Card::Simple))
}))
.push(image::success_mark_icon().width(Length::Fixed(50.0)))
.align_items(Alignment::Center),
row(vec![
column(vec![
Row::new()
.spacing(5)
.push_maybe(alias.map(text::p1_bold))
.push(text::p1_regular(format!("#{}", fingerprint)))
.into(),
Row::new()
.spacing(5)
.push(text::caption(kind.to_string()))
.push_maybe(version.map(|v| text::caption(v)))
.into(),
])
.width(Length::Fill)
.into(),
if let Some(w) = warning {
tooltip::Tooltip::new(
icon::warning_icon(),
iced::widget::text!("{}", w),
tooltip::Position::Bottom,
)
.style(theme::card::simple)
.into()
} else {
Row::new().into()
},
image::success_mark_icon().width(Length::Fixed(50.0)).into(),
])
.align_y(Alignment::Center),
)
.padding(10)
}
@ -223,7 +230,7 @@ pub fn sign_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Displa
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
container(
row(vec![
@ -242,14 +249,14 @@ pub fn sign_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Displa
.width(Length::Fill)
.into(),
row(vec![
text::p1_regular("Signed").style(color::GREEN).into(),
text::p1_regular("Signed").color(color::GREEN).into(),
image::success_mark_icon().width(Length::Fixed(50.0)).into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(5)
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
@ -258,7 +265,7 @@ pub fn registration_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
container(
row(vec![
@ -277,19 +284,19 @@ pub fn registration_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F
.width(Length::Fill)
.into(),
row(vec![
text::p1_regular("Registered").style(color::GREEN).into(),
text::p1_regular("Registered").color(color::GREEN).into(),
image::success_mark_icon().width(Length::Fixed(50.0)).into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(5)
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn wrong_network_hardware_wallet<'a, T: 'a, K: Display, V: Display>(
pub fn wrong_network_hardware_wallet<'a, T: 'static, K: Display, V: Display>(
kind: K,
version: Option<V>,
) -> Container<'a, T> {
@ -313,15 +320,15 @@ pub fn wrong_network_hardware_wallet<'a, T: 'a, K: Display, V: Display>(
"The wrong bitcoin application is open or the device was initialized with the wrong network",
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn unsupported_hardware_wallet<'a, T: 'a, K: Display, V: Display>(
pub fn unsupported_hardware_wallet<'a, T: 'static, K: Display, V: Display>(
kind: K,
version: Option<V>,
) -> Container<'a, T> {
@ -345,15 +352,15 @@ pub fn unsupported_hardware_wallet<'a, T: 'a, K: Display, V: Display>(
"Make sure your device is unlocked and a supported Bitcoin application is opened.",
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn unsupported_version_hardware_wallet<'a, T: 'a, K: Display, V: Display, S: Display>(
pub fn unsupported_version_hardware_wallet<'a, T: 'static, K: Display, V: Display, S: Display>(
kind: K,
version: Option<V>,
requested_version: S,
@ -376,17 +383,17 @@ pub fn unsupported_version_hardware_wallet<'a, T: 'a, K: Display, V: Display, S:
"Please upgrade firmware",
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple))
.style(theme::card::simple)
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn sign_success_hot_signer<'a, T: 'a, F: Display>(
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
container(
row(vec![
@ -404,21 +411,21 @@ pub fn sign_success_hot_signer<'a, T: 'a, F: Display>(
.width(Length::Fill)
.into(),
row(vec![
text::p1_regular("Signed").style(color::GREEN).into(),
text::p1_regular("Signed").color(color::GREEN).into(),
image::success_mark_icon().width(Length::Fixed(50.0)).into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(5)
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn selected_hot_signer<'a, T: 'a, F: Display>(
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
container(
row(vec![
@ -440,14 +447,14 @@ pub fn selected_hot_signer<'a, T: 'a, F: Display>(
.into(),
image::success_mark_icon().width(Length::Fixed(50.0)).into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.padding(10)
}
pub fn unselected_hot_signer<'a, T: 'a, F: Display>(
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
Container::new(
column(vec![
@ -471,7 +478,7 @@ pub fn unselected_hot_signer<'a, T: 'a, F: Display>(
pub fn hot_signer<'a, T: 'a, F: Display>(
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<impl Into<Cow<'a, str>> + Display>,
) -> Container<'a, T> {
Container::new(
column(vec![

View File

@ -24,7 +24,7 @@ use self::text::Text;
pub fn separation<'a, T: 'a>() -> Container<'a, T> {
Container::new(Column::new().push(text::text(" ")))
.style(theme::Container::Border)
.style(theme::container::border)
.height(Length::Fixed(1.0))
}
@ -44,10 +44,9 @@ pub fn network_banner<'a, T: 'a>(network: Network) -> Container<'a, T> {
)
.push(text::text(", COINS HAVE "))
.push(text::text("NO VALUE").bold())
.align_items(iced::Alignment::Center),
.align_y(iced::Alignment::Center),
)
.padding(5)
.width(Length::Fill)
.center_x()
.style(theme::Container::Banner)
.center_x(Length::Fill)
.style(theme::banner::network)
}

View File

@ -147,7 +147,7 @@ where
state: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
operation: &mut dyn widget::Operation,
) {
self.base
.as_widget()
@ -249,7 +249,7 @@ where
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
operation: &mut dyn widget::Operation,
) {
self.content.as_widget().operate(
self.tree,

View File

@ -1,4 +1,3 @@
use std::borrow::Cow;
use std::fmt::Display;
use crate::{
@ -20,41 +19,41 @@ pub fn warning<'a, T: 'a + Clone>(message: String, error: String) -> Container<'
Row::new()
.push(
Container::new(
text::p1_bold(message_clone.to_string()).style(color::LIGHT_BLACK),
text::p1_bold(message_clone.to_string()).color(color::LIGHT_BLACK),
)
.width(Length::Fill),
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text::p1_bold("Learn more").style(color::LIGHT_BLACK))
.push(icon::collapse_icon().style(color::LIGHT_BLACK)),
.push(text::p1_bold("Learn more").color(color::LIGHT_BLACK))
.push(icon::collapse_icon().color(color::LIGHT_BLACK)),
),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || {
Button::new(
Row::new()
.push(
Container::new(text::p1_bold(message.to_owned()).style(color::LIGHT_BLACK))
Container::new(text::p1_bold(message.to_owned()).color(color::LIGHT_BLACK))
.width(Length::Fill),
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text::p1_bold("Learn more").style(color::LIGHT_BLACK))
.push(icon::collapsed_icon().style(color::LIGHT_BLACK)),
.push(text::p1_bold("Learn more").color(color::LIGHT_BLACK))
.push(icon::collapsed_icon().color(color::LIGHT_BLACK)),
),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || Element::<'a, T>::from(text::p2_regular(error.to_owned())),
)))
.padding(15)
.style(theme::Container::Card(theme::Card::Warning))
.style(theme::card::warning)
.width(Length::Fill)
}
@ -62,14 +61,14 @@ pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>
kind: K,
version: Option<V>,
fingerprint: F,
alias: Option<impl Into<Cow<'a, str>>>,
alias: Option<&'a str>,
) -> Container<'a, T> {
container(
row(vec![
column(vec![
Row::new()
.spacing(5)
.push_maybe(alias.map(|a| text::p1_bold(a)))
.push_maybe(alias.map(text::p1_bold))
.push(text::p1_regular(format!("#{}", fingerprint)))
.into(),
Row::new()
@ -86,9 +85,9 @@ pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>
])
.into(),
])
.align_items(Alignment::Center),
.align_y(Alignment::Center),
)
.style(theme::Container::Notification(theme::Notification::Pending))
.style(theme::notification::pending)
.padding(10)
}
@ -103,40 +102,40 @@ pub fn processing_hardware_wallet_error<'a, T: 'a + Clone>(
Row::new()
.push(
Container::new(
text::p1_bold(message_clone.to_string()).style(color::LIGHT_BLACK),
text::p1_bold(message_clone.to_string()).color(color::LIGHT_BLACK),
)
.width(Length::Fill),
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text::p1_bold("Learn more").style(color::LIGHT_BLACK))
.push(icon::collapse_icon().style(color::LIGHT_BLACK)),
.push(text::p1_bold("Learn more").color(color::LIGHT_BLACK))
.push(icon::collapse_icon().color(color::LIGHT_BLACK)),
),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || {
Button::new(
Row::new()
.push(
Container::new(text::p1_bold(message.to_owned()).style(color::LIGHT_BLACK))
Container::new(text::p1_bold(message.to_owned()).color(color::LIGHT_BLACK))
.width(Length::Fill),
)
.push(
Row::new()
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(10)
.push(text::p1_bold("Learn more").style(color::LIGHT_BLACK))
.push(icon::collapsed_icon().style(color::LIGHT_BLACK)),
.push(text::p1_bold("Learn more").color(color::LIGHT_BLACK))
.push(icon::collapsed_icon().color(color::LIGHT_BLACK)),
),
)
.style(theme::Button::Transparent)
.style(theme::button::transparent)
},
move || Element::<'a, T>::from(text::p2_regular(error.to_owned())),
)))
.padding(10)
.style(theme::Container::Notification(theme::Notification::Error))
.style(theme::notification::error)
.width(Length::Fill)
}

View File

@ -108,7 +108,7 @@ where
_viewport: &Rectangle,
) -> event::Status {
let state = tree.state.downcast_mut::<CarouselState>();
if let Event::Window(_, window::Event::RedrawRequested(now)) = event {
if let Event::Window(window::Event::RedrawRequested(now)) = event {
if now.duration_since(state.last_transition) > self.interval {
state.last_transition = now;
state.current = (state.current + 1) % self.children.len();
@ -172,7 +172,7 @@ pub fn typing_text_carousel<'a, Message, Theme>(
text_builder: impl Fn(&'a str) -> iced::widget::Text<'a, Theme, Renderer>,
) -> Carousel<'a, Message, Theme>
where
Theme: 'a + iced::widget::text::StyleSheet,
Theme: 'a + iced::widget::text::Catalog,
{
let mut children = Vec::new();
if show_empty {

View File

@ -1,6 +1,6 @@
use crate::{font, theme::Theme};
use iced::advanced::text::Shaping;
use std::borrow::Cow;
use std::fmt::Display;
pub const H1_SIZE: u16 = 40;
pub const H2_SIZE: u16 = 29;
@ -11,98 +11,98 @@ pub const P1_SIZE: u16 = 16;
pub const P2_SIZE: u16 = 14;
pub const CAPTION_SIZE: u16 = 12;
pub fn h1<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h1<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::BOLD)
.size(H1_SIZE)
}
pub fn h2<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h2<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::BOLD)
.size(H2_SIZE)
}
pub fn h3<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h3<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::BOLD)
.size(H3_SIZE)
}
pub fn h4_bold<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h4_bold<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::BOLD)
.size(H4_SIZE)
}
pub fn h4_regular<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h4_regular<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::REGULAR)
.size(H4_SIZE)
}
pub fn h5_medium<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h5_medium<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::MEDIUM)
.size(H5_SIZE)
}
pub fn h5_regular<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn h5_regular<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::REGULAR)
.size(H5_SIZE)
}
pub fn p1_bold<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn p1_bold<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::BOLD)
.size(P1_SIZE)
}
pub fn p1_medium<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn p1_medium<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::MEDIUM)
.size(P1_SIZE)
}
pub fn p1_regular<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn p1_regular<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::REGULAR)
.size(P1_SIZE)
}
pub fn p2_medium<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn p2_medium<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::MEDIUM)
.size(P2_SIZE)
}
pub fn p2_regular<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn p2_regular<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::REGULAR)
.size(P2_SIZE)
}
pub fn caption<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
iced::widget::Text::new(content)
pub fn caption<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
iced::widget::text!("{}", content)
.shaping(Shaping::Advanced)
.font(font::REGULAR)
.size(CAPTION_SIZE)
}
pub fn text<'a>(content: impl Into<Cow<'a, str>>) -> iced::widget::Text<'a, Theme> {
pub fn text<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> {
p1_regular(content)
}

View File

@ -96,7 +96,7 @@ where
state: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn Operation<Message>,
operation: &mut dyn Operation,
) {
operation.container(None, layout.bounds(), &mut |operation| {
self.content
@ -303,7 +303,7 @@ where
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn iced::advanced::widget::Operation<Message>,
operation: &mut dyn iced::advanced::widget::Operation,
) {
operation.container(None, layout.bounds(), &mut |operation| {
self.toasts

View File

@ -1,12 +1,12 @@
use crate::{icon, theme, widget::*};
pub fn tooltip<'a, T: 'a>(help: &'static str) -> Container<'a, T> {
pub fn tooltip<T: 'static>(help: &'static str) -> Container<'static, T> {
Container::new(
iced::widget::tooltip::Tooltip::new(
icon::tooltip_icon(),
help,
iced::widget::tooltip::Position::Right,
)
.style(theme::Container::Card(theme::Card::Simple)),
.style(theme::card::simple),
)
}

View File

@ -1,7 +1,8 @@
use iced::{
font::{Family, Stretch, Weight},
Command, Font,
Font,
};
use std::borrow::Cow;
pub const BOLD: Font = Font {
family: Family::Name("IBM Plex Sans"),
@ -26,12 +27,12 @@ pub const REGULAR_BYTES: &[u8] = include_bytes!("../static/fonts/IBMPlexSans-Reg
pub const ICONEX_ICONS_BYTES: &[u8] = include_bytes!("../static/icons/iconex/iconex-icons.ttf");
pub const BOOTSTRAP_ICONS_BYTE: &[u8] = include_bytes!("../static/icons/bootstrap-icons.ttf");
pub fn loads<T: From<Result<(), iced::font::Error>> + 'static>() -> Vec<Command<T>> {
pub fn load() -> Vec<Cow<'static, [u8]>> {
vec![
iced::font::load(BOLD_BYTES).map(T::from),
iced::font::load(MEDIUM_BYTES).map(T::from),
iced::font::load(REGULAR_BYTES).map(T::from),
iced::font::load(ICONEX_ICONS_BYTES).map(T::from),
iced::font::load(BOOTSTRAP_ICONS_BYTE).map(T::from),
BOLD_BYTES.into(),
MEDIUM_BYTES.into(),
REGULAR_BYTES.into(),
ICONEX_ICONS_BYTES.into(),
BOOTSTRAP_ICONS_BYTE.into(),
]
}

View File

@ -7,7 +7,7 @@ fn bootstrap_icon(unicode: char) -> Text<'static> {
Text::new(unicode.to_string())
.font(BOOTSTRAP_ICONS)
.width(Length::Fixed(20.0))
.horizontal_alignment(alignment::Horizontal::Center)
.align_x(alignment::Horizontal::Center)
.size(P1_SIZE)
}
@ -129,7 +129,7 @@ fn iconex_icon(unicode: char) -> Text<'static> {
Text::new(unicode.to_string())
.font(ICONEX_ICONS)
.width(Length::Fixed(20.0))
.horizontal_alignment(alignment::Horizontal::Center)
.align_x(alignment::Horizontal::Center)
.size(P1_SIZE)
}

View File

@ -10,52 +10,52 @@ pub fn liana_app_icon() -> icon::Icon {
icon::from_file_data(LIANA_APP_ICON, None).unwrap()
}
pub fn liana_grey_logo() -> Svg {
pub fn liana_grey_logo() -> Svg<'static> {
let h = Handle::from_memory(LIANA_LOGO_GREY.to_vec());
Svg::new(h)
}
pub fn liana_brand_grey() -> Svg {
pub fn liana_brand_grey() -> Svg<'static> {
let h = Handle::from_memory(LIANA_BRAND_GREY.to_vec());
Svg::new(h)
}
pub fn wizardsardine() -> Svg {
pub fn wizardsardine() -> Svg<'static> {
let h = Handle::from_memory(WIZARDSARDINE_LETTERING.to_vec());
Svg::new(h)
}
const CREATE_NEW_WALLET_ICON: &[u8] = include_bytes!("../static/icons/blueprint.svg");
pub fn create_new_wallet_icon() -> Svg {
pub fn create_new_wallet_icon() -> Svg<'static> {
let h = Handle::from_memory(CREATE_NEW_WALLET_ICON.to_vec());
Svg::new(h)
}
const PARTICIPATE_IN_NEW_WALLET_ICON: &[u8] = include_bytes!("../static/icons/discussion.svg");
pub fn participate_in_new_wallet_icon() -> Svg {
pub fn participate_in_new_wallet_icon() -> Svg<'static> {
let h = Handle::from_memory(PARTICIPATE_IN_NEW_WALLET_ICON.to_vec());
Svg::new(h)
}
const RESTORE_WALLET_ICON: &[u8] = include_bytes!("../static/icons/syncdata.svg");
pub fn restore_wallet_icon() -> Svg {
pub fn restore_wallet_icon() -> Svg<'static> {
let h = Handle::from_memory(RESTORE_WALLET_ICON.to_vec());
Svg::new(h)
}
const SUCCESS_MARK_ICON: &[u8] = include_bytes!("../static/icons/success-mark.svg");
pub fn success_mark_icon() -> Svg {
pub fn success_mark_icon() -> Svg<'static> {
let h = Handle::from_memory(SUCCESS_MARK_ICON.to_vec());
Svg::new(h)
}
const KEY_MARK_ICON: &[u8] = include_bytes!("../static/icons/key-mark.svg");
pub fn key_mark_icon() -> Svg {
pub fn key_mark_icon() -> Svg<'static> {
let h = Handle::from_memory(KEY_MARK_ICON.to_vec());
Svg::new(h)
}
@ -63,7 +63,7 @@ pub fn key_mark_icon() -> Svg {
const INHERITANCE_TEMPLATE_DESC: &[u8] =
include_bytes!("../static/images/inheritance_template_description.svg");
pub fn inheritance_template_description() -> Svg {
pub fn inheritance_template_description() -> Svg<'static> {
let h = Handle::from_memory(INHERITANCE_TEMPLATE_DESC.to_vec());
Svg::new(h)
}
@ -71,7 +71,7 @@ pub fn inheritance_template_description() -> Svg {
const CUSTOM_TEMPLATE_DESC: &[u8] =
include_bytes!("../static/images/custom_template_description.svg");
pub fn custom_template_description() -> Svg {
pub fn custom_template_description() -> Svg<'static> {
let h = Handle::from_memory(CUSTOM_TEMPLATE_DESC.to_vec());
Svg::new(h)
}
@ -79,7 +79,7 @@ pub fn custom_template_description() -> Svg {
const MULTISIG_SECURITY_TEMPLATE_DESC: &[u8] =
include_bytes!("../static/images/multisig_security_template.svg");
pub fn multisig_security_template_description() -> Svg {
pub fn multisig_security_template_description() -> Svg<'static> {
let h = Handle::from_memory(MULTISIG_SECURITY_TEMPLATE_DESC.to_vec());
Svg::new(h)
}

View File

@ -19,9 +19,9 @@ pub mod widget {
pub type Text<'a> = iced::widget::Text<'a, Theme, Renderer>;
pub type TextInput<'a, Message> = iced::widget::TextInput<'a, Message, Theme, Renderer>;
pub type Tooltip<'a> = iced::widget::Tooltip<'a, Theme, Renderer>;
pub type ProgressBar = iced::widget::ProgressBar<Theme>;
pub type ProgressBar<'a> = iced::widget::ProgressBar<'a, Theme>;
pub type PickList<'a, T, L, V, Message> =
iced::widget::PickList<'a, T, L, V, Message, Theme, Renderer>;
pub type Scrollable<'a, Message> = iced::widget::Scrollable<'a, Message, Theme, Renderer>;
pub type Svg = iced::widget::Svg<Theme>;
pub type Svg<'a> = iced::widget::Svg<'a, Theme>;
}

View File

@ -1,990 +0,0 @@
use iced::{
application,
widget::{
button, checkbox, container, pick_list, progress_bar, qr_code, radio, scrollable, slider,
svg, text, text_input,
},
};
use super::color;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum Theme {
#[default]
Dark,
Light,
}
impl application::StyleSheet for Theme {
type Style = ();
fn appearance(&self, _style: &Self::Style) -> application::Appearance {
match self {
Theme::Light => application::Appearance {
background_color: color::GREY_2,
text_color: color::LIGHT_BLACK,
},
Theme::Dark => application::Appearance {
background_color: color::LIGHT_BLACK,
text_color: color::WHITE,
},
}
}
}
#[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::GREY_2,
background: color::GREY_6.into(),
border: iced::Border {
color: color::GREY_2,
width: 0.0,
radius: 25.0.into(),
},
selected_text_color: color::LIGHT_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]
Default,
Color(iced::Color),
}
impl From<iced::Color> for Text {
fn from(color: iced::Color) -> Self {
Text::Color(color)
}
}
impl text::StyleSheet for Theme {
type Style = Text;
fn appearance(&self, style: Self::Style) -> text::Appearance {
match style {
Text::Default => Default::default(),
Text::Color(c) => text::Appearance { color: Some(c) },
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Container {
#[default]
Transparent,
Background,
Foreground,
Border,
Banner,
Card(Card),
Badge(Badge),
Pill(Pill),
Custom(iced::Color),
Notification(Notification),
QrCode,
}
impl container::StyleSheet for Theme {
type Style = Container;
fn appearance(&self, style: &Self::Style) -> iced::widget::container::Appearance {
match self {
Theme::Light => match style {
Container::Transparent => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
..container::Appearance::default()
},
Container::Background => container::Appearance {
background: Some(color::GREY_2.into()),
..container::Appearance::default()
},
Container::Foreground => container::Appearance {
background: Some(color::GREY_2.into()),
..container::Appearance::default()
},
Container::Border => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
border: iced::Border {
color: color::LIGHT_BLACK,
width: 1.0,
radius: 0.0.into(),
},
..container::Appearance::default()
},
Container::Card(c) => c.appearance(self),
Container::Badge(c) => c.appearance(self),
Container::Pill(c) => c.appearance(self),
Container::Notification(c) => c.appearance(self),
Container::Custom(c) => container::Appearance {
background: Some((*c).into()),
..container::Appearance::default()
},
Container::QrCode => container::Appearance {
background: Some(color::WHITE.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Container::Banner => container::Appearance {
background: Some(color::WHITE.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 0.0.into(),
},
text_color: color::LIGHT_BLACK.into(),
..container::Appearance::default()
},
},
Theme::Dark => match style {
Container::Transparent => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
..container::Appearance::default()
},
Container::Background => container::Appearance {
background: Some(color::LIGHT_BLACK.into()),
..container::Appearance::default()
},
Container::Foreground => container::Appearance {
background: Some(color::BLACK.into()),
..container::Appearance::default()
},
Container::Border => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
border: iced::Border {
color: color::GREY_3,
width: 1.0,
radius: 0.0.into(),
},
..container::Appearance::default()
},
Container::Card(c) => c.appearance(self),
Container::Badge(c) => c.appearance(self),
Container::Pill(c) => c.appearance(self),
Container::Notification(c) => c.appearance(self),
Container::Custom(c) => container::Appearance {
background: Some((*c).into()),
..container::Appearance::default()
},
Container::QrCode => container::Appearance {
background: Some(color::WHITE.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Container::Banner => container::Appearance {
background: Some(color::BLUE.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 0.0.into(),
},
text_color: color::LIGHT_BLACK.into(),
..container::Appearance::default()
},
},
}
}
}
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 Notification {
#[default]
Pending,
Error,
}
impl Notification {
fn appearance(&self, theme: &Theme) -> iced::widget::container::Appearance {
match theme {
Theme::Light => match self {
Self::Pending => container::Appearance {
background: Some(iced::Background::Color(color::GREEN)),
text_color: color::LIGHT_BLACK.into(),
border: iced::Border {
color: color::GREEN,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Self::Error => container::Appearance {
background: Some(iced::Background::Color(color::ORANGE)),
text_color: color::LIGHT_BLACK.into(),
border: iced::Border {
color: color::ORANGE,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
},
Theme::Dark => match self {
Self::Pending => container::Appearance {
background: Some(iced::Background::Color(color::GREEN)),
text_color: color::LIGHT_BLACK.into(),
border: iced::Border {
color: color::GREEN,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Self::Error => container::Appearance {
background: Some(iced::Background::Color(color::ORANGE)),
text_color: color::LIGHT_BLACK.into(),
border: iced::Border {
color: color::ORANGE,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
},
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Card {
#[default]
Simple,
Modal,
Border,
Invalid,
Warning,
Error,
}
impl Card {
fn appearance(&self, theme: &Theme) -> iced::widget::container::Appearance {
match theme {
Theme::Light => match self {
Card::Simple => container::Appearance {
background: Some(color::GREY_2.into()),
..container::Appearance::default()
},
Card::Modal => container::Appearance {
background: Some(color::GREY_2.into()),
..container::Appearance::default()
},
Card::Border => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
border: iced::Border {
color: color::GREY_7,
width: 1.0,
radius: 10.0.into(),
},
..container::Appearance::default()
},
Card::Invalid => container::Appearance {
background: Some(color::GREY_2.into()),
text_color: color::BLACK.into(),
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 0.0.into(),
},
..container::Appearance::default()
},
Card::Error => container::Appearance {
background: Some(color::GREY_2.into()),
text_color: color::RED.into(),
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 0.0.into(),
},
..container::Appearance::default()
},
Card::Warning => container::Appearance {
background: Some(color::ORANGE.into()),
text_color: color::GREY_2.into(),
..container::Appearance::default()
},
},
Theme::Dark => match self {
Card::Simple => container::Appearance {
background: Some(color::GREY_6.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Card::Modal => container::Appearance {
background: Some(color::LIGHT_BLACK.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Card::Border => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
border: iced::Border {
color: color::GREY_7,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Card::Invalid => container::Appearance {
background: Some(color::LIGHT_BLACK.into()),
text_color: color::RED.into(),
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Card::Error => container::Appearance {
background: Some(color::LIGHT_BLACK.into()),
text_color: color::RED.into(),
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 25.0.into(),
},
..container::Appearance::default()
},
Card::Warning => container::Appearance {
background: Some(color::ORANGE.into()),
text_color: color::LIGHT_BLACK.into(),
..container::Appearance::default()
},
},
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Badge {
#[default]
Standard,
Bitcoin,
}
impl Badge {
fn appearance(&self, _theme: &Theme) -> iced::widget::container::Appearance {
match self {
Self::Standard => container::Appearance {
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 40.0.into(),
},
background: Some(color::GREY_4.into()),
..container::Appearance::default()
},
Self::Bitcoin => container::Appearance {
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 40.0.into(),
},
background: Some(color::ORANGE.into()),
text_color: iced::Color::WHITE.into(),
..container::Appearance::default()
},
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Pill {
#[default]
Simple,
Primary,
Success,
Warning,
}
impl Pill {
fn appearance(&self, _theme: &Theme) -> iced::widget::container::Appearance {
match self {
Self::Primary => container::Appearance {
background: Some(color::GREEN.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
text_color: color::LIGHT_BLACK.into(),
..container::Appearance::default()
},
Self::Success => container::Appearance {
background: Some(color::GREEN.into()),
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
text_color: color::LIGHT_BLACK.into(),
..container::Appearance::default()
},
Self::Simple => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
border: iced::Border {
color: color::GREY_3,
width: 1.0,
radius: 25.0.into(),
},
text_color: color::GREY_3.into(),
..container::Appearance::default()
},
Self::Warning => container::Appearance {
background: Some(iced::Color::TRANSPARENT.into()),
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 25.0.into(),
},
text_color: color::RED.into(),
..container::Appearance::default()
},
}
}
}
#[derive(Default)]
pub struct Radio {}
impl radio::StyleSheet for Theme {
type Style = Radio;
fn active(&self, _style: &Self::Style, _is_selected: bool) -> radio::Appearance {
radio::Appearance {
background: iced::Color::TRANSPARENT.into(),
dot_color: color::GREEN,
border_width: 1.0,
border_color: color::GREY_7,
text_color: None,
}
}
fn hovered(&self, style: &Self::Style, is_selected: bool) -> radio::Appearance {
let active = self.active(style, is_selected);
radio::Appearance {
dot_color: color::GREEN,
border_color: color::GREEN,
background: iced::Color::TRANSPARENT.into(),
..active
}
}
}
#[derive(Default, Clone)]
pub struct Scrollable {}
impl scrollable::StyleSheet for Theme {
type Style = Scrollable;
fn active(&self, _style: &Self::Style) -> scrollable::Appearance {
scrollable::Appearance {
gap: None,
container: container::Appearance::default(),
scrollbar: scrollable::Scrollbar {
background: None,
border: iced::Border {
color: color::GREY_3,
width: 0.0,
radius: 10.0.into(),
},
scroller: scrollable::Scroller {
color: color::GREY_7,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 10.0.into(),
},
},
},
}
}
fn hovered(&self, style: &Self::Style, _is_hovered: bool) -> scrollable::Appearance {
let active = self.active(style);
scrollable::Appearance { ..active }
}
}
#[derive(Default, Clone)]
pub enum PickList {
#[default]
Secondary,
}
impl pick_list::StyleSheet for Theme {
type Style = PickList;
fn active(&self, _style: &Self::Style) -> pick_list::Appearance {
pick_list::Appearance {
placeholder_color: color::GREY_6,
handle_color: color::GREY_7,
background: color::GREY_6.into(),
border: iced::Border {
color: color::GREY_7,
width: 1.0,
radius: 25.0.into(),
},
text_color: color::GREY_2,
}
}
fn hovered(&self, _style: &Self::Style) -> pick_list::Appearance {
pick_list::Appearance {
placeholder_color: color::GREY_6,
handle_color: color::GREEN,
background: color::GREY_6.into(),
border: iced::Border {
color: color::GREEN,
width: 1.0,
radius: 25.0.into(),
},
text_color: color::GREEN,
}
}
}
#[derive(Default)]
pub struct CheckBox {}
impl checkbox::StyleSheet for Theme {
type Style = CheckBox;
fn active(&self, _style: &Self::Style, is_selected: bool) -> checkbox::Appearance {
if is_selected {
checkbox::Appearance {
background: color::GREEN.into(),
icon_color: color::GREY_4,
text_color: None,
border: iced::Border {
color: color::TRANSPARENT,
width: 1.0,
radius: 4.0.into(),
},
}
} else {
checkbox::Appearance {
background: color::GREY_4.into(),
icon_color: color::GREEN,
text_color: None,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 4.0.into(),
},
}
}
}
fn hovered(&self, style: &Self::Style, is_selected: bool) -> checkbox::Appearance {
self.active(style, is_selected)
}
}
#[derive(Default)]
pub enum Button {
#[default]
Primary,
Secondary,
Destructive,
SecondaryDestructive,
Transparent,
TransparentBorder,
Border,
Menu(bool),
}
impl button::StyleSheet for Theme {
type Style = Button;
fn active(&self, style: &Self::Style) -> button::Appearance {
match self {
Theme::Light => button::Appearance::default(),
Theme::Dark => match style {
Button::Primary => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::GREEN.into()),
text_color: color::LIGHT_BLACK,
border: iced::Border {
color: color::GREEN,
width: 1.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Secondary | Button::SecondaryDestructive | Button::Border => {
button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::GREY_6.into()),
text_color: color::GREY_2,
border: iced::Border {
color: color::GREY_7,
width: 1.0,
radius: 25.0.into(),
},
..button::Appearance::default()
}
}
Button::Destructive => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::GREY_6.into()),
text_color: color::RED,
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Transparent => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(iced::Color::TRANSPARENT.into()),
text_color: color::GREY_2,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::TransparentBorder => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(iced::Color::TRANSPARENT.into()),
text_color: color::WHITE,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Menu(active) => {
if *active {
button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::LIGHT_BLACK.into()),
text_color: color::WHITE,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
}
} else {
button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(iced::Color::TRANSPARENT.into()),
text_color: color::WHITE,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
}
}
}
},
}
}
fn hovered(&self, style: &Self::Style) -> button::Appearance {
match self {
Theme::Light => button::Appearance::default(),
Theme::Dark => match style {
Button::Primary => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::GREEN.into()),
text_color: color::LIGHT_BLACK,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Secondary => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::GREY_6.into()),
text_color: color::GREEN,
border: iced::Border {
color: color::GREEN,
width: 1.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Destructive | Button::SecondaryDestructive => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::RED.into()),
text_color: color::LIGHT_BLACK,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Transparent => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(iced::Color::TRANSPARENT.into()),
text_color: color::GREY_2,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::TransparentBorder | Button::Border => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::GREY_6.into()),
text_color: color::WHITE,
border: iced::Border {
color: color::GREEN,
width: 1.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
Button::Menu(_) => button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::LIGHT_BLACK.into()),
text_color: color::WHITE,
border: iced::Border {
color: color::TRANSPARENT,
width: 0.0,
radius: 25.0.into(),
},
..button::Appearance::default()
},
},
}
}
fn disabled(&self, style: &Self::Style) -> button::Appearance {
let active = if let Button::Primary = style {
self.active(&Button::Secondary)
} else {
self.active(style)
};
button::Appearance {
shadow_offset: iced::Vector::default(),
background: Some(color::TRANSPARENT.into()),
text_color: iced::Color {
a: active.text_color.a * 0.5,
..active.text_color
},
..active
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Form {
#[default]
Simple,
Invalid,
}
impl text_input::StyleSheet for Theme {
type Style = Form;
fn active(&self, style: &Self::Style) -> text_input::Appearance {
match style {
Form::Simple => text_input::Appearance {
icon_color: color::GREY_7,
background: iced::Background::Color(iced::Color::TRANSPARENT),
border: iced::Border {
color: color::GREY_7,
width: 1.0,
radius: 25.0.into(),
},
},
Form::Invalid => text_input::Appearance {
icon_color: color::GREY_7,
background: iced::Background::Color(iced::Color::TRANSPARENT),
border: iced::Border {
color: color::RED,
width: 1.0,
radius: 25.0.into(),
},
},
}
}
fn disabled(&self, style: &Self::Style) -> text_input::Appearance {
text_input::Appearance {
..self.active(style)
}
}
fn focused(&self, style: &Self::Style) -> text_input::Appearance {
text_input::Appearance {
..self.active(style)
}
}
fn disabled_color(&self, _style: &Self::Style) -> iced::Color {
color::GREY_7
}
fn placeholder_color(&self, _style: &Self::Style) -> iced::Color {
color::GREY_7
}
fn value_color(&self, _style: &Self::Style) -> iced::Color {
color::GREY_2
}
fn selection_color(&self, _style: &Self::Style) -> iced::Color {
color::GREEN
}
}
#[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: color::GREY_6.into(),
bar: color::GREEN.into(),
border_radius: 10.0.into(),
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Slider {
#[default]
Simple,
}
impl slider::StyleSheet for Theme {
type Style = Slider;
fn active(&self, _style: &Self::Style) -> slider::Appearance {
let handle = slider::Handle {
shape: slider::HandleShape::Rectangle {
width: 8,
border_radius: 4.0.into(),
},
color: color::BLACK,
border_color: color::GREEN,
border_width: 1.0,
};
slider::Appearance {
rail: slider::Rail {
colors: (color::GREEN, iced::Color::TRANSPARENT),
border_radius: 4.0.into(),
width: 2.0,
},
handle,
}
}
fn hovered(&self, _style: &Self::Style) -> slider::Appearance {
let handle = slider::Handle {
shape: slider::HandleShape::Rectangle {
width: 8,
border_radius: 4.0.into(),
},
color: color::GREEN,
border_color: color::GREEN,
border_width: 1.0,
};
slider::Appearance {
rail: slider::Rail {
colors: (color::GREEN, iced::Color::TRANSPARENT),
border_radius: 4.0.into(),
width: 2.0,
},
handle,
}
}
fn dragging(&self, _style: &Self::Style) -> slider::Appearance {
let handle = slider::Handle {
shape: slider::HandleShape::Rectangle {
width: 8,
border_radius: 4.0.into(),
},
color: color::GREEN,
border_color: color::GREEN,
border_width: 1.0,
};
slider::Appearance {
rail: slider::Rail {
colors: (color::GREEN, iced::Color::TRANSPARENT),
border_radius: 4.0.into(),
width: 2.0,
},
handle,
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum Svg {
#[default]
Simple,
}
impl svg::StyleSheet for Theme {
type Style = ProgressBar;
fn appearance(&self, _style: &Self::Style) -> svg::Appearance {
svg::Appearance::default()
}
}
impl qr_code::StyleSheet for Theme {
type Style = ();
fn appearance(&self, _style: &Self::Style) -> qr_code::Appearance {
qr_code::Appearance {
cell: color::BLACK,
background: color::WHITE,
}
}
}

View File

@ -0,0 +1,26 @@
use iced::widget::container::Style;
use iced::{Background, Border};
use super::palette::ContainerPalette;
use super::Theme;
fn badge(palette: &ContainerPalette) -> Style {
Style {
background: Some(Background::Color(palette.background)),
text_color: palette.text,
border: Border {
radius: 25.0.into(),
width: 1.0,
color: iced::Color::TRANSPARENT,
},
..Default::default()
}
}
pub fn simple(theme: &Theme) -> Style {
badge(&theme.colors.badges.simple)
}
pub fn bitcoin(theme: &Theme) -> Style {
badge(&theme.colors.badges.bitcoin)
}

View File

@ -0,0 +1,28 @@
use iced::widget::container::Style;
use iced::{Background, Border};
use super::palette::ContainerPalette;
use super::Theme;
fn banner(palette: &ContainerPalette) -> Style {
Style {
background: Some(Background::Color(palette.background)),
text_color: palette.text,
border: if let Some(color) = palette.border {
Border {
width: 1.0,
color,
..Default::default()
}
} else {
Border {
..Default::default()
}
},
..Default::default()
}
}
pub fn network(theme: &Theme) -> Style {
banner(&theme.colors.banners.network)
}

View File

@ -0,0 +1,147 @@
use iced::widget::button::{Catalog, Status, Style, StyleFn};
use iced::{Background, Border, Color};
use super::palette::Button;
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn primary(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.primary, status)
}
pub fn secondary(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.secondary, status)
}
pub fn destructive(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.destructive, status)
}
pub fn container(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.container, status)
}
pub fn container_border(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.container_border, status)
}
pub fn menu(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.menu, status)
}
pub fn menu_pressed(theme: &Theme, _status: Status) -> Style {
button(&theme.colors.buttons.menu, Status::Pressed)
}
pub fn transparent(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.transparent, status)
}
pub fn transparent_border(theme: &Theme, status: Status) -> Style {
button(&theme.colors.buttons.transparent_border, status)
}
fn button(p: &Button, status: Status) -> Style {
match status {
Status::Active => Style {
background: Some(Background::Color(p.active.background)),
text_color: p.active.text,
border: if let Some(color) = p.active.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
..Default::default()
},
Status::Pressed => {
if let Some(pressed) = p.pressed {
Style {
background: Some(Background::Color(pressed.background)),
text_color: pressed.text,
border: if let Some(color) = pressed.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
..Default::default()
}
} else {
button(p, Status::Active)
}
}
Status::Hovered => Style {
background: Some(Background::Color(p.hovered.background)),
text_color: p.hovered.text,
border: if let Some(color) = p.hovered.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
..Default::default()
},
Status::Disabled => {
if let Some(disabled) = p.disabled {
Style {
background: Some(Background::Color(disabled.background)),
text_color: Color {
a: 0.2,
r: disabled.text.r,
g: disabled.text.g,
b: disabled.text.b,
},
border: if let Some(color) = disabled.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
..Default::default()
}
} else {
let active: Style = button(p, Status::Active);
Style {
text_color: Color {
a: 0.2,
..active.text_color
},
..active
}
}
}
}
}

View File

@ -0,0 +1,48 @@
use iced::widget::container::Style;
use iced::{Background, Border};
use super::palette::ContainerPalette;
use super::Theme;
fn card(palette: &ContainerPalette) -> Style {
Style {
background: Some(Background::Color(palette.background)),
text_color: palette.text,
border: if let Some(color) = palette.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
..Default::default()
}
}
pub fn simple(theme: &Theme) -> Style {
card(&theme.colors.cards.simple)
}
pub fn modal(theme: &Theme) -> Style {
card(&theme.colors.cards.modal)
}
pub fn border(theme: &Theme) -> Style {
card(&theme.colors.cards.border)
}
pub fn invalid(theme: &Theme) -> Style {
card(&theme.colors.cards.invalid)
}
pub fn warning(theme: &Theme) -> Style {
card(&theme.colors.cards.warning)
}
pub fn error(theme: &Theme) -> Style {
card(&theme.colors.cards.error)
}

View File

@ -0,0 +1,37 @@
use iced::{
widget::checkbox::{Catalog, Status, Style, StyleFn},
Border,
};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> <Self as Catalog>::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &<Self as Catalog>::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn primary(theme: &Theme, _status: Status) -> Style {
Style {
icon_color: theme.colors.checkboxes.icon,
text_color: theme.colors.checkboxes.text.into(),
background: theme.colors.checkboxes.background.into(),
border: if let Some(color) = theme.colors.checkboxes.border {
Border {
radius: 4.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
}
}

View File

@ -0,0 +1,44 @@
use iced::widget::container::{transparent, Catalog, Style, StyleFn};
use iced::Background;
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(transparent)
}
fn style(&self, class: &Self::Class<'_>) -> Style {
class(self)
}
}
pub fn background(theme: &Theme) -> Style {
Style {
background: Some(Background::Color(theme.colors.general.background)),
..Default::default()
}
}
pub fn foreground(theme: &Theme) -> Style {
Style {
background: Some(Background::Color(theme.colors.general.foreground)),
..Default::default()
}
}
pub fn border(theme: &Theme) -> Style {
Style {
background: Some(Background::Color(theme.colors.general.background)),
..Default::default()
}
}
pub fn custom(color: iced::Color) -> Box<dyn Fn(&Theme) -> Style> {
Box::new(move |_theme: &Theme| Style {
background: Some(Background::Color(color)),
..Default::default()
})
}

33
liana-ui/src/theme/mod.rs Normal file
View File

@ -0,0 +1,33 @@
pub mod badge;
pub mod banner;
pub mod button;
pub mod card;
pub mod checkbox;
pub mod container;
pub mod notification;
pub mod overlay;
pub mod palette;
pub mod pick_list;
pub mod pill;
pub mod progress_bar;
pub mod qr_code;
pub mod radio;
pub mod scrollable;
pub mod slider;
pub mod svg;
pub mod text;
pub mod text_input;
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Theme {
pub colors: palette::Palette,
}
impl iced::application::DefaultStyle for Theme {
fn default_style(&self) -> iced::application::Appearance {
iced::application::Appearance {
background_color: self.colors.general.background,
text_color: self.colors.text.primary,
}
}
}

View File

@ -0,0 +1,32 @@
use iced::widget::container::Style;
use iced::{Background, Border};
use super::palette::ContainerPalette;
use super::Theme;
fn notification(palette: &ContainerPalette) -> Style {
Style {
background: Some(Background::Color(palette.background)),
text_color: palette.text,
border: if let Some(color) = palette.border {
Border {
width: 1.0,
color,
radius: 25.0.into(),
}
} else {
Border {
..Default::default()
}
},
..Default::default()
}
}
pub fn pending(theme: &Theme) -> Style {
notification(&theme.colors.notifications.pending)
}
pub fn error(theme: &Theme) -> Style {
notification(&theme.colors.notifications.error)
}

View File

@ -0,0 +1,38 @@
use iced::{
widget::overlay::menu::{Catalog, Style, StyleFn},
Border,
};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> <Self as Catalog>::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style {
class(self)
}
}
pub fn primary(theme: &Theme) -> Style {
Style {
text_color: theme.colors.text.primary,
background: theme.colors.buttons.secondary.active.background.into(),
selected_text_color: theme.colors.buttons.primary.active.text,
selected_background: theme.colors.buttons.primary.active.background.into(),
border: if let Some(color) = theme.colors.buttons.secondary.active.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
}
}

View File

@ -0,0 +1,508 @@
use crate::color;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Palette {
pub general: General,
pub text: Text,
pub buttons: Buttons,
pub cards: Cards,
pub banners: Banners,
pub badges: Badges,
pub pills: Pills,
pub notifications: Notifications,
pub text_inputs: TextInputs,
pub checkboxes: Checkboxes,
pub radio_buttons: RadioButtons,
pub sliders: Sliders,
pub progress_bars: ProgressBars,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Text {
pub primary: iced::Color,
pub secondary: iced::Color,
pub warning: iced::Color,
pub success: iced::Color,
pub error: iced::Color,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct General {
pub background: iced::Color,
pub foreground: iced::Color,
pub scrollable: iced::Color,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Buttons {
pub transparent: Button,
pub transparent_border: Button,
pub primary: Button,
pub secondary: Button,
pub destructive: Button,
pub container: Button,
pub container_border: Button,
pub menu: Button,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Button {
pub active: ButtonPalette,
pub hovered: ButtonPalette,
pub pressed: Option<ButtonPalette>,
pub disabled: Option<ButtonPalette>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ButtonPalette {
pub background: iced::Color,
pub text: iced::Color,
pub border: Option<iced::Color>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Containers {
pub border: ContainerPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ContainerPalette {
pub background: iced::Color,
pub text: Option<iced::Color>,
pub border: Option<iced::Color>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cards {
pub simple: ContainerPalette,
pub modal: ContainerPalette,
pub border: ContainerPalette,
pub invalid: ContainerPalette,
pub warning: ContainerPalette,
pub error: ContainerPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Banners {
pub network: ContainerPalette,
pub warning: ContainerPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Badges {
pub simple: ContainerPalette,
pub bitcoin: ContainerPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Pills {
pub simple: ContainerPalette,
pub primary: ContainerPalette,
pub success: ContainerPalette,
pub warning: ContainerPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Notifications {
pub pending: ContainerPalette,
pub error: ContainerPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextInputs {
pub primary: TextInput,
pub invalid: TextInput,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextInput {
pub active: TextInputPalette,
pub disabled: TextInputPalette,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextInputPalette {
pub background: iced::Color,
pub icon: iced::Color,
pub placeholder: iced::Color,
pub value: iced::Color,
pub selection: iced::Color,
pub border: Option<iced::Color>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Checkboxes {
pub icon: iced::Color,
pub text: iced::Color,
pub background: iced::Color,
pub border: Option<iced::Color>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RadioButtons {
pub dot: iced::Color,
pub text: iced::Color,
pub border: iced::Color,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Sliders {
pub background: iced::Color,
pub border: iced::Color,
pub rail_border: Option<iced::Color>,
pub rail_backgrounds: (iced::Color, iced::Color),
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ProgressBars {
pub background: iced::Color,
pub bar: iced::Color,
pub border: Option<iced::Color>,
}
impl std::default::Default for Palette {
fn default() -> Self {
Self {
general: General {
background: color::LIGHT_BLACK,
foreground: color::BLACK,
scrollable: color::GREY_7,
},
text: Text {
primary: color::WHITE,
secondary: color::GREY_3,
warning: color::ORANGE,
success: color::GREEN,
error: color::RED,
},
buttons: Buttons {
primary: Button {
active: ButtonPalette {
background: color::GREEN,
text: color::LIGHT_BLACK,
border: color::GREEN.into(),
},
hovered: ButtonPalette {
background: color::GREEN,
text: color::LIGHT_BLACK,
border: color::GREEN.into(),
},
pressed: Some(ButtonPalette {
background: color::GREEN,
text: color::LIGHT_BLACK,
border: color::GREEN.into(),
}),
disabled: Some(ButtonPalette {
background: color::GREY_6,
text: color::GREY_2,
border: color::GREY_7.into(),
}),
},
secondary: Button {
active: ButtonPalette {
background: color::GREY_6,
text: color::GREY_2,
border: color::GREY_7.into(),
},
hovered: ButtonPalette {
background: color::GREY_6,
text: color::GREEN,
border: color::GREEN.into(),
},
pressed: Some(ButtonPalette {
background: color::GREY_6,
text: color::GREEN,
border: color::GREEN.into(),
}),
disabled: Some(ButtonPalette {
background: color::GREY_6,
text: color::GREY_2,
border: color::GREY_7.into(),
}),
},
destructive: Button {
active: ButtonPalette {
background: color::GREY_6,
text: color::RED,
border: color::RED.into(),
},
hovered: ButtonPalette {
background: color::RED,
text: color::LIGHT_BLACK,
border: color::RED.into(),
},
pressed: Some(ButtonPalette {
background: color::RED,
text: color::LIGHT_BLACK,
border: color::RED.into(),
}),
disabled: Some(ButtonPalette {
background: color::GREY_6,
text: color::RED,
border: color::RED.into(),
}),
},
transparent: Button {
active: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
},
hovered: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
},
pressed: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
}),
disabled: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
}),
},
transparent_border: Button {
active: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::TRANSPARENT.into(),
},
hovered: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::GREEN.into(),
},
pressed: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::GREEN.into(),
}),
disabled: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::TRANSPARENT.into(),
}),
},
container: Button {
active: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
},
hovered: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
},
pressed: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
}),
disabled: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: None,
}),
},
container_border: Button {
active: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::TRANSPARENT.into(),
},
hovered: ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::GREEN.into(),
},
pressed: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::GREEN.into(),
}),
disabled: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::GREY_2,
border: color::TRANSPARENT.into(),
}),
},
menu: Button {
active: ButtonPalette {
background: color::TRANSPARENT,
text: color::WHITE,
border: color::TRANSPARENT.into(),
},
hovered: ButtonPalette {
background: color::LIGHT_BLACK,
text: color::WHITE,
border: color::TRANSPARENT.into(),
},
pressed: Some(ButtonPalette {
background: color::LIGHT_BLACK,
text: color::WHITE,
border: color::TRANSPARENT.into(),
}),
disabled: Some(ButtonPalette {
background: color::TRANSPARENT,
text: color::WHITE,
border: color::TRANSPARENT.into(),
}),
},
},
cards: Cards {
simple: ContainerPalette {
background: color::GREY_6,
text: None,
border: Some(color::TRANSPARENT),
},
modal: ContainerPalette {
background: color::LIGHT_BLACK,
text: None,
border: color::TRANSPARENT.into(),
},
border: ContainerPalette {
background: color::TRANSPARENT,
text: None,
border: color::GREY_7.into(),
},
invalid: ContainerPalette {
background: color::LIGHT_BLACK,
text: color::RED.into(),
border: color::RED.into(),
},
warning: ContainerPalette {
background: color::LIGHT_BLACK,
text: color::ORANGE.into(),
border: color::ORANGE.into(),
},
error: ContainerPalette {
background: color::LIGHT_BLACK,
text: color::RED.into(),
border: color::RED.into(),
},
},
banners: Banners {
network: ContainerPalette {
background: color::BLUE,
text: color::LIGHT_BLACK.into(),
border: None,
},
warning: ContainerPalette {
background: color::ORANGE,
text: color::LIGHT_BLACK.into(),
border: None,
},
},
badges: Badges {
simple: ContainerPalette {
background: color::GREY_4,
text: None,
border: color::TRANSPARENT.into(),
},
bitcoin: ContainerPalette {
background: color::ORANGE,
text: color::WHITE.into(),
border: color::TRANSPARENT.into(),
},
},
pills: Pills {
primary: ContainerPalette {
background: color::GREEN,
text: color::LIGHT_BLACK.into(),
border: color::TRANSPARENT.into(),
},
simple: ContainerPalette {
background: color::TRANSPARENT,
text: color::GREY_3.into(),
border: color::GREY_3.into(),
},
warning: ContainerPalette {
background: color::TRANSPARENT,
text: color::RED.into(),
border: color::RED.into(),
},
success: ContainerPalette {
background: color::GREEN,
text: color::LIGHT_BLACK.into(),
border: color::GREEN.into(),
},
},
notifications: Notifications {
pending: ContainerPalette {
background: color::GREEN,
text: color::LIGHT_BLACK.into(),
border: Some(color::GREEN),
},
error: ContainerPalette {
background: color::ORANGE,
text: color::LIGHT_BLACK.into(),
border: Some(color::ORANGE),
},
},
text_inputs: TextInputs {
primary: TextInput {
active: TextInputPalette {
background: color::TRANSPARENT,
icon: color::TRANSPARENT,
placeholder: color::GREY_7,
value: color::GREY_2,
selection: color::GREEN,
border: Some(color::GREY_7),
},
disabled: TextInputPalette {
background: color::TRANSPARENT,
icon: color::TRANSPARENT,
placeholder: color::GREY_7,
value: color::GREY_2,
selection: color::GREEN,
border: Some(color::GREY_7),
},
},
invalid: TextInput {
active: TextInputPalette {
background: color::TRANSPARENT,
icon: color::TRANSPARENT,
placeholder: color::GREY_7,
value: color::GREY_2,
selection: color::GREEN,
border: Some(color::RED),
},
disabled: TextInputPalette {
background: color::TRANSPARENT,
icon: color::TRANSPARENT,
placeholder: color::GREY_7,
value: color::TRANSPARENT,
selection: color::GREEN,
border: Some(color::RED),
},
},
},
checkboxes: Checkboxes {
icon: color::GREEN,
text: color::GREY_2,
background: color::GREY_4,
border: Some(color::GREY_4),
},
radio_buttons: RadioButtons {
dot: color::GREEN,
text: color::GREY_2,
border: color::GREY_7,
},
sliders: Sliders {
background: color::GREEN,
border: color::GREEN,
rail_border: None,
rail_backgrounds: (color::GREEN, color::TRANSPARENT),
},
progress_bars: ProgressBars {
bar: color::GREEN,
border: color::TRANSPARENT.into(),
background: color::GREY_6,
},
}
}
}

View File

@ -0,0 +1,38 @@
use iced::{
widget::pick_list::{Catalog, Status, Style, StyleFn},
Border,
};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> <Self as Catalog>::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &<Self as Catalog>::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn primary(theme: &Theme, _status: Status) -> Style {
Style {
text_color: theme.colors.buttons.secondary.active.text,
placeholder_color: theme.colors.buttons.secondary.active.text,
background: theme.colors.buttons.secondary.active.background.into(),
border: if let Some(color) = theme.colors.buttons.secondary.active.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
handle_color: theme.colors.buttons.secondary.active.text,
}
}

View File

@ -0,0 +1,34 @@
use iced::widget::container::Style;
use iced::{Background, Border};
use super::palette::ContainerPalette;
use super::Theme;
fn pill(palette: &ContainerPalette) -> Style {
Style {
background: Some(Background::Color(palette.background)),
text_color: palette.text,
border: Border {
radius: 25.0.into(),
width: 1.0,
color: palette.border.unwrap_or_default(),
},
..Default::default()
}
}
pub fn simple(theme: &Theme) -> Style {
pill(&theme.colors.pills.simple)
}
pub fn primary(theme: &Theme) -> Style {
pill(&theme.colors.pills.primary)
}
pub fn success(theme: &Theme) -> Style {
pill(&theme.colors.pills.success)
}
pub fn warning(theme: &Theme) -> Style {
pill(&theme.colors.pills.warning)
}

View File

@ -0,0 +1,36 @@
use iced::{
widget::progress_bar::{Catalog, Style, StyleFn},
Border,
};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> <Self as Catalog>::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style {
class(self)
}
}
pub fn primary(theme: &Theme) -> Style {
Style {
background: theme.colors.progress_bars.background.into(),
bar: theme.colors.progress_bars.bar.into(),
border: if let Some(color) = theme.colors.cards.simple.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border {
..Default::default()
}
},
}
}

View File

@ -0,0 +1,22 @@
use iced::widget::qr_code::{Catalog, Style, StyleFn};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(qr_code)
}
fn style(&self, class: &Self::Class<'_>) -> Style {
class(self)
}
}
pub fn qr_code(_theme: &Theme) -> Style {
Style {
background: iced::Color::WHITE,
cell: iced::Color::BLACK,
}
}

View File

@ -0,0 +1,25 @@
use iced::widget::radio::{Catalog, Status, Style, StyleFn};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> <Self as Catalog>::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &<Self as Catalog>::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn primary(theme: &Theme, _status: Status) -> Style {
Style {
dot_color: theme.colors.radio_buttons.dot,
text_color: theme.colors.radio_buttons.text.into(),
background: theme.colors.cards.simple.background.into(),
border_width: 1.0,
border_color: theme.colors.radio_buttons.border,
}
}

View File

@ -0,0 +1,54 @@
use iced::{
widget::{
container,
scrollable::{Catalog, Rail, Scroller, Status, Style, StyleFn},
},
Border, Color, Shadow,
};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn primary(theme: &Theme, status: Status) -> Style {
let rail = Rail {
background: None,
border: Border::default(),
scroller: Scroller {
color: theme.colors.general.scrollable,
border: Border {
radius: 8.0.into(),
width: 0.0,
color: Color::TRANSPARENT,
},
},
};
match status {
Status::Active { .. } | Status::Hovered { .. } | Status::Dragged { .. } => Style {
container: container::Style {
text_color: None,
background: None,
border: Border {
radius: 8.0.into(),
width: 1.0,
color: Color::TRANSPARENT,
},
shadow: Shadow::default(),
},
vertical_rail: rail,
horizontal_rail: rail,
gap: None,
},
}
}

View File

@ -0,0 +1,50 @@
use iced::{
widget::slider::{Catalog, Handle, HandleShape, Rail, Status, Style, StyleFn},
Border,
};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(slider)
}
fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn slider(theme: &Theme, _status: Status) -> Style {
Style {
rail: Rail {
backgrounds: (
theme.colors.sliders.rail_backgrounds.0.into(),
theme.colors.sliders.rail_backgrounds.1.into(),
),
border: if let Some(color) = theme.colors.sliders.rail_border {
Border {
color,
width: 1.0,
radius: 4.0.into(),
}
} else {
Border {
..Default::default()
}
},
width: 2.0,
},
handle: Handle {
shape: HandleShape::Rectangle {
width: 8,
border_radius: 4.0.into(),
},
background: theme.colors.sliders.background.into(),
border_color: theme.colors.sliders.border,
border_width: 1.0,
},
}
}

19
liana-ui/src/theme/svg.rs Normal file
View File

@ -0,0 +1,19 @@
use iced::widget::svg::{Catalog, Status, Style, StyleFn};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(default)
}
fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn default(_theme: &Theme, _status: Status) -> Style {
Style { color: None }
}

View File

@ -0,0 +1,35 @@
use iced::widget::text::{Catalog, Style, StyleFn};
use super::Theme;
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(default)
}
fn style(&self, class: &Self::Class<'_>) -> Style {
class(self)
}
}
pub fn default(_theme: &Theme) -> Style {
Style { color: None }
}
pub fn primary(theme: &Theme) -> Style {
Style {
color: Some(theme.colors.text.primary),
}
}
pub fn secondary(theme: &Theme) -> Style {
Style {
color: Some(theme.colors.text.secondary),
}
}
pub fn custom(color: iced::Color) -> Style {
Style { color: Some(color) }
}

View File

@ -0,0 +1,65 @@
use iced::{
widget::text_input::{Catalog, Status, Style, StyleFn},
Background, Border,
};
use super::{palette::TextInput, Theme};
impl Catalog for Theme {
type Class<'a> = StyleFn<'a, Self>;
fn default<'a>() -> Self::Class<'a> {
Box::new(primary)
}
fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
class(self, status)
}
}
pub fn primary(theme: &Theme, status: Status) -> Style {
text_input(&theme.colors.text_inputs.primary, status)
}
pub fn invalid(theme: &Theme, status: Status) -> Style {
text_input(&theme.colors.text_inputs.invalid, status)
}
fn text_input(c: &TextInput, status: Status) -> Style {
let active = Style {
background: Background::Color(c.active.background),
border: if let Some(color) = c.active.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border::default()
},
icon: c.active.icon,
placeholder: c.active.placeholder,
value: c.active.value,
selection: c.active.selection,
};
match status {
Status::Active | Status::Hovered | Status::Focused { .. } => active,
Status::Disabled => Style {
background: Background::Color(c.disabled.background),
border: if let Some(color) = c.disabled.border {
Border {
radius: 25.0.into(),
width: 1.0,
color,
}
} else {
Border::default()
},
icon: c.disabled.icon,
placeholder: c.disabled.placeholder,
value: c.disabled.value,
selection: c.disabled.selection,
},
}
}