Skip to content

Commit f5a1551

Browse files
committed
Merge #997: gui: add transaction redirection
0c1a1b8 gui: add redirection to selected transaction panel (edouardparis) Pull request description: based on #959 This PR removes the payment section about the transaction inputs outputs for a redirection to the payment transaction (The `See transaction details` button). It makes it easy to fee bump a payment by clicking on it to be redirected to the transaction to rbf ![20240305_18h13m51s_grim](https://github.com/wizardsardine/liana/assets/6933020/bbb21e84-9fb6-4eed-ba93-2c4f6177cb95) Maybe the UX/UI of the payment should be changed to remove more transaction information, but I fear it makes the panel a little bit empty. ACKs for top commit: jp1ac4: ACK 0c1a1b8. Tree-SHA512: f767b1cbf86cafcd0b46e5dfc0625f15719b48314de93418b73e59bd32e6dc659ab2ea3a4e2d379680c4209bfbd633c5329fe9fa2616c042dd2851f62f860498
2 parents 505b218 + 0c1a1b8 commit f5a1551

File tree

5 files changed

+93
-61
lines changed

5 files changed

+93
-61
lines changed

gui/src/app/menu.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub enum Menu {
55
Receive,
66
PSBTs,
77
Transactions,
8+
TransactionPreSelected(Txid),
89
Settings,
910
Coins,
1011
CreateSpendTx,

gui/src/app/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl Panels {
8484
Menu::Receive => &self.receive,
8585
Menu::PSBTs => &self.psbts,
8686
Menu::Transactions => &self.transactions,
87+
Menu::TransactionPreSelected(_) => &self.transactions,
8788
Menu::Settings => &self.settings,
8889
Menu::Coins => &self.coins,
8990
Menu::CreateSpendTx => &self.create_spend,
@@ -99,6 +100,7 @@ impl Panels {
99100
Menu::Receive => &mut self.receive,
100101
Menu::PSBTs => &mut self.psbts,
101102
Menu::Transactions => &mut self.transactions,
103+
Menu::TransactionPreSelected(_) => &mut self.transactions,
102104
Menu::Settings => &mut self.settings,
103105
Menu::Coins => &mut self.coins,
104106
Menu::CreateSpendTx => &mut self.create_spend,
@@ -152,6 +154,17 @@ impl App {
152154

153155
fn set_current_panel(&mut self, menu: Menu) -> Command<Message> {
154156
match &menu {
157+
menu::Menu::TransactionPreSelected(txid) => {
158+
if let Ok(Some(tx)) = self
159+
.daemon
160+
.get_history_txs(&[*txid])
161+
.map(|txs| txs.first().cloned())
162+
{
163+
self.panels.transactions.preselect(tx);
164+
self.panels.current = menu;
165+
return Command::none();
166+
};
167+
}
155168
menu::Menu::PsbtPreSelected(txid) => {
156169
// Get preselected spend from DB in case it's not yet in the cache.
157170
// We only need this single spend as we will go straight to its view and not show the PSBTs list.

gui/src/app/state/transactions.rs

+39-36
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub struct TransactionsPanel {
3636
pending_txs: Vec<HistoryTransaction>,
3737
txs: Vec<HistoryTransaction>,
3838
labels_edited: LabelsEdited,
39-
selected_tx: Option<usize>,
39+
selected_tx: Option<HistoryTransaction>,
4040
warning: Option<Error>,
4141
create_rbf_modal: Option<CreateRbfModal>,
4242
}
@@ -52,16 +52,17 @@ impl TransactionsPanel {
5252
create_rbf_modal: None,
5353
}
5454
}
55+
56+
pub fn preselect(&mut self, tx: HistoryTransaction) {
57+
self.selected_tx = Some(tx);
58+
self.warning = None;
59+
self.create_rbf_modal = None;
60+
}
5561
}
5662

5763
impl State for TransactionsPanel {
5864
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
59-
if let Some(i) = self.selected_tx {
60-
let tx = if i < self.pending_txs.len() {
61-
&self.pending_txs[i]
62-
} else {
63-
&self.txs[i - self.pending_txs.len()]
64-
};
65+
if let Some(tx) = self.selected_tx.as_ref() {
6566
let content = view::transactions::tx_view(
6667
cache,
6768
tx,
@@ -121,40 +122,42 @@ impl State for TransactionsPanel {
121122
return self.reload(daemon);
122123
}
123124
Message::View(view::Message::Select(i)) => {
124-
self.selected_tx = Some(i);
125+
self.selected_tx = if i < self.pending_txs.len() {
126+
self.pending_txs.get(i).cloned()
127+
} else {
128+
self.txs.get(i - self.pending_txs.len()).cloned()
129+
};
125130
}
126131
Message::View(view::Message::CreateRbf(view::CreateRbfMessage::Cancel)) => {
127132
self.create_rbf_modal = None;
128133
}
129134
Message::View(view::Message::CreateRbf(view::CreateRbfMessage::New(is_cancel))) => {
130-
if let Some(idx) = self.selected_tx {
131-
if let Some(tx) = self.pending_txs.get(idx) {
132-
if tx.fee_amount.is_some() {
133-
let tx = tx.clone();
134-
let txid = tx.tx.txid();
135-
return Command::perform(
136-
async move {
137-
daemon
138-
// TODO: filter for spending coins when this is possible:
139-
// https://github.com/wizardsardine/liana/issues/677
140-
.list_coins()
141-
.map(|res| {
142-
res.coins
143-
.iter()
144-
.filter_map(|c| {
145-
if c.outpoint.txid == txid {
146-
c.spend_info.map(|info| info.txid)
147-
} else {
148-
None
149-
}
150-
})
151-
.collect()
152-
})
153-
.map_err(|e| e.into())
154-
},
155-
move |res| Message::RbfModal(tx, is_cancel, res),
156-
);
157-
}
135+
if let Some(tx) = &self.selected_tx {
136+
if tx.fee_amount.is_some() {
137+
let tx = tx.clone();
138+
let txid = tx.tx.txid();
139+
return Command::perform(
140+
async move {
141+
daemon
142+
// TODO: filter for spending coins when this is possible:
143+
// https://github.com/wizardsardine/liana/issues/677
144+
.list_coins()
145+
.map(|res| {
146+
res.coins
147+
.iter()
148+
.filter_map(|c| {
149+
if c.outpoint.txid == txid {
150+
c.spend_info.map(|info| info.txid)
151+
} else {
152+
None
153+
}
154+
})
155+
.collect()
156+
})
157+
.map_err(|e| e.into())
158+
},
159+
move |res| Message::RbfModal(tx, is_cancel, res),
160+
);
158161
}
159162
}
160163
}

gui/src/app/view/home.rs

+2-25
Original file line numberDiff line numberDiff line change
@@ -315,31 +315,8 @@ pub fn payment_view<'a>(
315315
.spacing(5),
316316
))
317317
.push(
318-
Column::new()
319-
.spacing(20)
320-
// We do not need to display inputs for external incoming transactions
321-
.push_maybe(if tx.is_external() {
322-
None
323-
} else {
324-
Some(super::psbt::inputs_view(
325-
&tx.coins,
326-
&tx.tx,
327-
&tx.labels,
328-
labels_editing,
329-
))
330-
})
331-
.push(super::psbt::outputs_view(
332-
&tx.tx,
333-
cache.network,
334-
if tx.is_external() {
335-
None
336-
} else {
337-
Some(tx.change_indexes.clone())
338-
},
339-
&tx.labels,
340-
labels_editing,
341-
tx.is_single_payment().is_some(),
342-
)),
318+
button::primary(None, "See transaction details")
319+
.on_press(Message::Menu(Menu::TransactionPreSelected(tx.tx.txid()))),
343320
)
344321
.spacing(20),
345322
)

gui/src/daemon/mod.rs

+38
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,44 @@ pub trait Daemon: Debug {
184184
Ok(txs)
185185
}
186186

187+
fn get_history_txs(
188+
&self,
189+
txids: &[Txid],
190+
) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
191+
let info = self.get_info()?;
192+
let coins = self.list_coins()?.coins;
193+
let txs = self.list_txs(txids)?.transactions;
194+
let mut txs = txs
195+
.into_iter()
196+
.map(|tx| {
197+
let mut tx_coins = Vec::new();
198+
let mut change_indexes = Vec::new();
199+
for coin in &coins {
200+
if coin.outpoint.txid == tx.tx.txid() {
201+
change_indexes.push(coin.outpoint.vout as usize)
202+
} else if tx
203+
.tx
204+
.input
205+
.iter()
206+
.any(|input| input.previous_output == coin.outpoint)
207+
{
208+
tx_coins.push(coin.clone());
209+
}
210+
}
211+
model::HistoryTransaction::new(
212+
tx.tx,
213+
tx.height,
214+
tx.time,
215+
tx_coins,
216+
change_indexes,
217+
info.network,
218+
)
219+
})
220+
.collect();
221+
load_labels(self, &mut txs)?;
222+
Ok(txs)
223+
}
224+
187225
fn list_pending_txs(&self) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
188226
let info = self.get_info()?;
189227
let coins = self.list_coins()?.coins;

0 commit comments

Comments
 (0)