Add a section for comparing remaining amounts

This commit is contained in:
traxys 2023-12-09 18:05:38 +01:00
parent 7545d7768f
commit 09f35f84ea
2 changed files with 62 additions and 25 deletions

View file

@ -1,4 +1,4 @@
use std::{cmp::Ordering, collections::BTreeMap, iter}; use std::{borrow::Cow, cmp::Ordering, collections::BTreeMap, iter};
use enum_map::{Enum, EnumMap}; use enum_map::{Enum, EnumMap};
use iced::{ use iced::{
@ -20,6 +20,8 @@ pub(crate) struct Compare<'a, F> {
pub left: Option<(CompareLoad, Box<dyn Spendings>)>, pub left: Option<(CompareLoad, Box<dyn Spendings>)>,
pub right: Option<(CompareLoad, Box<dyn Spendings>)>, pub right: Option<(CompareLoad, Box<dyn Spendings>)>,
pub archive: &'a BTreeMap<ReportDate, Report>, pub archive: &'a BTreeMap<ReportDate, Report>,
pub person_1: &'a str,
pub person_2: &'a str,
pub on_load: F, pub on_load: F,
} }
@ -40,6 +42,7 @@ pub(crate) enum Section {
Recurring, Recurring,
Variable, Variable,
Accounts, Accounts,
Remaining,
} }
impl Section { impl Section {
@ -48,6 +51,7 @@ impl Section {
Section::Recurring => "Recurring", Section::Recurring => "Recurring",
Section::Variable => "Variable", Section::Variable => "Variable",
Section::Accounts => "Accounts", Section::Accounts => "Accounts",
Section::Remaining => "Remaining",
} }
} }
} }
@ -167,12 +171,15 @@ where
let left = self.left.as_ref().map(|(_, r)| &**r); let left = self.left.as_ref().map(|(_, r)| &**r);
let right = self.right.as_ref().map(|(_, r)| &**r); let right = self.right.as_ref().map(|(_, r)| &**r);
fn compare_row<'b, M>( fn compare_row<'b, S, M>(
size: u16, size: u16,
always: Option<&str>, always: Option<&str>,
left: Option<(&str, f64)>, left: Option<(&S, f64)>,
right: Option<(&str, f64)>, right: Option<(&S, f64)>,
) -> Vec<[iced::Element<'b, M>; 4]> { ) -> Vec<[iced::Element<'b, M>; 4]>
where
S: AsRef<str> + ?Sized,
{
let float_text = |f: f64| Some(text(format!("{f:.2}")).size(size)); let float_text = |f: f64| Some(text(format!("{f:.2}")).size(size));
match (left, right) { match (left, right) {
@ -183,24 +190,34 @@ where
(None, Some((k, v))) => { (None, Some((k, v))) => {
vec![text_row( vec![text_row(
size, size,
[Some(text(k).size(size)), None, None, float_text(v)], [Some(text(k.as_ref()).size(size)), None, None, float_text(v)],
)] )]
} }
(Some((k, v)), None) => { (Some((k, v)), None) => {
vec![text_row( vec![text_row(
size, size,
[Some(text(k).size(size)), float_text(v), None, None], [Some(text(k.as_ref()).size(size)), float_text(v), None, None],
)] )]
} }
(Some((lk, lv)), Some((rk, rv))) if lk != rk => { (Some((lk, lv)), Some((rk, rv))) if lk.as_ref() != rk.as_ref() => {
vec![ vec![
text_row( text_row(
size, size,
[Some(text(lk).size(size)), float_text(lv), None, None], [
Some(text(lk.as_ref()).size(size)),
float_text(lv),
None,
None,
],
), ),
text_row( text_row(
size, size,
[Some(text(rk).size(size)), None, None, float_text(rv)], [
Some(text(rk.as_ref()).size(size)),
None,
None,
float_text(rv),
],
), ),
] ]
} }
@ -209,7 +226,7 @@ where
vec![text_row( vec![text_row(
size, size,
[ [
Some(text(k).size(size)), Some(text(k.as_ref()).size(size)),
float_text(lv), float_text(lv),
None, None,
float_text(rv), float_text(rv),
@ -226,7 +243,7 @@ where
vec![text_row( vec![text_row(
size, size,
[ [
Some(text(k).size(size)), Some(text(k.as_ref()).size(size)),
float_text(lv), float_text(lv),
Some(text(format!("{sign}{}%", difference.abs())).size(size)), Some(text(format!("{sign}{}%", difference.abs())).size(size)),
float_text(rv), float_text(rv),
@ -237,20 +254,21 @@ where
} }
} }
fn item_compare<'a, I, M>( fn item_compare<'a, 's, I, S, M>(
collapse: bool, collapse: bool,
left: Option<I>, left: Option<I>,
right: Option<I>, right: Option<I>,
) -> Vec<[iced::Element<'a, M>; 4]> ) -> Vec<[iced::Element<'a, M>; 4]>
where where
I: IntoIterator<Item = (&'a str, f64)>, I: IntoIterator<Item = (S, f64)>,
S: Into<Cow<'s, str>>,
{ {
if collapse { if collapse {
return Vec::new(); return Vec::new();
} }
let to_btree = |i: I| i.into_iter().collect::<BTreeMap<_, _>>(); let entry_ref = |(s, v): (S, f64)| (s.into(), v);
let to_btree = |i: I| i.into_iter().map(entry_ref).collect::<BTreeMap<_, _>>();
let float_text = |f: f64| Some(text(format!("{f:.2}")).size(TEXT_NORMAL)); let float_text = |f: f64| Some(text(format!("{f:.2}")).size(TEXT_NORMAL));
let (left, right) = match (left, right) { let (left, right) = match (left, right) {
@ -259,7 +277,8 @@ where
(Some(u), None) => { (Some(u), None) => {
return u return u
.into_iter() .into_iter()
.sorted_by_key(|(k, _)| *k) .map(entry_ref)
.sorted_by(|(ka, _), (kb, _)| ka.cmp(kb))
.map(|(k, v)| { .map(|(k, v)| {
text_row( text_row(
TEXT_NORMAL, TEXT_NORMAL,
@ -271,7 +290,8 @@ where
(None, Some(u)) => { (None, Some(u)) => {
return u return u
.into_iter() .into_iter()
.sorted_by_key(|(k, _)| *k) .map(entry_ref)
.sorted_by(|(ka, _), (kb, _)| ka.cmp(kb))
.map(|(k, v)| { .map(|(k, v)| {
text_row( text_row(
TEXT_NORMAL, TEXT_NORMAL,
@ -290,16 +310,16 @@ where
Right, Right,
} }
type Peek<'a> = Option<&'a (&'a &'a str, &'a f64)>; type Peek<'a> = Option<&'a (&'a Cow<'a, str>, &'a f64)>;
let needs_to_wait = |l: Peek, r: Peek| match (l, r) { let needs_to_wait = |l: Peek, r: Peek| match (l, r) {
(_, None) | (None, _) => None, (_, None) | (None, _) => None,
(Some((&l, _)), Some((&r, _))) => match l.cmp(r) { (Some((l, _)), Some((r, _))) => match l.cmp(r) {
Ordering::Less => match left.contains_key(r) { Ordering::Less => match left.contains_key(*r) {
false => None, false => None,
true => Some(Side::Left), true => Some(Side::Left),
}, },
Ordering::Equal => None, Ordering::Equal => None,
Ordering::Greater => match right.contains_key(l) { Ordering::Greater => match right.contains_key(*l) {
false => None, false => None,
true => Some(Side::Right), true => Some(Side::Right),
}, },
@ -308,15 +328,15 @@ where
let mut compare = Vec::new(); let mut compare = Vec::new();
type Item<'a> = Option<(&'a &'a str, &'a f64)>; type Item<'a> = Option<(&'a Cow<'a, str>, &'a f64)>;
let mut insert_row = |l: Item, r: Item| { let mut insert_row = |l: Item, r: Item| {
let mut inserted = false; let mut inserted = false;
compare.extend( compare.extend(
compare_row( compare_row(
TEXT_NORMAL, TEXT_NORMAL,
None, None,
l.map(|(a, b)| (*a, *b)), l.map(|(a, b)| (a, *b)),
r.map(|(a, b)| (*a, *b)), r.map(|(a, b)| (a, *b)),
) )
.into_iter() .into_iter()
.inspect(|_| { .inspect(|_| {
@ -379,6 +399,21 @@ where
std::iter::once(("Main", main_account)).chain(s.savings()) std::iter::once(("Main", main_account)).chain(s.savings())
}), }),
mk_section!(Section::Remaining, move |s| {
let contrib = s.contributions(self.archive);
let remaining_1 = format!("Equal {}", self.person_1);
let remaining_2 = format!("Equal {}", self.person_2);
[
(
Cow::Borrowed("Same"),
contrib.same_remaining.remaining.person_1,
),
(remaining_1.into(), contrib.proportional.remaining.person_1),
(remaining_2.into(), contrib.proportional.remaining.person_2),
]
}),
], ],
)) ))
.into() .into()

View file

@ -521,6 +521,8 @@ impl Application for Glaurung {
right: self.compare_load(self.compare_right), right: self.compare_load(self.compare_right),
archive: &self.archive, archive: &self.archive,
on_load: Message::CompareLoad, on_load: Message::CompareLoad,
person_1: &self.config.person_1,
person_2: &self.config.person_2,
}), }),
}; };