Skip to content

Commit

Permalink
fix(color): Restrict time/date to valid values, check for changed val…
Browse files Browse the repository at this point in the history
…ues before updating screen (#2884)

* Fix RTC date editing to limit day max value to actual number of days in the selected month.
If month or year is updated check that day value is still in range, if not update day to max value for selected year and month.
Only update UI values that have actually changed.

* Use struct assignment instead of memcpy to initialise property.
  • Loading branch information
philmoz authored Dec 18, 2022
1 parent 2b00583 commit 0be85bb
Showing 1 changed file with 103 additions and 91 deletions.
194 changes: 103 additions & 91 deletions radio/src/gui/colorlcd/radio_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,151 +48,163 @@ class DateTimeWindow : public FormGroup {
{
FormGroup::checkEvents();

if (get_tmr10ms() - lastRefresh >= 10) {
struct gtm newTS;
if (seconds && (get_tmr10ms() - lastRefresh >= 10)) {
lastRefresh = get_tmr10ms();

gettime(&newTS);
if(newTS.tm_sec == lastSecond)
return;

lastSecond = newTS.tm_sec;
year->update();
month->update();
day->update();
hour->update();
minutes->update();
seconds->update();
gettime(&m_tm);
if (m_tm.tm_year != m_last_tm.tm_year) {
m_last_tm.tm_year = m_tm.tm_year;
year->update();
}
if (m_tm.tm_mon != m_last_tm.tm_mon) {
m_last_tm.tm_mon = m_tm.tm_mon;
month->update();
}
if (m_tm.tm_mday != m_last_tm.tm_mday) {
m_last_tm.tm_mday = m_tm.tm_mday;
day->update();
}
if (m_tm.tm_hour != m_last_tm.tm_hour) {
m_last_tm.tm_hour = m_tm.tm_hour;
hour->update();
}
if (m_tm.tm_min != m_last_tm.tm_min) {
m_last_tm.tm_min = m_tm.tm_min;
minutes->update();
}
if (m_tm.tm_sec != m_last_tm.tm_sec) {
m_last_tm.tm_sec = m_tm.tm_sec;
seconds->update();
}
}
}

protected:
struct gtm m_tm;
struct gtm m_last_tm;
tmr10ms_t lastRefresh = 0;
int8_t lastSecond;
NumberEdit* year = nullptr;
NumberEdit* month = nullptr;
NumberEdit* day = nullptr;
NumberEdit* hour = nullptr;
NumberEdit* minutes = nullptr;
NumberEdit* seconds = nullptr;

int8_t daysInMonth()
{
static const int8_t dmon[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int16_t year = TM_YEAR_BASE + m_tm.tm_year;
int8_t days_in_month = dmon[m_tm.tm_mon];
if ((m_tm.tm_mon == 1) && (((year % 4 == 0) && (year % 100 != 0)) || (year%400==0)))
days_in_month += 1;
return days_in_month;
}

void setDaysInMonth()
{
if (day) {
day->setMax(daysInMonth());
if (m_tm.tm_mday > day->getMax()) {
// Update stored day value if > actual days in month
// Will be written to RTC via SET_LOAD_DATETIME call after returning
// UI will update on next iteration of checkEvents
m_tm.tm_mday = day->getMax();
}
}
}

void build()
{
setFlexLayout();
FlexGridLayout grid(col_four_dsc, row_dsc, 2);

auto line = newLine(&grid);
gettime(&m_tm);
m_last_tm = m_tm;

// Date
auto line = newLine(&grid);
new StaticText(line, rect_t{}, STR_DATE, 0, COLOR_THEME_PRIMARY1);
year = new NumberEdit(line, rect_t{}, 2018, 2100,
[=]() -> int32_t {
struct gtm t;
gettime(&t);
return TM_YEAR_BASE + t.tm_year;
return TM_YEAR_BASE + m_tm.tm_year;
},
[=](int32_t newValue) {
struct gtm t;
gettime(&t);
t.tm_year = newValue - TM_YEAR_BASE;
SET_LOAD_DATETIME(&t);
m_last_tm.tm_year = m_tm.tm_year = newValue - TM_YEAR_BASE;
setDaysInMonth();
SET_LOAD_DATETIME(&m_tm);
});
lv_obj_set_style_grid_cell_x_align(year->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);

month = new NumberEdit(line, rect_t{}, 1, 12,
[=]() -> int32_t {
struct gtm t;
gettime(&t);
return 1 + t.tm_mon;
},
[=](int32_t newValue) {
struct gtm t;
gettime(&t);
t.tm_mon = newValue - 1;
SET_LOAD_DATETIME(&t);
});
[=]() -> int32_t {
return 1 + m_tm.tm_mon;
},
[=](int32_t newValue) {
m_last_tm.tm_mon = m_tm.tm_mon = newValue - 1;
setDaysInMonth();
SET_LOAD_DATETIME(&m_tm);
});
month->setDisplayHandler([](int32_t value) {
return formatNumberAsString(value, LEADING0);
});
lv_obj_set_style_grid_cell_x_align(month->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);

/* TODO dynamic max instead of 31 ...
int16_t year = TM_YEAR_BASE + t.tm_year;
int8_t dlim = (((((year%4==0) && (year%100!=0)) || (year%400==0)) && (t.tm_mon==1)) ? 1 : 0);
static const pm_uint8_t dmon[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
dlim += *(&dmon[t.tm_mon]);*/
int8_t dlim = 31;
day = new NumberEdit(line, rect_t{}, 1, dlim,
[=]() -> int32_t {
struct gtm t;
gettime(&t);
return t.tm_mday;
},
[=](int32_t newValue) {
struct gtm t;
gettime(&t);
t.tm_mday = newValue;
SET_LOAD_DATETIME(&t);
});
day = new NumberEdit(line, rect_t{}, 1, daysInMonth(),
[=]() -> int32_t {
return m_tm.tm_mday;
},
[=](int32_t newValue) {
m_last_tm.tm_mday = m_tm.tm_mday = newValue;
SET_LOAD_DATETIME(&m_tm);
});
day->setDisplayHandler([](int32_t value) {
return formatNumberAsString(value, LEADING0, 2);
});
lv_obj_set_style_grid_cell_x_align(day->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
line = newLine(&grid);

// Time
line = newLine(&grid);
new StaticText(line, rect_t{}, STR_TIME, 0, COLOR_THEME_PRIMARY1);
hour = new NumberEdit(line, rect_t{}, 0, 24,
[=]() -> int32_t {
struct gtm t;
gettime(&t);
return t.tm_hour;
},
[=](int32_t newValue) {
struct gtm t;
gettime(&t);
t.tm_hour = newValue;
SET_LOAD_DATETIME(&t);
});
hour = new NumberEdit(line, rect_t{}, 0, 23,
[=]() -> int32_t {
return m_tm.tm_hour;
},
[=](int32_t newValue) {
m_last_tm.tm_hour = m_tm.tm_hour = newValue;
SET_LOAD_DATETIME(&m_tm);
});
hour->setDisplayHandler([](int32_t value) {
static char s[50];
BitmapBuffer::formatNumberAsString(s, 49, value, LEADING0, 2);
return std::string(s);
// dc->drawNumber(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, flags | LEADING0, 2);
return formatNumberAsString(value, LEADING0, 2);
});
lv_obj_set_style_grid_cell_x_align(hour->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);

minutes = new NumberEdit(line, rect_t{}, 0, 59,
[=]() -> int32_t {
struct gtm t;
gettime(&t);
return t.tm_min;
},
[=](int32_t newValue) {
struct gtm t;
gettime(&t);
t.tm_min = newValue;
SET_LOAD_DATETIME(&t);
});
minutes = new NumberEdit(line, rect_t{}, 0, 59,
[=]() -> int32_t {
return m_tm.tm_min;
},
[=](int32_t newValue) {
m_last_tm.tm_min = m_tm.tm_min = newValue;
SET_LOAD_DATETIME(&m_tm);
});
minutes->setDisplayHandler([](int32_t value) {
return formatNumberAsString(value, LEADING0, 2);
});
lv_obj_set_style_grid_cell_x_align(minutes->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);

seconds = new NumberEdit(line, rect_t{}, 0, 59,
[=]() -> int32_t {
struct gtm t;
gettime(&t);
return t.tm_sec;
},
[=](int32_t newValue) {
struct gtm t;
gettime(&t);
t.tm_sec = newValue;
SET_LOAD_DATETIME(&t);
});
[=]() -> int32_t {
return m_tm.tm_sec;
},
[=](int32_t newValue) {
m_last_tm.tm_sec = m_tm.tm_sec = newValue;
SET_LOAD_DATETIME(&m_tm);
});
seconds->setDisplayHandler([](int value) {
return formatNumberAsString(value, LEADING0, 2);
});
lv_obj_set_style_grid_cell_x_align(seconds->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);

// Spacer
line = newLine(&grid);
}
};
Expand Down

0 comments on commit 0be85bb

Please sign in to comment.