From 1a370d380655b0cf852f2a51688cd15a327e1d7e Mon Sep 17 00:00:00 2001 From: edouardparis Date: Fri, 20 Sep 2024 14:32:35 +0200 Subject: [PATCH] fix history events and txs pagination The problem: We display the button if the size of the list is a multiple of the page size. Otherwise, we assume that the user has reached a partial page, indicating they've reached the bottom. However, since we chose to include all transactions with the same block time on a single page (because it's not possible to order them by block index in the database, as we don't store the block index), this can cause the page size to exceed the set limit. As a result, the list size may not be a multiple of the page size. The solution: keep in the state if the last fetched page has a length inferior of the expected page size and do not display the button 'See more' then as we reached the bottom. --- gui/src/app/state/mod.rs | 13 ++++++++--- gui/src/app/state/transactions.rs | 23 +++++++++++++++---- gui/src/app/view/home.rs | 37 ++++++++++++++----------------- gui/src/app/view/transactions.rs | 37 ++++++++++++++----------------- 4 files changed, 63 insertions(+), 47 deletions(-) diff --git a/gui/src/app/state/mod.rs b/gui/src/app/state/mod.rs index a7a9c4d1..97392b44 100644 --- a/gui/src/app/state/mod.rs +++ b/gui/src/app/state/mod.rs @@ -21,6 +21,8 @@ use liana_ui::widget::*; use super::{cache::Cache, error::Error, menu::Menu, message::Message, view, wallet::Wallet}; +pub const HISTORY_EVENT_PAGE_SIZE: u64 = 20; + use crate::daemon::{ model::{remaining_sequence, Coin, HistoryTransaction, Labelled}, Daemon, @@ -72,6 +74,7 @@ pub struct Home { expiring_coins: Vec, pending_events: Vec, events: Vec, + is_last_page: bool, selected_event: Option<(usize, usize)>, labels_edited: LabelsEdited, warning: Option, @@ -102,6 +105,7 @@ impl Home { pending_events: Vec::new(), labels_edited: LabelsEdited::default(), warning: None, + is_last_page: false, } } } @@ -133,6 +137,7 @@ impl State for Home { &self.expiring_coins, &self.pending_events, &self.events, + self.is_last_page, ), ) } @@ -185,12 +190,14 @@ impl State for Home { self.warning = None; self.events = events; self.events.sort_by(|a, b| b.time.cmp(&a.time)); + self.is_last_page = (self.events.len() as u64) < HISTORY_EVENT_PAGE_SIZE; } }, Message::HistoryTransactionsExtension(res) => match res { Err(e) => self.warning = Some(e), Ok(events) => { self.warning = None; + self.is_last_page = (events.len() as u64) < HISTORY_EVENT_PAGE_SIZE; for event in events { if !self.events.iter().any(|other| other.tx == event.tx) { self.events.push(event); @@ -238,7 +245,7 @@ impl State for Home { let last_event_date = last.time.unwrap(); return Command::perform( async move { - let mut limit = view::home::HISTORY_EVENT_PAGE_SIZE; + let mut limit = HISTORY_EVENT_PAGE_SIZE; let mut events = daemon .list_history_txs(0_u32, last_event_date, limit) .await?; @@ -262,7 +269,7 @@ impl State for Home { && events.len() as u64 == limit { // increments of the equivalent of one page more. - limit += view::home::HISTORY_EVENT_PAGE_SIZE; + limit += HISTORY_EVENT_PAGE_SIZE; events = daemon.list_history_txs(0, last_event_date, limit).await?; } Ok(events) @@ -300,7 +307,7 @@ impl State for Home { Command::perform( async move { daemon1 - .list_history_txs(0, now, view::home::HISTORY_EVENT_PAGE_SIZE) + .list_history_txs(0, now, HISTORY_EVENT_PAGE_SIZE) .await .map_err(|e| e.into()) }, diff --git a/gui/src/app/state/transactions.rs b/gui/src/app/state/transactions.rs index aa1a62d2..bb9e3eec 100644 --- a/gui/src/app/state/transactions.rs +++ b/gui/src/app/state/transactions.rs @@ -16,6 +16,8 @@ use liana_ui::{ widget::*, }; +pub const HISTORY_EVENT_PAGE_SIZE: u64 = 20; + use crate::{ app::{ cache::Cache, @@ -41,6 +43,7 @@ pub struct TransactionsPanel { selected_tx: Option, warning: Option, create_rbf_modal: Option, + is_last_page: bool, } impl TransactionsPanel { @@ -53,6 +56,7 @@ impl TransactionsPanel { labels_edited: LabelsEdited::default(), warning: None, create_rbf_modal: None, + is_last_page: false, } } @@ -83,6 +87,7 @@ impl State for TransactionsPanel { &self.pending_txs, &self.txs, self.warning.as_ref(), + self.is_last_page, ) } } @@ -98,6 +103,16 @@ impl State for TransactionsPanel { Err(e) => self.warning = Some(e), Ok(txs) => { self.warning = None; + self.txs = txs; + self.is_last_page = (self.txs.len() as u64) < HISTORY_EVENT_PAGE_SIZE; + self.txs.sort_by(|a, b| b.time.cmp(&a.time)); + } + }, + Message::HistoryTransactionsExtension(res) => match res { + Err(e) => self.warning = Some(e), + Ok(txs) => { + self.warning = None; + self.is_last_page = (txs.len() as u64) < HISTORY_EVENT_PAGE_SIZE; for tx in txs { if let Some(t) = self.txs.iter_mut().find(|other| other.tx == tx.tx) { t.labels = tx.labels; @@ -204,7 +219,7 @@ impl State for TransactionsPanel { let last_tx_date = last.time.unwrap(); return Command::perform( async move { - let mut limit = view::home::HISTORY_EVENT_PAGE_SIZE; + let mut limit = HISTORY_EVENT_PAGE_SIZE; let mut txs = daemon.list_history_txs(0_u32, last_tx_date, limit).await?; @@ -227,12 +242,12 @@ impl State for TransactionsPanel { && txs.len() as u64 == limit { // increments of the equivalent of one page more. - limit += view::home::HISTORY_EVENT_PAGE_SIZE; + limit += HISTORY_EVENT_PAGE_SIZE; txs = daemon.list_history_txs(0, last_tx_date, limit).await?; } Ok(txs) }, - Message::HistoryTransactions, + Message::HistoryTransactionsExtension, ); } } @@ -267,7 +282,7 @@ impl State for TransactionsPanel { Command::perform( async move { daemon1 - .list_history_txs(0, now, view::home::HISTORY_EVENT_PAGE_SIZE) + .list_history_txs(0, now, HISTORY_EVENT_PAGE_SIZE) .await .map_err(|e| e.into()) }, diff --git a/gui/src/app/view/home.rs b/gui/src/app/view/home.rs index 7adc4f90..235eb4ce 100644 --- a/gui/src/app/view/home.rs +++ b/gui/src/app/view/home.rs @@ -21,8 +21,6 @@ use crate::{ daemon::model::{HistoryTransaction, TransactionKind}, }; -pub const HISTORY_EVENT_PAGE_SIZE: u64 = 20; - pub fn home_view<'a>( balance: &'a bitcoin::Amount, unconfirmed_balance: &'a bitcoin::Amount, @@ -30,6 +28,7 @@ pub fn home_view<'a>( expiring_coins: &[bitcoin::OutPoint], pending_events: &'a [HistoryTransaction], events: &'a [HistoryTransaction], + is_last_page: bool, ) -> Element<'a, Message> { Column::new() .push(h3("Balance")) @@ -119,27 +118,25 @@ pub fn home_view<'a>( } }, )) - .push_maybe( - if events.len() % HISTORY_EVENT_PAGE_SIZE as usize == 0 && !events.is_empty() { - Some( - Container::new( - Button::new( - text("See more") - .width(Length::Fill) - .horizontal_alignment(alignment::Horizontal::Center), - ) - .width(Length::Fill) - .padding(15) - .style(theme::Button::TransparentBorder) - .on_press(Message::Next), + .push_maybe(if !is_last_page && !events.is_empty() { + Some( + Container::new( + Button::new( + text("See more") + .width(Length::Fill) + .horizontal_alignment(alignment::Horizontal::Center), ) .width(Length::Fill) - .style(theme::Container::Card(theme::Card::Simple)), + .padding(15) + .style(theme::Button::TransparentBorder) + .on_press(Message::Next), ) - } else { - None - }, - ), + .width(Length::Fill) + .style(theme::Container::Card(theme::Card::Simple)), + ) + } else { + None + }), ) .spacing(20) .into() diff --git a/gui/src/app/view/transactions.rs b/gui/src/app/view/transactions.rs index f1e1437d..e1958f91 100644 --- a/gui/src/app/view/transactions.rs +++ b/gui/src/app/view/transactions.rs @@ -20,13 +20,12 @@ use crate::{ daemon::model::{HistoryTransaction, Txid}, }; -pub const HISTORY_EVENT_PAGE_SIZE: u64 = 20; - pub fn transactions_view<'a>( cache: &'a Cache, pending_txs: &'a [HistoryTransaction], txs: &'a [HistoryTransaction], warning: Option<&'a Error>, + is_last_page: bool, ) -> Element<'a, Message> { dashboard( &Menu::Transactions, @@ -56,27 +55,25 @@ pub fn transactions_view<'a>( col.push(tx_list_view(i + pending_txs.len(), tx)) }), ) - .push_maybe( - if txs.len() % HISTORY_EVENT_PAGE_SIZE as usize == 0 && !txs.is_empty() { - Some( - Container::new( - Button::new( - text("See more") - .width(Length::Fill) - .horizontal_alignment(alignment::Horizontal::Center), - ) - .width(Length::Fill) - .padding(15) - .style(theme::Button::TransparentBorder) - .on_press(Message::Next), + .push_maybe(if !is_last_page && !txs.is_empty() { + Some( + Container::new( + Button::new( + text("See more") + .width(Length::Fill) + .horizontal_alignment(alignment::Horizontal::Center), ) .width(Length::Fill) - .style(theme::Container::Card(theme::Card::Simple)), + .padding(15) + .style(theme::Button::TransparentBorder) + .on_press(Message::Next), ) - } else { - None - }, - ), + .width(Length::Fill) + .style(theme::Container::Card(theme::Card::Simple)), + ) + } else { + None + }), ) .align_items(Alignment::Center) .spacing(30),