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 iced::{
@ -20,6 +20,8 @@ pub(crate) struct Compare<'a, F> {
pub left: Option<(CompareLoad, Box<dyn Spendings>)>,
pub right: Option<(CompareLoad, Box<dyn Spendings>)>,
pub archive: &'a BTreeMap<ReportDate, Report>,
pub person_1: &'a str,
pub person_2: &'a str,
pub on_load: F,
}
@ -40,6 +42,7 @@ pub(crate) enum Section {
Recurring,
Variable,
Accounts,
Remaining,
}
impl Section {
@ -48,6 +51,7 @@ impl Section {
Section::Recurring => "Recurring",
Section::Variable => "Variable",
Section::Accounts => "Accounts",
Section::Remaining => "Remaining",
}
}
}
@ -167,12 +171,15 @@ where
let left = self.left.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,
always: Option<&str>,
left: Option<(&str, f64)>,
right: Option<(&str, f64)>,
) -> Vec<[iced::Element<'b, M>; 4]> {
left: Option<(&S, f64)>,
right: Option<(&S, f64)>,
) -> Vec<[iced::Element<'b, M>; 4]>
where
S: AsRef<str> + ?Sized,
{
let float_text = |f: f64| Some(text(format!("{f:.2}")).size(size));
match (left, right) {
@ -183,24 +190,34 @@ where
(None, Some((k, v))) => {
vec![text_row(
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) => {
vec![text_row(
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![
text_row(
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(
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(
size,
[
Some(text(k).size(size)),
Some(text(k.as_ref()).size(size)),
float_text(lv),
None,
float_text(rv),
@ -226,7 +243,7 @@ where
vec![text_row(
size,
[
Some(text(k).size(size)),
Some(text(k.as_ref()).size(size)),
float_text(lv),
Some(text(format!("{sign}{}%", difference.abs())).size(size)),
float_text(rv),
@ -237,20 +254,21 @@ where
}
}
fn item_compare<'a, I, M>(
fn item_compare<'a, 's, I, S, M>(
collapse: bool,
left: Option<I>,
right: Option<I>,
) -> Vec<[iced::Element<'a, M>; 4]>
where
I: IntoIterator<Item = (&'a str, f64)>,
I: IntoIterator<Item = (S, f64)>,
S: Into<Cow<'s, str>>,
{
if collapse {
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 (left, right) = match (left, right) {
@ -259,7 +277,8 @@ where
(Some(u), None) => {
return u
.into_iter()
.sorted_by_key(|(k, _)| *k)
.map(entry_ref)
.sorted_by(|(ka, _), (kb, _)| ka.cmp(kb))
.map(|(k, v)| {
text_row(
TEXT_NORMAL,
@ -271,7 +290,8 @@ where
(None, Some(u)) => {
return u
.into_iter()
.sorted_by_key(|(k, _)| *k)
.map(entry_ref)
.sorted_by(|(ka, _), (kb, _)| ka.cmp(kb))
.map(|(k, v)| {
text_row(
TEXT_NORMAL,
@ -290,16 +310,16 @@ where
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) {
(_, None) | (None, _) => None,
(Some((&l, _)), Some((&r, _))) => match l.cmp(r) {
Ordering::Less => match left.contains_key(r) {
(Some((l, _)), Some((r, _))) => match l.cmp(r) {
Ordering::Less => match left.contains_key(*r) {
false => None,
true => Some(Side::Left),
},
Ordering::Equal => None,
Ordering::Greater => match right.contains_key(l) {
Ordering::Greater => match right.contains_key(*l) {
false => None,
true => Some(Side::Right),
},
@ -308,15 +328,15 @@ where
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 inserted = false;
compare.extend(
compare_row(
TEXT_NORMAL,
None,
l.map(|(a, b)| (*a, *b)),
r.map(|(a, b)| (*a, *b)),
l.map(|(a, b)| (a, *b)),
r.map(|(a, b)| (a, *b)),
)
.into_iter()
.inspect(|_| {
@ -379,6 +399,21 @@ where
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()

View file

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