Merge #314: gui: change path signature details

56d3522f8c74ff774cb3ecdbf76b48dd216497f9 gui: change path signature details (edouard)

Pull request description:

  ![2023-02-03T21:50:42,669968940+01:00](https://user-images.githubusercontent.com/6933020/216709669-81b18325-60ad-469f-a506-6717e997e72a.png)
  ![2023-02-03T21:50:50,459471889+01:00](https://user-images.githubusercontent.com/6933020/216709675-f48041dc-1e17-4723-9d24-0f65cd896cfa.png)
  ![2023-02-03T21:58:48,281389762+01:00](https://user-images.githubusercontent.com/6933020/216709676-977c845e-f1c2-4a6c-9e9c-49c345d20cf1.png)

ACKs for top commit:
  edouardparis:
    Self-ACK 56d3522f8c74ff774cb3ecdbf76b48dd216497f9

Tree-SHA512: 72c0ee502f8f8475b38cf3ee6619e02f9a0920373cc1542cdd37f7d79f83ac489cef444c1f4f79df45ffca4e8b3a1857606994392238ec77a8457d0af117ea63
This commit is contained in:
edouard 2023-02-06 11:53:46 +01:00
commit 66e37a2cdf
No known key found for this signature in database
GPG Key ID: E65F7A089C20DC8F
3 changed files with 109 additions and 71 deletions

View File

@ -287,26 +287,54 @@ pub fn signatures<'a>(
keys_aliases: &'a HashMap<Fingerprint, String>,
) -> Element<'a, Message> {
Column::new()
.push(Collapse::new(
.push(
if let Some(sigs) = tx.path_ready() {
Container::new(
Scrollable::new(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::SUCCESS))
.push(text("Ready").bold().style(color::SUCCESS))
.push(text(", signed by"))
.push(
sigs.signed_pubkeys
.keys()
.fold(Row::new().spacing(5), |row, value| {
row.push(if let Some(alias) = keys_aliases.get(value) {
Container::new(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(3)
.style(badge::PillStyle::Simple),
value.to_string(),
tooltip::Position::Bottom,
)
.style(card::SimpleCardStyle),
)
} else {
Container::new(text(value.to_string()))
.padding(3)
.style(badge::PillStyle::Simple)
})
}),
)
).horizontal_scroll(scrollable::Properties::new().width(2).scroller_width(2))
).padding(15)
} else{
Container::new(
Collapse::new(
move || {
Button::new(
Row::new()
.align_items(Alignment::Center)
.push(if tx.is_ready() {
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::SUCCESS))
.push(text("Ready").bold().style(color::SUCCESS))
.width(Length::Fill)
} else {
Row::new()
.push(Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon())
.push(text("Not ready").bold())
.width(Length::Fill)
})
)
.push(icon::collapse_icon()),
)
.padding(15)
@ -317,21 +345,14 @@ pub fn signatures<'a>(
Button::new(
Row::new()
.align_items(Alignment::Center)
.push(if tx.is_ready() {
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_check_icon().style(color::SUCCESS))
.push(text("Ready").bold().style(color::SUCCESS))
.width(Length::Fill)
} else {
.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(icon::circle_cross_icon())
.push(text("Not ready").bold())
.width(Length::Fill)
})
)
.push(icon::collapsed_icon()),
)
.padding(15)
@ -344,6 +365,11 @@ pub fn signatures<'a>(
Column::new()
.padding(15)
.spacing(10)
.push(text(if tx.sigs.recovery_path().is_some() {
"2 spending paths available. Finalizing this transaction requires either:"
} else {
"1 spending path available. Finalizing this transaction requires:"
}))
.push(path_view(
desc_info.primary_path(),
tx.sigs.primary_path(),
@ -356,14 +382,14 @@ pub fn signatures<'a>(
),
)
},
))
))})
.push_maybe(if tx.status == SpendStatus::Pending {
Some(
Column::new().push(separation().width(Length::Fill)).push(
Container::new(
Row::new()
.push(Space::with_width(Length::Fill))
.push_maybe(if !tx.is_ready() {
.push_maybe(if tx.path_ready().is_some() {
Some(
button::primary(None, "Sign")
.on_press(Message::Spend(SpendTxMessage::Sign))
@ -394,29 +420,62 @@ pub fn path_view<'a>(
key_aliases: &'a HashMap<Fingerprint, String>,
) -> Element<'a, Message> {
let mut keys: Vec<Fingerprint> = path.thresh_fingerprints().1.into_iter().collect();
let missing_signatures = if sigs.sigs_count >= sigs.threshold {
0
} else {
sigs.threshold - sigs.sigs_count
};
keys.sort();
Scrollable::new(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(if sigs.signed_pubkeys.len() >= sigs.threshold {
.push(if sigs.sigs_count >= sigs.threshold {
icon::circle_check_icon().style(color::SUCCESS)
} else {
icon::circle_cross_icon()
})
.push(
Container::new(text(format!(" {} ", sigs.threshold))).style(
if sigs.signed_pubkeys.len() >= sigs.threshold {
badge::PillStyle::Success
} else {
badge::PillStyle::Simple
},
),
)
.push(text(format!(" {}", missing_signatures)).bold())
.push(text(format!(
"signature{} out of",
if sigs.threshold > 1 { "s" } else { "" }
" more signature{}",
if missing_signatures > 1 {
"s from "
} else if missing_signatures == 0 {
""
} else {
" from "
}
)))
.push_maybe(if keys.is_empty() {
None
} else {
Some(keys.iter().fold(Row::new().spacing(5), |row, &value| {
row.push_maybe(if !sigs.signed_pubkeys.contains_key(&value) {
Some(if let Some(alias) = key_aliases.get(&value) {
Container::new(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(3)
.style(badge::PillStyle::Simple),
value.to_string(),
tooltip::Position::Bottom,
)
.style(card::SimpleCardStyle),
)
} else {
Container::new(text(value.to_string()))
.padding(3)
.style(badge::PillStyle::Simple)
})
} else {
None
})
}))
})
.push_maybe(if sigs.signed_pubkeys.is_empty() {
None
} else {
Some(text(", already signed by "))
})
.push(
sigs.signed_pubkeys
.keys()
@ -426,7 +485,7 @@ pub fn path_view<'a>(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(3)
.style(badge::PillStyle::Success),
.style(badge::PillStyle::Simple),
value.to_string(),
tooltip::Position::Bottom,
)
@ -435,32 +494,10 @@ pub fn path_view<'a>(
} else {
Container::new(text(value.to_string()))
.padding(3)
.style(badge::PillStyle::Success)
.style(badge::PillStyle::Simple)
})
}),
)
.push(keys.iter().fold(Row::new().spacing(5), |row, &value| {
row.push_maybe(if !sigs.signed_pubkeys.contains_key(&value) {
Some(if let Some(alias) = key_aliases.get(&value) {
Container::new(
tooltip::Tooltip::new(
Container::new(text(alias))
.padding(3)
.style(badge::PillStyle::Simple),
value.to_string(),
tooltip::Position::Bottom,
)
.style(card::SimpleCardStyle),
)
} else {
Container::new(text(value.to_string()))
.padding(3)
.style(badge::PillStyle::Simple)
})
} else {
None
})
})),
),
)
.horizontal_scroll(scrollable::Properties::new().width(2).scroller_width(2))
.into()

View File

@ -121,8 +121,8 @@ fn spend_tx_list_view<'a>(i: usize, tx: &SpendTx) -> Element<'a, Message> {
.align_items(Alignment::Center)
.push(text(format!(
"{}/{}",
if sigs.signed_pubkeys.len() <= sigs.threshold {
sigs.signed_pubkeys.len()
if sigs.sigs_count <= sigs.threshold {
sigs.sigs_count
} else {
sigs.threshold
},
@ -142,8 +142,8 @@ fn spend_tx_list_view<'a>(i: usize, tx: &SpendTx) -> Element<'a, Message> {
.align_items(Alignment::Center)
.push(text(format!(
"{}/{}",
if sigs.signed_pubkeys.len() <= sigs.threshold {
sigs.signed_pubkeys.len()
if sigs.sigs_count <= sigs.threshold {
sigs.sigs_count
} else {
sigs.threshold
},

View File

@ -3,7 +3,7 @@ pub use liana::{
CreateSpendResult, GetAddressResult, GetInfoResult, ListCoinsEntry, ListCoinsResult,
ListSpendEntry, ListSpendResult, ListTransactionsResult, TransactionInfo,
},
descriptors::PartialSpendInfo,
descriptors::{PartialSpendInfo, PathSpendInfo},
miniscript::bitcoin::{util::psbt::Psbt, Amount, Transaction},
};
@ -78,17 +78,18 @@ impl SpendTx {
}
}
pub fn is_ready(&self) -> bool {
/// Returns the path ready if it exists.
pub fn path_ready(&self) -> Option<&PathSpendInfo> {
let path = self.sigs.primary_path();
if path.signed_pubkeys.len() >= path.threshold {
return true;
if path.sigs_count >= path.threshold {
return Some(path);
}
if let Some(path) = self.sigs.recovery_path() {
if path.signed_pubkeys.len() >= path.threshold {
return true;
if path.sigs_count >= path.threshold {
return Some(path);
}
}
false
None
}
}