Rename recurring component to re-use it for savings
This commit is contained in:
parent
4261ab76ca
commit
fd57d4644f
1 changed files with 59 additions and 56 deletions
115
src/main.rs
115
src/main.rs
|
|
@ -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| {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue