1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 02:28:12 +00:00

Calendar/AddEventDialog: Prevent inputting invalid date ranges

The calendar now verifies that the user can't input invalid date ranges,
i.e. date ranges where the end is before the start. The UI elements do
this implicitly, by adjusting the values when changing the dates in an
illegal way (e.g. when picking an end date that is before the start
date, the end date will change to the start date).
This commit is contained in:
david072 2023-11-17 21:51:13 +01:00 committed by Andrew Kaster
parent df3e6174b6
commit a84778f6ee
2 changed files with 78 additions and 30 deletions

View file

@ -14,6 +14,7 @@
#include <LibGUI/ComboBox.h>
#include <LibGUI/DatePicker.h>
#include <LibGUI/Label.h>
#include <LibGUI/MessageBox.h>
#include <LibGUI/Painter.h>
#include <LibGUI/SpinBox.h>
#include <LibGUI/TextBox.h>
@ -24,6 +25,8 @@
namespace Calendar {
static constexpr StringView DATE_FORMAT = "%Y-%m-%d"sv;
AddEventDialog::AddEventDialog(Core::DateTime date_time, EventManager& event_manager, Window* parent_window)
: Dialog(parent_window)
, m_start_date_time(date_time)
@ -46,8 +49,7 @@ AddEventDialog::AddEventDialog(Core::DateTime date_time, EventManager& event_man
auto& event_title_textbox = *widget->find_descendant_of_type_named<GUI::TextBox>("event_title_textbox");
event_title_textbox.set_focus(true);
auto& start_date_box = *widget->find_descendant_of_type_named<GUI::TextBox>("start_date");
start_date_box.set_text(MUST(m_start_date_time.to_string("%Y-%m-%d"sv)));
m_start_date_box = *widget->find_descendant_of_type_named<GUI::TextBox>("start_date");
auto calendar_date_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/calendar-date.png"sv).release_value_but_fixme_should_propagate_errors();
@ -55,38 +57,43 @@ AddEventDialog::AddEventDialog(Core::DateTime date_time, EventManager& event_man
pick_start_date_button.set_icon(calendar_date_icon);
pick_start_date_button.on_click = [&](auto) {
if (auto new_date = GUI::DatePicker::show(this, "Pick Start Date"_string, m_start_date_time); new_date.has_value()) {
m_start_date_time.set_date(new_date.release_value());
start_date_box.set_text(MUST(m_start_date_time.to_string("%Y-%m-%d"sv)));
m_start_date_time.set_date(new_date.value());
if (m_end_date_time < m_start_date_time) {
m_end_date_time.set_date(new_date.value());
update_end_date();
}
m_start_date_box->set_text(MUST(m_start_date_time.to_string(DATE_FORMAT)));
}
};
auto& starting_hour_input = *widget->find_descendant_of_type_named<GUI::SpinBox>("start_hour");
starting_hour_input.set_value(m_start_date_time.hour());
m_start_hour_box = *widget->find_descendant_of_type_named<GUI::SpinBox>("start_hour");
m_start_minute_box = *widget->find_descendant_of_type_named<GUI::SpinBox>("start_minute");
auto& starting_minute_input = *widget->find_descendant_of_type_named<GUI::SpinBox>("start_minute");
starting_minute_input.set_value(m_start_date_time.minute());
auto& end_date_box = *widget->find_descendant_of_type_named<GUI::TextBox>("end_date");
end_date_box.set_text(MUST(m_start_date_time.to_string("%Y-%m-%d"sv)));
m_end_date_box = *widget->find_descendant_of_type_named<GUI::TextBox>("end_date");
auto& pick_end_date_button = *widget->find_descendant_of_type_named<GUI::Button>("pick_end_date");
pick_end_date_button.set_icon(calendar_date_icon);
pick_end_date_button.on_click = [&](auto) {
if (auto new_date = GUI::DatePicker::show(this, "Pick End Date"_string, m_end_date_time); new_date.has_value()) {
m_end_date_time.set_date(new_date.release_value());
end_date_box.set_text(MUST(m_end_date_time.to_string("%Y-%m-%d"sv)));
m_end_date_time.set_date(new_date.value());
if (m_end_date_time < m_start_date_time) {
m_start_date_time.set_date(new_date.value());
update_start_date();
}
m_end_date_box->set_text(MUST(m_end_date_time.to_string(DATE_FORMAT)));
}
};
auto& ending_hour_input = *widget->find_descendant_of_type_named<GUI::SpinBox>("end_hour");
ending_hour_input.set_value(m_end_date_time.hour());
auto& ending_minute_input = *widget->find_descendant_of_type_named<GUI::SpinBox>("end_minute");
ending_minute_input.set_value(m_end_date_time.minute());
m_end_hour_box = *widget->find_descendant_of_type_named<GUI::SpinBox>("end_hour");
m_end_minute_box = *widget->find_descendant_of_type_named<GUI::SpinBox>("end_minute");
auto& ok_button = *widget->find_descendant_of_type_named<GUI::Button>("ok_button");
ok_button.on_click = [&](auto) {
add_event_to_calendar().release_value_but_fixme_should_propagate_errors();
auto successful = add_event_to_calendar().release_value_but_fixme_should_propagate_errors();
if (!successful)
return;
done(ExecResult::OK);
};
@ -94,24 +101,40 @@ AddEventDialog::AddEventDialog(Core::DateTime date_time, EventManager& event_man
cancel_button.on_click = [&](auto) { done(ExecResult::Cancel); };
auto update_starting_input_values = [&, this]() {
auto hour = starting_hour_input.value();
auto minute = starting_minute_input.value();
auto hour = m_start_hour_box->value();
auto minute = m_start_minute_box->value();
m_start_date_time.set_time_only(hour, minute);
if (m_end_date_time < m_start_date_time) {
m_end_date_time.set_time_only(hour, minute);
update_end_date();
}
};
auto update_ending_input_values = [&, this]() {
auto hour = ending_hour_input.value();
auto minute = ending_minute_input.value();
auto hour = m_end_hour_box->value();
auto minute = m_end_minute_box->value();
m_end_date_time.set_time_only(hour, minute);
if (m_end_date_time < m_start_date_time) {
m_start_date_time.set_time_only(hour, minute);
update_start_date();
}
};
starting_hour_input.on_change = [update_starting_input_values](auto) { update_starting_input_values(); };
starting_minute_input.on_change = [update_starting_input_values](auto) { update_starting_input_values(); };
ending_hour_input.on_change = [update_ending_input_values](auto) { update_ending_input_values(); };
ending_minute_input.on_change = [update_ending_input_values](auto) { update_ending_input_values(); };
m_start_hour_box->on_change = [update_starting_input_values](auto) { update_starting_input_values(); };
m_start_minute_box->on_change = [update_starting_input_values](auto) { update_starting_input_values(); };
m_end_hour_box->on_change = [update_ending_input_values](auto) { update_ending_input_values(); };
m_end_minute_box->on_change = [update_ending_input_values](auto) { update_ending_input_values(); };
update_start_date();
update_end_date();
}
ErrorOr<void> AddEventDialog::add_event_to_calendar()
ErrorOr<bool> AddEventDialog::add_event_to_calendar()
{
if (m_end_date_time < m_start_date_time) {
GUI::MessageBox::show_error(this, "The end date has to be after the start date."sv);
return false;
}
auto summary = find_descendant_of_type_named<GUI::TextBox>("event_title_textbox")->get_text();
m_event_manager.add_event(Event {
.summary = TRY(String::from_byte_string(summary)),
@ -119,7 +142,21 @@ ErrorOr<void> AddEventDialog::add_event_to_calendar()
.end = m_end_date_time,
});
return {};
return true;
}
void AddEventDialog::update_start_date()
{
m_start_date_box->set_text(MUST(m_start_date_time.to_string(DATE_FORMAT)));
m_start_hour_box->set_value(m_start_date_time.hour(), GUI::AllowCallback::No);
m_start_minute_box->set_value(m_start_date_time.minute(), GUI::AllowCallback::No);
}
void AddEventDialog::update_end_date()
{
m_end_date_box->set_text(MUST(m_end_date_time.to_string(DATE_FORMAT)));
m_end_hour_box->set_value(m_end_date_time.hour(), GUI::AllowCallback::No);
m_end_minute_box->set_value(m_end_date_time.minute(), GUI::AllowCallback::No);
}
}

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2019-2020, Ryan Grieb <ryan.m.grieb@gmail.com>
* Copyright (c) 2022-2023, the SerenityOS developers.
* Copyright (c) 2023, David Ganz <david.g.ganz@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -29,11 +30,21 @@ public:
private:
AddEventDialog(Core::DateTime date_time, EventManager& event_manager, Window* parent_window = nullptr);
ErrorOr<void> add_event_to_calendar();
ErrorOr<bool> add_event_to_calendar();
void update_start_date();
void update_end_date();
Core::DateTime m_start_date_time;
Core::DateTime m_end_date_time;
EventManager& m_event_manager;
RefPtr<GUI::TextBox> m_start_date_box;
RefPtr<GUI::TextBox> m_end_date_box;
RefPtr<GUI::SpinBox> m_start_hour_box;
RefPtr<GUI::SpinBox> m_start_minute_box;
RefPtr<GUI::SpinBox> m_end_hour_box;
RefPtr<GUI::SpinBox> m_end_minute_box;
};
}