Merge #421: Add alias to hotsigner component
997829bdfe30a950ca40412fc1d273c2f1ca7e43 fix unregistered hardware wallet view (edouard)
53d32085147fe6f8c0094c26008314eddfcc3bd0 Add alias to hot signer (edouard)
Pull request description:
When a hot signer is suggested to user and an alias was entered then the alias must be displayed with the "This computer" label as signer kind.
ACKs for top commit:
edouardparis:
Self-ACK 997829bdfe30a950ca40412fc1d273c2f1ca7e43
Tree-SHA512: 68cd8f6ca8bdbd439f6392fddf4f34f1d8a1a8b312003f219e20519dabff43b95af496051eef857fed132f80b3b49ee5cd3034361f0af7fdfe9ef666b2c16c2e
This commit is contained in:
commit
e55432d2d6
@ -379,6 +379,10 @@ impl Action for SignAction {
|
|||||||
self.error.as_ref(),
|
self.error.as_ref(),
|
||||||
&self.hws,
|
&self.hws,
|
||||||
self.wallet.signer.as_ref().map(|s| s.fingerprint()),
|
self.wallet.signer.as_ref().map(|s| s.fingerprint()),
|
||||||
|
self.wallet
|
||||||
|
.signer
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|signer| self.wallet.keys_aliases.get(&signer.fingerprint)),
|
||||||
self.processing,
|
self.processing,
|
||||||
self.chosen_hw,
|
self.chosen_hw,
|
||||||
&self.signed,
|
&self.signed,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ pub fn hw_list_view(
|
|||||||
version,
|
version,
|
||||||
fingerprint,
|
fingerprint,
|
||||||
alias,
|
alias,
|
||||||
|
registered,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if chosen && processing {
|
if chosen && processing {
|
||||||
@ -28,6 +29,13 @@ pub fn hw_list_view(
|
|||||||
fingerprint,
|
fingerprint,
|
||||||
alias.as_ref(),
|
alias.as_ref(),
|
||||||
)
|
)
|
||||||
|
} else if *registered == Some(false) {
|
||||||
|
hw::unregistered_hardware_wallet(
|
||||||
|
kind,
|
||||||
|
version.as_ref(),
|
||||||
|
fingerprint,
|
||||||
|
alias.as_ref(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
|
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ use liana_ui::{
|
|||||||
component::{
|
component::{
|
||||||
badge, button, card,
|
badge, button, card,
|
||||||
collapse::Collapse,
|
collapse::Collapse,
|
||||||
form, separation,
|
form, hw, separation,
|
||||||
text::{text, Text},
|
text::{text, Text},
|
||||||
},
|
},
|
||||||
icon, theme,
|
icon, theme,
|
||||||
@ -710,6 +710,7 @@ pub fn sign_action<'a>(
|
|||||||
warning: Option<&Error>,
|
warning: Option<&Error>,
|
||||||
hws: &'a [HardwareWallet],
|
hws: &'a [HardwareWallet],
|
||||||
signer: Option<Fingerprint>,
|
signer: Option<Fingerprint>,
|
||||||
|
signer_alias: Option<&'a String>,
|
||||||
processing: bool,
|
processing: bool,
|
||||||
chosen_hw: Option<usize>,
|
chosen_hw: Option<usize>,
|
||||||
signed: &[Fingerprint],
|
signed: &[Fingerprint],
|
||||||
@ -746,35 +747,11 @@ pub fn sign_action<'a>(
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
.push_maybe(signer.map(|fingerprint| {
|
.push_maybe(signer.map(|fingerprint| {
|
||||||
Button::new(
|
Button::new(if signed.contains(&fingerprint) {
|
||||||
Row::new()
|
hw::sign_success_hot_signer(fingerprint, signer_alias)
|
||||||
.align_items(Alignment::Center)
|
} else {
|
||||||
.push(
|
hw::hot_signer(fingerprint, signer_alias)
|
||||||
Column::new()
|
})
|
||||||
.width(Length::Fill)
|
|
||||||
.push(text("This computer").bold())
|
|
||||||
.push(
|
|
||||||
text(format!("fingerprint: {}", fingerprint))
|
|
||||||
.small(),
|
|
||||||
)
|
|
||||||
.spacing(5)
|
|
||||||
.width(Length::Fill),
|
|
||||||
)
|
|
||||||
.push_maybe(if signed.contains(&fingerprint) {
|
|
||||||
Some(
|
|
||||||
Row::new()
|
|
||||||
.align_items(Alignment::Center)
|
|
||||||
.spacing(5)
|
|
||||||
.push(
|
|
||||||
icon::circle_check_icon()
|
|
||||||
.style(color::legacy::SUCCESS),
|
|
||||||
)
|
|
||||||
.push(text("Signed").style(color::legacy::SUCCESS)),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.on_press(Message::Spend(SpendTxMessage::SelectHotSigner))
|
.on_press(Message::Spend(SpendTxMessage::SelectHotSigner))
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.style(theme::Button::Secondary)
|
.style(theme::Button::Secondary)
|
||||||
|
|||||||
@ -725,11 +725,9 @@ pub struct EditXpubModal {
|
|||||||
form_xpub: form::Value<String>,
|
form_xpub: form::Value<String>,
|
||||||
edit_name: bool,
|
edit_name: bool,
|
||||||
|
|
||||||
chosen_hw: Option<usize>,
|
|
||||||
hws: Vec<HardwareWallet>,
|
hws: Vec<HardwareWallet>,
|
||||||
|
hot_signer: Arc<Signer>,
|
||||||
signer: Arc<Signer>,
|
chosen_signer: Option<Fingerprint>,
|
||||||
chosen_signer: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditXpubModal {
|
impl EditXpubModal {
|
||||||
@ -742,7 +740,7 @@ impl EditXpubModal {
|
|||||||
network: Network,
|
network: Network,
|
||||||
account_indexes: HashMap<Fingerprint, ChildNumber>,
|
account_indexes: HashMap<Fingerprint, ChildNumber>,
|
||||||
keys_aliases: HashMap<Fingerprint, String>,
|
keys_aliases: HashMap<Fingerprint, String>,
|
||||||
signer: Arc<Signer>,
|
hot_signer: Arc<Signer>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
form_name: form::Value {
|
form_name: form::Value {
|
||||||
@ -757,14 +755,13 @@ impl EditXpubModal {
|
|||||||
account_indexes,
|
account_indexes,
|
||||||
path_index,
|
path_index,
|
||||||
key_index,
|
key_index,
|
||||||
chosen_hw: None,
|
|
||||||
processing: false,
|
processing: false,
|
||||||
hws: Vec::new(),
|
hws: Vec::new(),
|
||||||
error: None,
|
error: None,
|
||||||
network,
|
network,
|
||||||
edit_name: false,
|
edit_name: false,
|
||||||
chosen_signer: Some(signer.fingerprint()) == key.map(|k| k.master_fingerprint()),
|
chosen_signer: key.map(|k| k.master_fingerprint()),
|
||||||
signer,
|
hot_signer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn load(&self) -> Command<Message> {
|
fn load(&self) -> Command<Message> {
|
||||||
@ -790,7 +787,7 @@ impl DescriptorEditModal for EditXpubModal {
|
|||||||
..
|
..
|
||||||
}) = self.hws.get(i)
|
}) = self.hws.get(i)
|
||||||
{
|
{
|
||||||
self.chosen_hw = Some(i);
|
self.chosen_signer = Some(*fingerprint);
|
||||||
self.processing = true;
|
self.processing = true;
|
||||||
// If another account n exists, the key is retrieved for the account n+1
|
// If another account n exists, the key is retrieved for the account n+1
|
||||||
let account_index = self
|
let account_index = self
|
||||||
@ -815,10 +812,7 @@ impl DescriptorEditModal for EditXpubModal {
|
|||||||
Message::ConnectedHardwareWallets(hws) => {
|
Message::ConnectedHardwareWallets(hws) => {
|
||||||
self.hws = hws;
|
self.hws = hws;
|
||||||
if let Ok(key) = DescriptorPublicKey::from_str(&self.form_xpub.value) {
|
if let Ok(key) = DescriptorPublicKey::from_str(&self.form_xpub.value) {
|
||||||
self.chosen_hw = self
|
self.chosen_signer = Some(key.master_fingerprint());
|
||||||
.hws
|
|
||||||
.iter()
|
|
||||||
.position(|hw| hw.fingerprint() == Some(key.master_fingerprint()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Reload => {
|
Message::Reload => {
|
||||||
@ -826,10 +820,9 @@ impl DescriptorEditModal for EditXpubModal {
|
|||||||
return self.load();
|
return self.load();
|
||||||
}
|
}
|
||||||
Message::UseHotSigner => {
|
Message::UseHotSigner => {
|
||||||
self.chosen_hw = None;
|
let fingerprint = self.hot_signer.fingerprint();
|
||||||
self.chosen_signer = true;
|
self.chosen_signer = Some(fingerprint);
|
||||||
self.form_xpub.valid = true;
|
self.form_xpub.valid = true;
|
||||||
let fingerprint = self.signer.fingerprint();
|
|
||||||
if let Some(alias) = self.keys_aliases.get(&fingerprint) {
|
if let Some(alias) = self.keys_aliases.get(&fingerprint) {
|
||||||
self.form_name.valid = true;
|
self.form_name.valid = true;
|
||||||
self.form_name.value = alias.clone();
|
self.form_name.value = alias.clone();
|
||||||
@ -848,7 +841,7 @@ impl DescriptorEditModal for EditXpubModal {
|
|||||||
"[{}{}]{}",
|
"[{}{}]{}",
|
||||||
fingerprint,
|
fingerprint,
|
||||||
derivation_path.to_string().trim_start_matches('m'),
|
derivation_path.to_string().trim_start_matches('m'),
|
||||||
self.signer.get_extended_pubkey(&derivation_path)
|
self.hot_signer.get_extended_pubkey(&derivation_path)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Message::DefineDescriptor(message::DefineDescriptor::KeyModal(msg)) => match msg {
|
Message::DefineDescriptor(message::DefineDescriptor::KeyModal(msg)) => match msg {
|
||||||
@ -863,12 +856,12 @@ impl DescriptorEditModal for EditXpubModal {
|
|||||||
} else {
|
} else {
|
||||||
self.edit_name = true;
|
self.edit_name = true;
|
||||||
}
|
}
|
||||||
self.chosen_signer = false;
|
self.chosen_signer = None;
|
||||||
self.form_xpub.valid = true;
|
self.form_xpub.valid = true;
|
||||||
self.form_xpub.value = key.to_string();
|
self.form_xpub.value = key.to_string();
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.chosen_hw = None;
|
self.chosen_signer = None;
|
||||||
self.error = Some(e);
|
self.error = Some(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -944,8 +937,9 @@ impl DescriptorEditModal for EditXpubModal {
|
|||||||
&self.hws,
|
&self.hws,
|
||||||
self.error.as_ref(),
|
self.error.as_ref(),
|
||||||
self.processing,
|
self.processing,
|
||||||
self.chosen_hw,
|
|
||||||
self.chosen_signer,
|
self.chosen_signer,
|
||||||
|
&self.hot_signer,
|
||||||
|
self.keys_aliases.get(&self.hot_signer.fingerprint),
|
||||||
&self.form_xpub,
|
&self.form_xpub,
|
||||||
&self.form_name,
|
&self.form_name,
|
||||||
self.edit_name,
|
self.edit_name,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use iced::{alignment, Alignment, Length};
|
|||||||
|
|
||||||
use std::{collections::HashSet, str::FromStr};
|
use std::{collections::HashSet, str::FromStr};
|
||||||
|
|
||||||
use liana::miniscript::bitcoin;
|
use liana::miniscript::bitcoin::{self, util::bip32::Fingerprint};
|
||||||
use liana_ui::{
|
use liana_ui::{
|
||||||
color,
|
color,
|
||||||
component::{
|
component::{
|
||||||
@ -25,6 +25,7 @@ use crate::{
|
|||||||
message::{self, Message},
|
message::{self, Message},
|
||||||
prompt, Error,
|
prompt, Error,
|
||||||
},
|
},
|
||||||
|
signer::Signer,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@ -1236,8 +1237,9 @@ pub fn edit_key_modal<'a>(
|
|||||||
hws: &'a [HardwareWallet],
|
hws: &'a [HardwareWallet],
|
||||||
error: Option<&Error>,
|
error: Option<&Error>,
|
||||||
processing: bool,
|
processing: bool,
|
||||||
chosen_hw: Option<usize>,
|
chosen_signer: Option<Fingerprint>,
|
||||||
chosen_signer: bool,
|
signer: &Signer,
|
||||||
|
signer_alias: Option<&'a String>,
|
||||||
form_xpub: &form::Value<String>,
|
form_xpub: &form::Value<String>,
|
||||||
form_name: &'a form::Value<String>,
|
form_name: &'a form::Value<String>,
|
||||||
edit_name: bool,
|
edit_name: bool,
|
||||||
@ -1269,37 +1271,21 @@ pub fn edit_key_modal<'a>(
|
|||||||
col.push(hw_list_view(
|
col.push(hw_list_view(
|
||||||
i,
|
i,
|
||||||
hw,
|
hw,
|
||||||
Some(i) == chosen_hw,
|
hw.fingerprint() == chosen_signer,
|
||||||
processing,
|
processing,
|
||||||
!processing
|
!processing
|
||||||
&& Some(i) == chosen_hw
|
&& hw.fingerprint() == chosen_signer
|
||||||
&& form_xpub.valid
|
&& form_xpub.valid
|
||||||
&& !form_xpub.value.is_empty(),
|
&& !form_xpub.value.is_empty(),
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.push(
|
.push(
|
||||||
Button::new(
|
Button::new(if Some(signer.fingerprint) == chosen_signer {
|
||||||
Row::new()
|
hw::selected_hot_signer(signer.fingerprint, signer_alias)
|
||||||
.padding(5)
|
} else {
|
||||||
.width(Length::Fill)
|
hw::unselected_hot_signer(signer.fingerprint, signer_alias)
|
||||||
.align_items(Alignment::Center)
|
})
|
||||||
.push(
|
|
||||||
Column::new()
|
|
||||||
.spacing(5)
|
|
||||||
.push(text("This computer").bold())
|
|
||||||
.push(
|
|
||||||
text("Derive a key from a mnemonic stored on this computer").small(),
|
|
||||||
)
|
|
||||||
.width(Length::Fill),
|
|
||||||
)
|
|
||||||
.push_maybe(if chosen_signer {
|
|
||||||
Some(icon::circle_check_icon().style(color::legacy::SUCCESS))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.spacing(10),
|
|
||||||
)
|
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.on_press(Message::UseHotSigner)
|
.on_press(Message::UseHotSigner)
|
||||||
.style(theme::Button::Secondary),
|
.style(theme::Button::Secondary),
|
||||||
@ -1315,7 +1301,9 @@ pub fn edit_key_modal<'a>(
|
|||||||
.push(
|
.push(
|
||||||
form::Form::new("Extended public key", form_xpub, |msg| {
|
form::Form::new("Extended public key", form_xpub, |msg| {
|
||||||
Message::DefineDescriptor(
|
Message::DefineDescriptor(
|
||||||
message::DefineDescriptor::KeyModal(message::ImportKeyModal::XPubEdited(msg)),
|
message::DefineDescriptor::KeyModal(
|
||||||
|
message::ImportKeyModal::XPubEdited(msg),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.warning(if network == bitcoin::Network::Bitcoin {
|
.warning(if network == bitcoin::Network::Bitcoin {
|
||||||
@ -1349,9 +1337,9 @@ pub fn edit_key_modal<'a>(
|
|||||||
.push(text(&form_name.value)),
|
.push(text(&form_name.value)),
|
||||||
)
|
)
|
||||||
.push(button::border(Some(icon::pencil_icon()), "Edit").on_press(
|
.push(button::border(Some(icon::pencil_icon()), "Edit").on_press(
|
||||||
Message::DefineDescriptor(
|
Message::DefineDescriptor(message::DefineDescriptor::KeyModal(
|
||||||
message::DefineDescriptor::KeyModal(message::ImportKeyModal::EditName),
|
message::ImportKeyModal::EditName,
|
||||||
)
|
)),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
} else if !form_xpub.value.is_empty() && form_xpub.valid {
|
} else if !form_xpub.value.is_empty() && form_xpub.valid {
|
||||||
@ -1365,9 +1353,9 @@ pub fn edit_key_modal<'a>(
|
|||||||
)
|
)
|
||||||
.push(
|
.push(
|
||||||
form::Form::new("Alias", form_name, |msg| {
|
form::Form::new("Alias", form_name, |msg| {
|
||||||
Message::DefineDescriptor(
|
Message::DefineDescriptor(message::DefineDescriptor::KeyModal(
|
||||||
message::DefineDescriptor::KeyModal(message::ImportKeyModal::NameEdited(msg)),
|
message::ImportKeyModal::NameEdited(msg),
|
||||||
)
|
))
|
||||||
})
|
})
|
||||||
.warning("Please enter correct alias")
|
.warning("Please enter correct alias")
|
||||||
.size(20)
|
.size(20)
|
||||||
@ -1381,11 +1369,11 @@ pub fn edit_key_modal<'a>(
|
|||||||
if form_xpub.valid && !form_xpub.value.is_empty() && !form_name.value.is_empty()
|
if form_xpub.valid && !form_xpub.value.is_empty() && !form_name.value.is_empty()
|
||||||
{
|
{
|
||||||
button::primary(None, "Apply")
|
button::primary(None, "Apply")
|
||||||
.on_press(
|
.on_press(Message::DefineDescriptor(
|
||||||
Message::DefineDescriptor(
|
message::DefineDescriptor::KeyModal(
|
||||||
message::DefineDescriptor::KeyModal(message::ImportKeyModal::ConfirmXpub),
|
message::ImportKeyModal::ConfirmXpub,
|
||||||
)
|
),
|
||||||
)
|
))
|
||||||
.width(Length::Units(200))
|
.width(Length::Units(200))
|
||||||
} else {
|
} else {
|
||||||
button::primary(None, "Apply").width(Length::Units(100))
|
button::primary(None, "Apply").width(Length::Units(100))
|
||||||
|
|||||||
@ -15,7 +15,7 @@ use liana::{
|
|||||||
pub struct Signer {
|
pub struct Signer {
|
||||||
curve: secp256k1::Secp256k1<secp256k1::SignOnly>,
|
curve: secp256k1::Secp256k1<secp256k1::SignOnly>,
|
||||||
key: HotSigner,
|
key: HotSigner,
|
||||||
fingerprint: Fingerprint,
|
pub fingerprint: Fingerprint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Signer {
|
impl std::fmt::Debug for Signer {
|
||||||
|
|||||||
@ -235,3 +235,109 @@ pub fn unsupported_hardware_wallet<'a, T: 'a, K: Display, V: Display>(
|
|||||||
)
|
)
|
||||||
.padding(10)
|
.padding(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sign_success_hot_signer<'a, T: 'a, F: Display>(
|
||||||
|
fingerprint: F,
|
||||||
|
alias: Option<impl Into<Cow<'a, str>>>,
|
||||||
|
) -> Container<'a, T> {
|
||||||
|
container(
|
||||||
|
row(vec![
|
||||||
|
column(vec![
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push_maybe(alias.map(|a| text(a).bold()))
|
||||||
|
.push(text(format!("#{}", fingerprint)))
|
||||||
|
.into(),
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push(text("This computer").small())
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.width(Length::Fill)
|
||||||
|
.into(),
|
||||||
|
row(vec![
|
||||||
|
icon::circle_check_icon()
|
||||||
|
.style(color::legacy::SUCCESS)
|
||||||
|
.into(),
|
||||||
|
text("Signed").style(color::legacy::SUCCESS).into(),
|
||||||
|
])
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.spacing(5)
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.align_items(Alignment::Center),
|
||||||
|
)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn selected_hot_signer<'a, T: 'a, F: Display>(
|
||||||
|
fingerprint: F,
|
||||||
|
alias: Option<impl Into<Cow<'a, str>>>,
|
||||||
|
) -> Container<'a, T> {
|
||||||
|
container(
|
||||||
|
row(vec![
|
||||||
|
column(vec![
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push_maybe(alias.map(|a| text(a).bold()))
|
||||||
|
.push(text(format!("#{}", fingerprint)))
|
||||||
|
.into(),
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push(text("This computer").small())
|
||||||
|
.push(text("(A derived key from a mnemonic stored locally)").small())
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.width(Length::Fill)
|
||||||
|
.into(),
|
||||||
|
icon::circle_check_icon()
|
||||||
|
.style(color::legacy::SUCCESS)
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.align_items(Alignment::Center),
|
||||||
|
)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unselected_hot_signer<'a, T: 'a, F: Display>(
|
||||||
|
fingerprint: F,
|
||||||
|
alias: Option<impl Into<Cow<'a, str>>>,
|
||||||
|
) -> Container<'a, T> {
|
||||||
|
Container::new(
|
||||||
|
column(vec![
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push_maybe(alias.map(|a| text(a).bold()))
|
||||||
|
.push(text(format!("#{}", fingerprint)))
|
||||||
|
.into(),
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push(text("This computer").small())
|
||||||
|
.push(text("(A derived key from a mnemonic stored locally)").small())
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.width(Length::Fill),
|
||||||
|
)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hot_signer<'a, T: 'a, F: Display>(
|
||||||
|
fingerprint: F,
|
||||||
|
alias: Option<impl Into<Cow<'a, str>>>,
|
||||||
|
) -> Container<'a, T> {
|
||||||
|
Container::new(
|
||||||
|
column(vec![
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push_maybe(alias.map(|a| text(a).bold()))
|
||||||
|
.push(text(format!("#{}", fingerprint)))
|
||||||
|
.into(),
|
||||||
|
Row::new()
|
||||||
|
.spacing(5)
|
||||||
|
.push(text("This computer").small())
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.width(Length::Fill),
|
||||||
|
)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user