diff options
Diffstat (limited to 'schist_desktop_gui/src/gui/components/transactions_view.rs')
| -rw-r--r-- | schist_desktop_gui/src/gui/components/transactions_view.rs | 271 |
1 files changed, 62 insertions, 209 deletions
diff --git a/schist_desktop_gui/src/gui/components/transactions_view.rs b/schist_desktop_gui/src/gui/components/transactions_view.rs index a52c419..5627e71 100644 --- a/schist_desktop_gui/src/gui/components/transactions_view.rs +++ b/schist_desktop_gui/src/gui/components/transactions_view.rs @@ -1,24 +1,27 @@ -mod view_transactions_view; - -use std::collections::{HashMap, VecDeque}; +use iced::{ + alignment, + widget::{row, Container}, + Element, Length, +}; -use iced::font; -use itertools::Itertools; -use schist_models::{Account, AccountTransfer, Bucket, DateUtc, Transaction}; +use schist_models::{Account, AccountTransfer, Bucket, Transaction}; use crate::{ - gui::components::{navigation, AccountNavigationEntry, Navigation}, - traits::Component, + gui::components::{ + AccountNavigationEntry, + Navigation, + TransactionsTable, + navigation, + transactions_table + }, + traits::{Component, Viewable}, + style::SPACING_LG, }; #[derive(Clone, Debug)] pub struct TransactionsView { - accounts: Vec<Account>, - account_transfers: Vec<AccountTransfer>, - buckets: Vec<Bucket>, navigation: Navigation<AccountNavigationEntry>, - transactions: Vec<Transaction>, - transaction_rows_by_account_id: HashMap<i32, Vec<TransactionRow>>, + transactions_table: TransactionsTable, } #[derive(Clone, Debug)] @@ -30,133 +33,13 @@ pub enum Message { SetAccountTransfers(Vec<AccountTransfer>), SetBuckets(Vec<Bucket>), SetTransactions(Vec<Transaction>), + TransactionsTableMessage(transactions_table::Message), } pub enum Action { None, } -#[derive(Debug, PartialEq, Eq)] -struct TransactionRowWithoutAggregations { - amount: i32, - bucket: String, - bucket_font_style: font::Style, - date: DateUtc, - payee: String, - payee_font_style: font::Style, -} - -impl TransactionRowWithoutAggregations { - fn from_transaction( - account_id: i32, - transaction: &Transaction, - buckets: &[Bucket], - ) -> Option<Self> { - if transaction.account_id == account_id { - let (bucket, bucket_font_style) = match transaction.bucket_id { - Some(bucket_id) => match buckets.iter().find(|b| b.id == bucket_id) { - Some(bucket) => (bucket.name.clone(), font::Style::Normal), - None => (format!("Bucket <{}>", bucket_id), font::Style::Italic), - }, - None => (String::from("None"), font::Style::Italic), - }; - Some(Self { - amount: transaction.amount, - bucket, - bucket_font_style, - date: transaction.date, - payee: transaction.counterparty.clone(), - payee_font_style: font::Style::Normal, - }) - } else { - None - } - } - - fn from_account_transfer( - account_id: i32, - account_transfer: &AccountTransfer, - accounts: &[Account], - ) -> Option<Self> { - if account_transfer.from_account_id == account_id { - let (payee, payee_font_style) = if let Some(account) = accounts - .iter() - .find(|a| a.id == account_transfer.to_account_id) - { - (account.name.clone(), font::Style::Normal) - } else { - (format!("<{}>", account_id), font::Style::Italic) - }; - Some(Self { - amount: -account_transfer.amount, - bucket: String::from("Account transfer"), - bucket_font_style: font::Style::Italic, - date: account_transfer.date, - payee, - payee_font_style, - }) - } else if account_transfer.to_account_id == account_id { - let (payee, payee_font_style) = if let Some(account) = accounts - .iter() - .find(|a| a.id == account_transfer.from_account_id) - { - (account.name.clone(), font::Style::Normal) - } else { - (format!("Account <{}>", account_id), font::Style::Italic) - }; - Some(Self { - amount: account_transfer.amount, - bucket: String::from("Account transfer"), - bucket_font_style: font::Style::Italic, - date: account_transfer.date, - payee, - payee_font_style, - }) - } else { - None - } - } - - fn with_aggregations(self, balance: i32) -> TransactionRow { - TransactionRow { - amount: self.amount, - balance, - bucket: self.bucket, - bucket_font_style: self.bucket_font_style, - date: self.date, - payee: self.payee, - payee_font_style: self.payee_font_style, - } - } - - fn compare_date_desc(&self, other: &Self) -> std::cmp::Ordering { - other.date.cmp(&self.date) - } -} - -impl std::cmp::PartialOrd for TransactionRowWithoutAggregations { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { - Some(self.compare_date_desc(other)) - } -} - -impl std::cmp::Ord for TransactionRowWithoutAggregations { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.compare_date_desc(other) - } -} - -#[derive(Clone, Debug, Hash)] -struct TransactionRow { - amount: i32, - balance: i32, - bucket: String, - bucket_font_style: font::Style, - date: DateUtc, - payee: String, - payee_font_style: font::Style, -} - impl TransactionsView { pub fn new( accounts: &[Account], @@ -169,19 +52,14 @@ impl TransactionsView { .cloned() .map(AccountNavigationEntry::new) .collect(); + let active_nav_entry = account_navigation_entries.first().cloned(); let navigation = Navigation::new( - account_navigation_entries.first().cloned(), - account_navigation_entries, - ); - let transaction_rows_by_account_id = - calculate_rows(accounts, account_transfers, buckets, transactions); + active_nav_entry.clone(), account_navigation_entries); + let transactions_table = + TransactionsTable::new(accounts, &active_nav_entry.map(|entry| entry.account), account_transfers, buckets, transactions); Self { - accounts: accounts.to_vec(), - account_transfers: account_transfers.to_vec(), - buckets: buckets.to_vec(), navigation: navigation, - transactions: transactions.to_vec(), - transaction_rows_by_account_id, + transactions_table, } } } @@ -191,52 +69,36 @@ impl<'a> Component<'a, Message, Action> for TransactionsView { match message { Message::NavigationMessage(message) => self.update_navigation(message), + Message::TransactionsTableMessage(message) => self.update_transactions_table(message), + Message::SetAccounts(accounts) => { - self.accounts = accounts.clone(); - self.transaction_rows_by_account_id = calculate_rows( - &self.accounts, - &self.account_transfers, - &self.buckets, - &self.transactions, - ); + let action_1 = self.update_transactions_table( + transactions_table::Message::SetAccounts(accounts.clone())); + let account_navigation_entries: Vec<AccountNavigationEntry> = accounts .into_iter() .map(AccountNavigationEntry::new) .collect(); - self.update_navigation(navigation::Message::SetOptions(account_navigation_entries)) + let action_2 = self.update_navigation(navigation::Message::SetOptions(account_navigation_entries)); + + match (action_1, action_2) { + (Action::None, Action::None) => Action::None + } } Message::SetAccountTransfers(account_transfers) => { - self.account_transfers = account_transfers; - self.transaction_rows_by_account_id = calculate_rows( - &self.accounts, - &self.account_transfers, - &self.buckets, - &self.transactions, - ); - Action::None + self.update_transactions_table( + transactions_table::Message::SetAccountTransfers(account_transfers.clone())) } Message::SetBuckets(buckets) => { - self.buckets = buckets; - self.transaction_rows_by_account_id = calculate_rows( - &self.accounts, - &self.account_transfers, - &self.buckets, - &self.transactions, - ); - Action::None + self.update_transactions_table( + transactions_table::Message::SetBuckets(buckets.clone())) } Message::SetTransactions(transactions) => { - self.transactions = transactions; - self.transaction_rows_by_account_id = calculate_rows( - &self.accounts, - &self.account_transfers, - &self.buckets, - &self.transactions, - ); - Action::None + self.update_transactions_table( + transactions_table::Message::SetTransactions(transactions.clone())) } Message::SelectNextAccount => self.update_navigation(navigation::Message::SelectNext), @@ -252,44 +114,35 @@ impl TransactionsView { message: navigation::Message<AccountNavigationEntry>, ) -> Action { match self.navigation.update(message) { - navigation::Action::ActivateOption(_) | navigation::Action::SelectOption(_) => { - Action::None + navigation::Action::ActivateOption(option) | navigation::Action::SelectOption(option) => { + self.update_transactions_table(transactions_table::Message::SetActiveAccount(option.account)) } navigation::Action::None => Action::None, } } -} - -fn calculate_rows( - accounts: &[Account], - account_transfers: &[AccountTransfer], - buckets: &[Bucket], - transactions: &[Transaction], -) -> HashMap<i32, Vec<TransactionRow>> { - HashMap::from_iter(accounts.iter().map(|account| { - let transaction_rows_without_aggs = transactions - .iter() - .filter_map(|t| { - TransactionRowWithoutAggregations::from_transaction(account.id, t, buckets) - }) - .chain(account_transfers.iter().filter_map(|at| { - TransactionRowWithoutAggregations::from_account_transfer(account.id, at, accounts) - })) - .sorted(); - let mut running_balance: i32 = 0; - let mut transaction_rows = VecDeque::with_capacity(transaction_rows_without_aggs.len()); - for row in transaction_rows_without_aggs.rev() { - if running_balance.checked_add(row.amount).is_none() { - panic!( - "can't add {} + {}. row: {:?}", - running_balance, row.amount, row - ); - } - running_balance += row.amount; - transaction_rows.push_front(row.with_aggregations(running_balance)); + fn update_transactions_table( + &mut self, + message: transactions_table::Message, + ) -> Action { + match self.transactions_table.update(message) { + transactions_table::Action::None => Action::None, } + } +} - (account.id, transaction_rows.into()) - })) +impl<'a> Viewable<'a, Message> for TransactionsView { + fn view(&'a self) -> Element<'a, Message> { + let navigation = self.navigation.view().map(Message::NavigationMessage); + let table = self.transactions_table.view().map(Message::TransactionsTableMessage); + + row![ + Container::new(navigation).width(Length::FillPortion(1)), + Container::new(table).width(Length::FillPortion(3)), + ] + .align_y(alignment::Vertical::Center) + .height(Length::Fill) + .spacing(u32::from(SPACING_LG)) + .into() + } } |
