diff --git a/gui/src/app/state/coins.rs b/gui/src/app/state/coins.rs index f00f075c..dad584df 100644 --- a/gui/src/app/state/coins.rs +++ b/gui/src/app/state/coins.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::sync::Arc; use iced::{Command, Element}; @@ -17,21 +18,41 @@ pub struct CoinsPanel { impl CoinsPanel { pub fn new(coins: &[Coin], timelock: u32) -> Self { - Self { - coins: coins - .iter() - .filter_map(|coin| { - if coin.spend_info.is_none() { - Some(*coin) - } else { - None - } - }) - .collect(), + let mut panel = Self { + coins: Vec::new(), selected: Vec::new(), warning: None, timelock, - } + }; + panel.update_coins(coins); + panel + } + + fn update_coins(&mut self, coins: &[Coin]) { + self.coins = coins + .iter() + .filter_map(|coin| { + if coin.spend_info.is_none() { + Some(*coin) + } else { + None + } + }) + .collect(); + + self.coins + .sort_by(|a, b| match (a.block_height, b.block_height) { + (Some(a_height), Some(b_height)) => { + if a_height == b_height { + a.outpoint.vout.cmp(&b.outpoint.vout) + } else { + a_height.cmp(&b_height) + } + } + (None, Some(_)) => Ordering::Greater, + (Some(_), None) => Ordering::Less, + (None, None) => a.outpoint.vout.cmp(&b.outpoint.vout), + }) } } @@ -57,16 +78,7 @@ impl State for CoinsPanel { Ok(coins) => { self.selected = Vec::new(); self.warning = None; - self.coins = coins - .iter() - .filter_map(|coin| { - if coin.spend_info.is_none() { - Some(*coin) - } else { - None - } - }) - .collect(); + self.update_coins(&coins); } }, Message::View(view::Message::Select(i)) => { @@ -100,3 +112,61 @@ impl From for Box { Box::new(s) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::daemon::model::Coin; + use liana::miniscript::bitcoin; + use std::str::FromStr; + + #[test] + fn test_coins_panel_update_coins() { + let mut panel = CoinsPanel::new(&[], 0); + let txid = bitcoin::Txid::from_str( + "f7bd1b2a995b689d326e51eb742eb1088c4a8f110d9cb56128fd553acc9f88e5", + ) + .unwrap(); + + panel.update_coins(&[ + Coin { + outpoint: bitcoin::OutPoint { txid, vout: 2 }, + amount: bitcoin::Amount::from_sat(1), + block_height: Some(3), + spend_info: None, + }, + Coin { + outpoint: bitcoin::OutPoint { txid, vout: 3 }, + amount: bitcoin::Amount::from_sat(1), + block_height: None, + spend_info: None, + }, + Coin { + outpoint: bitcoin::OutPoint { txid, vout: 0 }, + amount: bitcoin::Amount::from_sat(1), + block_height: Some(2), + spend_info: None, + }, + Coin { + outpoint: bitcoin::OutPoint { txid, vout: 1 }, + amount: bitcoin::Amount::from_sat(1), + block_height: Some(3), + spend_info: None, + }, + ]); + + assert_eq!( + panel + .coins + .iter() + .map(|c| c.outpoint) + .collect::>(), + vec![ + bitcoin::OutPoint { txid, vout: 0 }, + bitcoin::OutPoint { txid, vout: 1 }, + bitcoin::OutPoint { txid, vout: 2 }, + bitcoin::OutPoint { txid, vout: 3 }, + ] + ) + } +}