summaryrefslogtreecommitdiff
path: root/schist_desktop_gui/src/gui/components/transactions_view.rs
diff options
context:
space:
mode:
Diffstat (limited to 'schist_desktop_gui/src/gui/components/transactions_view.rs')
-rw-r--r--schist_desktop_gui/src/gui/components/transactions_view.rs271
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()
+ }
}