mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-01-01 10:28:52 -05:00
* Adding document describing how to use logger * Adjusting logs to follow a new guide * Change order in log header: line number is now before function name
449 lines
18 KiB
C++
449 lines
18 KiB
C++
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include "TimeWidget.hpp"
|
|
#include <ListView.hpp>
|
|
#include <Style.hpp>
|
|
#include <time/time_conversion.hpp>
|
|
#include <time/time_date_validation.hpp>
|
|
#include "DateAndTimeStyle.hpp"
|
|
#include <time/TimeZone.hpp>
|
|
#include <service-time/api/TimeSettingsApi.hpp>
|
|
|
|
namespace gui
|
|
{
|
|
namespace date_and_time = style::window::date_and_time;
|
|
|
|
TimeWidget::TimeWidget(Item *parent,
|
|
const std::string &description,
|
|
Type type,
|
|
std::function<void(const UTF8 &text)> navBarTemporaryMode,
|
|
std::function<void()> navBarRestoreFromTemporaryMode)
|
|
: VBox(parent), mode24H{!stm::api::isTimeFormat12h()}, type{type},
|
|
navBarTemporaryMode(std::move(navBarTemporaryMode)),
|
|
navBarRestoreFromTemporaryMode(std::move(navBarRestoreFromTemporaryMode))
|
|
{
|
|
setMinimumSize(style::window::default_body_width, date_and_time::height);
|
|
setEdges(RectangleEdge::None);
|
|
|
|
descriptionLabel = new gui::Label(this, 0, 0, 0, 0);
|
|
descriptionLabel->setMinimumSize(style::window::default_body_width, date_and_time::topMargin);
|
|
descriptionLabel->setMargins(gui::Margins(0, 0, 0, date_and_time::topMargin / 4));
|
|
descriptionLabel->setEdges(gui::RectangleEdge::None);
|
|
descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
|
|
descriptionLabel->setFont(style::window::font::small);
|
|
descriptionLabel->activeItem = false;
|
|
|
|
hBox = new gui::HBox(this, 0, 0, 0, 0);
|
|
hBox->setMinimumSize(style::window::default_body_width, date_and_time::hBox_h);
|
|
hBox->setEdges(gui::RectangleEdge::None);
|
|
hBox->activeItem = false;
|
|
|
|
hourInput = new gui::Label(hBox, 0, 0, 0, 0);
|
|
hourInput->setEdges(gui::RectangleEdge::Bottom);
|
|
hourInput->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
|
|
hourInput->setFont(style::window::font::largelight);
|
|
hourInput->setPenFocusWidth(style::window::default_border_focus_w);
|
|
hourInput->setPenWidth(style::window::default_border_rect_no_focus);
|
|
|
|
colonLabel = new gui::Label(hBox, 0, 0, 0, 0);
|
|
colonLabel->setMinimumSize(date_and_time::separator, date_and_time::hBox_h);
|
|
colonLabel->setEdges(gui::RectangleEdge::None);
|
|
colonLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
|
|
colonLabel->setFont(style::window::font::medium);
|
|
colonLabel->setText(":");
|
|
colonLabel->activeItem = false;
|
|
|
|
minuteInput = new gui::Label(hBox, 0, 0, 0, 0);
|
|
minuteInput->setEdges(gui::RectangleEdge::Bottom);
|
|
minuteInput->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
|
|
minuteInput->setFont(style::window::font::largelight);
|
|
minuteInput->setPenFocusWidth(style::window::default_border_focus_w);
|
|
minuteInput->setPenWidth(style::window::default_border_rect_no_focus);
|
|
|
|
descriptionLabel->setText(description);
|
|
|
|
focusChangedCallback = [&](Item &item) {
|
|
setFocusItem(focus ? hBox : nullptr);
|
|
if (!item.focus) {
|
|
validateHour();
|
|
}
|
|
return true;
|
|
};
|
|
|
|
applyInputCallbacks();
|
|
prepareForTimeMode();
|
|
}
|
|
|
|
void TimeWidget::applyInputCallbacks()
|
|
{
|
|
inputCallback = [&](Item &item, const InputEvent &event) {
|
|
auto focusedItem = getFocusItem();
|
|
if (!event.isShortRelease()) {
|
|
return false;
|
|
}
|
|
if (event.is(gui::KeyCode::KEY_ENTER) || event.is(gui::KeyCode::KEY_RF)) {
|
|
return false;
|
|
}
|
|
|
|
if (focusedItem->onInput(event)) {
|
|
if (secondItem != nullptr) {
|
|
uint32_t hours;
|
|
|
|
try {
|
|
hours = std::stoi(hourInput->getText().c_str());
|
|
}
|
|
catch (std::exception &e) {
|
|
LOG_ERROR("Exception during getting hours: %s", e.what());
|
|
return true;
|
|
}
|
|
|
|
auto autofill_hour = hours + 1;
|
|
if (type == Type::Start && !mode24H) {
|
|
if (mode12hInput->getText() == timeConstants::after_noon) {
|
|
if (autofill_hour == utils::time::Locale::max_hour_12H_mode) {
|
|
autofill_hour = utils::time::Locale::max_hour_12H_mode - 1;
|
|
secondItem->minuteInput->setText(std::to_string(utils::time::Locale::max_minutes));
|
|
}
|
|
else {
|
|
secondItem->minuteInput->setText(minuteInput->getText());
|
|
}
|
|
secondItem->mode12hInput->setText(mode12hInput->getText());
|
|
}
|
|
else {
|
|
if (autofill_hour == utils::time::Locale::max_hour_12H_mode) {
|
|
secondItem->mode12hInput->setText(timeConstants::after_noon);
|
|
}
|
|
secondItem->minuteInput->setText(minuteInput->getText());
|
|
}
|
|
if (autofill_hour > utils::time::Locale::max_hour_12H_mode) {
|
|
autofill_hour = 1;
|
|
secondItem->mode12hInput->setText(mode12hInput->getText());
|
|
secondItem->minuteInput->setText(minuteInput->getText());
|
|
}
|
|
secondItem->hourInput->setText(std::to_string(autofill_hour));
|
|
}
|
|
else if (type == Type::Start && mode24H) {
|
|
if (secondItem != nullptr) {
|
|
secondItem->minuteInput->setText(minuteInput->getText());
|
|
if (autofill_hour > utils::time::Locale::max_hour_24H_mode) {
|
|
autofill_hour = utils::time::Locale::max_hour_24H_mode;
|
|
secondItem->minuteInput->setText(minuteInput->getText());
|
|
}
|
|
secondItem->hourInput->setText(std::to_string(autofill_hour));
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if (hBox->onInput(event)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
onInputCallback(*hourInput);
|
|
onInputCallback(*minuteInput);
|
|
}
|
|
|
|
void TimeWidget::prepareForTimeMode()
|
|
{
|
|
if (!mode24H) {
|
|
prepareMode12HInputLabel();
|
|
hourInput->setMinimumSize(date_and_time::time_input_12h_w, date_and_time::hBox_h);
|
|
minuteInput->setMinimumSize(date_and_time::time_input_12h_w, date_and_time::hBox_h);
|
|
}
|
|
else {
|
|
hourInput->setMinimumSize(date_and_time::time_input_24h_w, date_and_time::hBox_h);
|
|
minuteInput->setMinimumSize(date_and_time::time_input_24h_w, date_and_time::hBox_h);
|
|
}
|
|
}
|
|
|
|
void TimeWidget::prepareMode12HInputLabel()
|
|
{
|
|
mode12hInput = new gui::Label(hBox, 0, 0, 0, 0);
|
|
mode12hInput->setEdges(gui::RectangleEdge::Bottom);
|
|
mode12hInput->setAlignment(
|
|
gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
|
|
mode12hInput->setFont(style::window::font::largelight);
|
|
mode12hInput->setPenFocusWidth(style::window::default_border_focus_w);
|
|
mode12hInput->setPenWidth(style::window::default_border_rect_no_focus);
|
|
mode12hInput->setText(timeConstants::before_noon);
|
|
mode12hInput->inputCallback = [&](Item &item, const InputEvent &event) {
|
|
if (!event.isShortRelease()) {
|
|
return false;
|
|
}
|
|
if (event.is(gui::KeyCode::KEY_LF)) {
|
|
if (mode12hInput->getText() == timeConstants::before_noon) {
|
|
mode12hInput->setText(timeConstants::after_noon);
|
|
}
|
|
else {
|
|
mode12hInput->setText(timeConstants::before_noon);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
mode12hInput->focusChangedCallback = [&](Item &item) {
|
|
if (item.focus) {
|
|
navBarTemporaryMode(utils::translate("common_switch"));
|
|
}
|
|
else {
|
|
navBarRestoreFromTemporaryMode();
|
|
}
|
|
return true;
|
|
};
|
|
|
|
mode12hInput->setMinimumSize(date_and_time::time_input_12h_w, date_and_time::hBox_h);
|
|
mode12hInput->setMargins(gui::Margins(date_and_time::separator, 0, 0, 0));
|
|
}
|
|
|
|
void TimeWidget::setConnectionToSecondItem(gui::TimeWidget *item)
|
|
{
|
|
this->secondItem = item;
|
|
}
|
|
|
|
void TimeWidget::setConnectionToDateItem(gui::DateWidget *item)
|
|
{
|
|
this->dateItem = item;
|
|
}
|
|
|
|
bool TimeWidget::isPm(const std::string &text) const
|
|
{
|
|
return !(text == timeConstants::before_noon);
|
|
}
|
|
|
|
bool TimeWidget::validateHour() const
|
|
{
|
|
if (type == Type::End) {
|
|
if (secondItem == nullptr) {
|
|
LOG_ERROR("TimeWidget not connected!");
|
|
return false;
|
|
}
|
|
std::chrono::hours start_hour;
|
|
std::chrono::hours end_hour;
|
|
uint32_t start_minutes;
|
|
uint32_t end_minutes;
|
|
try {
|
|
auto hours = std::chrono::hours(std::stoi(secondItem->hourInput->getText().c_str()));
|
|
if (!mode24H) {
|
|
start_hour = date::make24(hours, isPm(secondItem->mode12hInput->getText()));
|
|
}
|
|
else {
|
|
start_hour = hours;
|
|
}
|
|
}
|
|
catch (std::exception &e) {
|
|
LOG_ERROR("Exception while setting start_hour: %s", e.what());
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
auto hours = std::chrono::hours(std::stoi(hourInput->getText().c_str()));
|
|
if (!mode24H) {
|
|
end_hour = date::make24(hours, isPm(mode12hInput->getText()));
|
|
}
|
|
else {
|
|
end_hour = hours;
|
|
}
|
|
}
|
|
catch (std::exception &e) {
|
|
LOG_ERROR("Exception while setting end_hour: %s", e.what());
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
start_minutes = std::stoi(secondItem->minuteInput->getText().c_str());
|
|
}
|
|
catch (std::exception &e) {
|
|
LOG_ERROR("Exception while setting start_minutes: %s", e.what());
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
end_minutes = std::stoi(minuteInput->getText().c_str());
|
|
}
|
|
catch (std::exception &e) {
|
|
LOG_ERROR("Exception while setting end_minutes: %s", e.what());
|
|
return false;
|
|
}
|
|
|
|
if (!mode24H) {
|
|
validateHourFor12hMode(start_hour, end_hour, start_minutes, end_minutes);
|
|
}
|
|
else {
|
|
validateHourFor24hMode(start_hour, end_hour, start_minutes, end_minutes);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void TimeWidget::validateHourFor12hMode(std::chrono::hours start_hour,
|
|
std::chrono::minutes end_hour,
|
|
uint32_t start_minutes,
|
|
uint32_t end_minutes) const
|
|
{
|
|
if (start_hour > end_hour || (start_hour == end_hour && start_minutes > end_minutes)) {
|
|
auto hour = start_hour.count() + 1;
|
|
if (secondItem->mode12hInput->getText() == timeConstants::after_noon) {
|
|
if (hour == utils::time::Locale::max_hour_12H_mode) {
|
|
hour = utils::time::Locale::max_hour_12H_mode - 1;
|
|
minuteInput->setText(std::to_string(utils::time::Locale::max_minutes));
|
|
}
|
|
else {
|
|
minuteInput->setText(secondItem->minuteInput->getText());
|
|
}
|
|
mode12hInput->setText(secondItem->mode12hInput->getText());
|
|
}
|
|
else {
|
|
if (hour == utils::time::Locale::max_hour_12H_mode) {
|
|
mode12hInput->setText(timeConstants::after_noon);
|
|
}
|
|
minuteInput->setText(minuteInput->getText());
|
|
}
|
|
if (hour > utils::time::Locale::max_hour_12H_mode) {
|
|
hour = 1;
|
|
mode12hInput->setText(secondItem->mode12hInput->getText());
|
|
minuteInput->setText(secondItem->minuteInput->getText());
|
|
}
|
|
hourInput->setText(utils::to_string(hour));
|
|
}
|
|
}
|
|
|
|
void TimeWidget::validateHourFor24hMode(std::chrono::hours start_hour,
|
|
std::chrono::minutes end_hour,
|
|
uint32_t start_minutes,
|
|
uint32_t end_minutes) const
|
|
{
|
|
if (start_hour > end_hour || (start_hour == end_hour && start_minutes > end_minutes)) {
|
|
auto hour = start_hour.count() + 1;
|
|
if (hour > utils::time::Locale::max_hour_24H_mode) {
|
|
hour = utils::time::Locale::max_hour_24H_mode;
|
|
minuteInput->setText(std::to_string(utils::time::Locale::max_minutes));
|
|
}
|
|
else {
|
|
minuteInput->setText(secondItem->minuteInput->getText());
|
|
}
|
|
hourInput->setText(std::to_string(hour));
|
|
}
|
|
}
|
|
|
|
void TimeWidget::setTime(int keyValue, gui::Label &item)
|
|
{
|
|
auto itemValue = item.getText();
|
|
auto key = std::to_string(keyValue);
|
|
if (itemValue == "0") {
|
|
itemValue = key;
|
|
}
|
|
else {
|
|
itemValue += key;
|
|
}
|
|
item.setText(itemValue);
|
|
|
|
if (!utils::time::validateTime(hourInput->getText(), minuteInput->getText(), !mode24H)) {
|
|
item.setText(key);
|
|
}
|
|
}
|
|
|
|
void TimeWidget::onInputCallback(gui::Label &timeInput)
|
|
{
|
|
timeInput.inputCallback = [&](Item &item, const InputEvent &event) {
|
|
if (!event.isShortRelease()) {
|
|
return false;
|
|
}
|
|
if (event.isDigit()) {
|
|
setTime(event.numericValue(), timeInput);
|
|
return true;
|
|
}
|
|
else if (event.is(gui::KeyCode::KEY_PND)) {
|
|
clearInput(timeInput);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
|
|
void TimeWidget::clearInput(gui::Label &timeInput)
|
|
{
|
|
if (auto length = timeInput.getText().length(); length > 0) {
|
|
auto value = timeInput.getText();
|
|
value.removeChar(length - 1);
|
|
if (value.length() == 0) {
|
|
value = "0";
|
|
}
|
|
timeInput.setText(value);
|
|
}
|
|
}
|
|
|
|
void TimeWidget::loadData(const std::chrono::hours &hoursFrom,
|
|
const std::chrono::minutes &minutesFrom,
|
|
const std::chrono::hours &hoursTill,
|
|
const std::chrono::minutes &minutesTill)
|
|
{
|
|
if (!mode24H) {
|
|
if (type == Type::Start) {
|
|
const auto hours12H = date::make12(hoursFrom);
|
|
hourInput->setText(utils::to_string(hours12H.count()));
|
|
minuteInput->setText(utils::to_string(minutesFrom.count()));
|
|
if (date::is_am(hoursFrom)) {
|
|
mode12hInput->setText(timeConstants::before_noon);
|
|
}
|
|
else {
|
|
mode12hInput->setText(timeConstants::after_noon);
|
|
}
|
|
}
|
|
else if (type == Type::End) {
|
|
const auto hours12H = date::make12(hoursTill);
|
|
hourInput->setText(utils::to_string(hours12H.count()));
|
|
minuteInput->setText(utils::to_string(minutesTill.count()));
|
|
if (date::is_am(hoursTill)) {
|
|
mode12hInput->setText(timeConstants::before_noon);
|
|
}
|
|
else {
|
|
mode12hInput->setText(timeConstants::after_noon);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (type == Type::Start) {
|
|
hourInput->setText(utils::to_string(hoursFrom.count()));
|
|
minuteInput->setText(utils::to_string(minutesFrom.count()));
|
|
}
|
|
else if (type == Type::End) {
|
|
hourInput->setText(utils::to_string(hoursTill.count()));
|
|
minuteInput->setText(utils::to_string(minutesTill.count()));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TimeWidget::saveData(std::shared_ptr<utils::time::FromTillDate> fromTillDate) const
|
|
{
|
|
if (!validateHour()) {
|
|
return false;
|
|
}
|
|
auto hours = std::chrono::hours(std::stoi(hourInput->getText().c_str()));
|
|
auto minutes = std::chrono::minutes(std::stoi(minuteInput->getText().c_str()));
|
|
|
|
if (!mode24H) {
|
|
hours = date::make24(hours, isPm(mode12hInput->getText()));
|
|
}
|
|
auto date = (dateItem != nullptr) ? TimePointFromYearMonthDay(dateItem->getChosenDate())
|
|
: TimePointFromYearMonthDay(TimePointToYearMonthDay(TimePointNow()));
|
|
|
|
TimePoint presetPointTime = date + hours + minutes;
|
|
auto timeZoneOffset =
|
|
utils::time::getTimeZoneOffset(stm::api::getCurrentTimezoneName(), TimePointToTimeT(presetPointTime));
|
|
|
|
if (type == Type::Start) {
|
|
fromTillDate->from = presetPointTime - timeZoneOffset;
|
|
}
|
|
else if (type == Type::End) {
|
|
fromTillDate->till = presetPointTime - timeZoneOffset;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} /* namespace gui */
|