Rename recurring component to re-use it for savings

This commit is contained in:
Quentin Boyer 2023-11-12 19:38:52 +01:00
parent 4261ab76ca
commit fd57d4644f

View file

@ -30,41 +30,41 @@ const TEXT_EMPH2: u16 = 20;
const LIST_RULE: u16 = 5;
const SECTION_RULE: u16 = 15;
struct AddRecurring<F> {
struct AddFixed<F> {
on_submit: F,
}
#[derive(Default)]
struct AddRecurringState {
struct AddFixedState {
value: String,
item: String,
}
#[derive(Debug, Clone)]
enum AddRecurringEvent {
enum AddFixedEvent {
SetItem(String),
SetValue(String),
SubmitValue,
}
impl<F> AddRecurring<F> {
impl<F> AddFixed<F> {
fn new(on_submit: F) -> Self {
Self { on_submit }
}
}
impl<M, F> iced::widget::Component<M, Renderer> for AddRecurring<F>
impl<M, F> iced::widget::Component<M, Renderer> for AddFixed<F>
where
F: FnMut(String, f64) -> M,
{
type State = AddRecurringState;
type Event = AddRecurringEvent;
type State = AddFixedState;
type Event = AddFixedEvent;
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<M> {
match event {
AddRecurringEvent::SetItem(i) => state.item = i,
AddRecurringEvent::SetValue(v) => state.value = v,
AddRecurringEvent::SubmitValue => {
AddFixedEvent::SetItem(i) => state.item = i,
AddFixedEvent::SetValue(v) => state.value = v,
AddFixedEvent::SubmitValue => {
if let Ok(v) = state.value.parse() {
state.value.clear();
return Some((self.on_submit)(std::mem::take(&mut state.item), v));
@ -77,36 +77,36 @@ where
fn view(&self, state: &Self::State) -> iced::Element<'_, Self::Event, Renderer> {
column![
text_input("item", &state.item).on_input(AddRecurringEvent::SetItem),
text_input("item", &state.item).on_input(AddFixedEvent::SetItem),
text_input("value", &state.value)
.on_input(AddRecurringEvent::SetValue)
.on_submit(AddRecurringEvent::SubmitValue)
.on_input(AddFixedEvent::SetValue)
.on_submit(AddFixedEvent::SubmitValue)
]
.into()
}
}
struct EditRecurring<'a, F> {
struct EditFixed<'a, F> {
value: String,
name: &'a str,
on_submit: F,
}
#[derive(Default)]
struct EditRecurringState {
struct EditFixedState {
edit: Option<String>,
modal: bool,
}
#[derive(Clone, Debug)]
enum EditRecurringEvent {
enum EditFixedgEvent {
Edit(String),
Open,
Close,
Submit,
}
impl<'a, F> EditRecurring<'a, F> {
impl<'a, F> EditFixed<'a, F> {
fn new(value: f64, name: &'a str, on_submit: F) -> Self {
Self {
value: value.to_string(),
@ -116,17 +116,17 @@ impl<'a, F> EditRecurring<'a, F> {
}
}
impl<M, F> iced::widget::Component<M, Renderer> for EditRecurring<'_, F>
impl<M, F> iced::widget::Component<M, Renderer> for EditFixed<'_, F>
where
F: FnMut(f64) -> M,
{
type State = EditRecurringState;
type Event = EditRecurringEvent;
type State = EditFixedState;
type Event = EditFixedgEvent;
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<M> {
match event {
EditRecurringEvent::Edit(v) => state.edit = Some(v),
EditRecurringEvent::Submit => {
EditFixedgEvent::Edit(v) => state.edit = Some(v),
EditFixedgEvent::Submit => {
if let Some(e) = &state.edit {
if let Ok(v) = e.parse() {
state.edit = None;
@ -135,10 +135,10 @@ where
}
}
}
EditRecurringEvent::Open => {
EditFixedgEvent::Open => {
state.modal = true;
}
EditRecurringEvent::Close => {
EditFixedgEvent::Close => {
state.modal = false;
state.edit = None;
}
@ -148,60 +148,62 @@ where
}
fn view(&self, state: &Self::State) -> iced_aw::Element<'_, Self::Event, Renderer> {
let underlay = button(text("Edit")).on_press(EditRecurringEvent::Open);
let underlay = button(text("Edit")).on_press(EditFixedgEvent::Open);
let overlay = match state.modal {
true => Some(
card(
text(&format!("Edit {}", self.name)),
text_input("new value", state.edit.as_ref().unwrap_or(&self.value))
.on_input(EditRecurringEvent::Edit)
.on_submit(EditRecurringEvent::Submit),
.on_input(EditFixedgEvent::Edit)
.on_submit(EditFixedgEvent::Submit),
)
.max_width(300.0)
.on_close(EditRecurringEvent::Close),
.on_close(EditFixedgEvent::Close),
),
false => None,
};
modal(underlay, overlay)
.backdrop(EditRecurringEvent::Close)
.on_esc(EditRecurringEvent::Close)
.backdrop(EditFixedgEvent::Close)
.on_esc(EditFixedgEvent::Close)
.into()
}
}
#[derive(Clone, Debug)]
enum RecurringMessage {
enum FixedAmountsMessage {
CloseAdd,
Add,
DoAdd(String, f64),
}
#[derive(Default)]
struct RecurringState {
add_recurring: bool,
struct FixedAmountsState {
add: bool,
}
struct Recurring<'a, F> {
struct FixedAmounts<'a, F> {
items: &'a BTreeMap<String, f64>,
add_label: &'a str,
title: &'a str,
on_add: F,
}
impl<M, F> iced::widget::Component<M, Renderer> for Recurring<'_, F>
impl<M, F> iced::widget::Component<M, Renderer> for FixedAmounts<'_, F>
where
F: FnMut(String, f64) -> M,
{
type State = RecurringState;
type Event = RecurringMessage;
type State = FixedAmountsState;
type Event = FixedAmountsMessage;
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<M> {
match event {
RecurringMessage::Add => state.add_recurring = true,
RecurringMessage::CloseAdd => {
state.add_recurring = false;
FixedAmountsMessage::Add => state.add = true,
FixedAmountsMessage::CloseAdd => {
state.add = false;
}
RecurringMessage::DoAdd(item, value) => {
state.add_recurring = false;
FixedAmountsMessage::DoAdd(item, value) => {
state.add = false;
return Some((self.on_add)(item, value));
}
}
@ -212,8 +214,8 @@ where
#[allow(unstable_name_collisions)]
fn view(&self, state: &Self::State) -> iced_aw::Element<'_, Self::Event, Renderer> {
let underlay = column![
text("Recurring").size(TEXT_H2),
button(text("Add")).on_press(RecurringMessage::Add),
text(self.title).size(TEXT_H2),
button(text("Add")).on_press(FixedAmountsMessage::Add),
horizontal_rule(LIST_RULE),
column(
self.items
@ -222,11 +224,10 @@ where
text(name).size(TEXT_EMPH1),
text(&format!("{value}")),
horizontal_space(Length::Fill),
component(EditRecurring::new(
value,
name,
|v| RecurringMessage::DoAdd(name.to_string(), v)
))
component(EditFixed::new(value, name, |v| FixedAmountsMessage::DoAdd(
name.to_string(),
v
)))
]
.spacing(5)
.align_items(iced::Alignment::Center)
@ -238,21 +239,21 @@ where
text(&format!("Total: {}", self.items.values().sum::<f64>())).size(TEXT_EMPH2)
];
let overlay = match state.add_recurring {
let overlay = match state.add {
true => Some(
card(
text("Add a recurring spending"),
component(AddRecurring::new(RecurringMessage::DoAdd)),
text(self.add_label),
component(AddFixed::new(FixedAmountsMessage::DoAdd)),
)
.on_close(RecurringMessage::CloseAdd)
.on_close(FixedAmountsMessage::CloseAdd)
.max_width(300.0),
),
false => None,
};
modal(underlay, overlay)
.backdrop(RecurringMessage::CloseAdd)
.on_esc(RecurringMessage::CloseAdd)
.backdrop(FixedAmountsMessage::CloseAdd)
.on_esc(FixedAmountsMessage::CloseAdd)
.into()
}
}
@ -653,8 +654,10 @@ impl Application for Glaurung {
fn view(&self) -> Element {
column![
text("Spendings").size(TEXT_H1),
component(Recurring {
component(FixedAmounts {
items: &self.recurring,
title: "Recurring",
add_label: "Add a recurring spending",
on_add: Message::AddRecurring,
}),
horizontal_rule(SECTION_RULE).style(|theme: &Theme| {