158 lines
4.7 KiB
C++
158 lines
4.7 KiB
C++
|
|
#include "SetTimeActivity.h"
|
||
|
|
|
||
|
|
#include <GfxRenderer.h>
|
||
|
|
#include <I18n.h>
|
||
|
|
#include <sys/time.h>
|
||
|
|
|
||
|
|
#include <cstdio>
|
||
|
|
#include <ctime>
|
||
|
|
|
||
|
|
#include "CrossPointSettings.h"
|
||
|
|
#include "MappedInputManager.h"
|
||
|
|
#include "components/UITheme.h"
|
||
|
|
#include "fontIds.h"
|
||
|
|
|
||
|
|
void SetTimeActivity::onEnter() {
|
||
|
|
Activity::onEnter();
|
||
|
|
|
||
|
|
// Initialize from current system time if it's been set (year > 2000)
|
||
|
|
time_t now = time(nullptr);
|
||
|
|
struct tm* t = localtime(&now);
|
||
|
|
if (t != nullptr && t->tm_year > 100) {
|
||
|
|
hour = t->tm_hour;
|
||
|
|
minute = t->tm_min;
|
||
|
|
} else {
|
||
|
|
hour = 12;
|
||
|
|
minute = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
selectedField = 0;
|
||
|
|
requestUpdate();
|
||
|
|
}
|
||
|
|
|
||
|
|
void SetTimeActivity::onExit() { Activity::onExit(); }
|
||
|
|
|
||
|
|
void SetTimeActivity::loop() {
|
||
|
|
// Back button: discard and exit
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||
|
|
finish();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Confirm button: apply time and exit
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||
|
|
applyTime();
|
||
|
|
finish();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Left/Right: switch between hour and minute fields
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||
|
|
selectedField = 0;
|
||
|
|
requestUpdate();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||
|
|
selectedField = 1;
|
||
|
|
requestUpdate();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Up/Down: increment/decrement the selected field
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Up)) {
|
||
|
|
if (selectedField == 0) {
|
||
|
|
hour = (hour + 1) % 24;
|
||
|
|
} else {
|
||
|
|
minute = (minute + 1) % 60;
|
||
|
|
}
|
||
|
|
requestUpdate();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
|
||
|
|
if (selectedField == 0) {
|
||
|
|
hour = (hour + 23) % 24;
|
||
|
|
} else {
|
||
|
|
minute = (minute + 59) % 60;
|
||
|
|
}
|
||
|
|
requestUpdate();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void SetTimeActivity::render(RenderLock&&) {
|
||
|
|
renderer.clearScreen();
|
||
|
|
|
||
|
|
const auto pageWidth = renderer.getScreenWidth();
|
||
|
|
const int lineHeight12 = renderer.getLineHeight(UI_12_FONT_ID);
|
||
|
|
|
||
|
|
// Title
|
||
|
|
renderer.drawCenteredText(UI_12_FONT_ID, 20, tr(STR_SET_TIME), true, EpdFontFamily::BOLD);
|
||
|
|
|
||
|
|
// Format hour and minute strings
|
||
|
|
char hourStr[4];
|
||
|
|
char minuteStr[4];
|
||
|
|
snprintf(hourStr, sizeof(hourStr), "%02d", hour);
|
||
|
|
snprintf(minuteStr, sizeof(minuteStr), "%02d", minute);
|
||
|
|
|
||
|
|
const int colonWidth = renderer.getTextWidth(UI_12_FONT_ID, " : ");
|
||
|
|
const int digitWidth = renderer.getTextWidth(UI_12_FONT_ID, "00");
|
||
|
|
const int totalWidth = digitWidth * 2 + colonWidth;
|
||
|
|
const int startX = (pageWidth - totalWidth) / 2;
|
||
|
|
const int timeY = 80;
|
||
|
|
|
||
|
|
// Draw selection highlight behind the selected field
|
||
|
|
constexpr int highlightPad = 6;
|
||
|
|
if (selectedField == 0) {
|
||
|
|
renderer.fillRoundedRect(startX - highlightPad, timeY - 4, digitWidth + highlightPad * 2, lineHeight12 + 8, 6,
|
||
|
|
Color::LightGray);
|
||
|
|
} else {
|
||
|
|
renderer.fillRoundedRect(startX + digitWidth + colonWidth - highlightPad, timeY - 4, digitWidth + highlightPad * 2,
|
||
|
|
lineHeight12 + 8, 6, Color::LightGray);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Draw the time digits and colon
|
||
|
|
renderer.drawText(UI_12_FONT_ID, startX, timeY, hourStr, true);
|
||
|
|
renderer.drawText(UI_12_FONT_ID, startX + digitWidth, timeY, " : ", true);
|
||
|
|
renderer.drawText(UI_12_FONT_ID, startX + digitWidth + colonWidth, timeY, minuteStr, true);
|
||
|
|
|
||
|
|
// Draw up/down arrows above and below the selected field
|
||
|
|
const int arrowX = (selectedField == 0) ? startX + digitWidth / 2 : startX + digitWidth + colonWidth + digitWidth / 2;
|
||
|
|
const int arrowUpY = timeY - 20;
|
||
|
|
const int arrowDownY = timeY + lineHeight12 + 12;
|
||
|
|
// Up arrow (simple triangle using lines)
|
||
|
|
constexpr int arrowSize = 6;
|
||
|
|
for (int row = 0; row < arrowSize; row++) {
|
||
|
|
renderer.drawLine(arrowX - row, arrowUpY + row, arrowX + row, arrowUpY + row);
|
||
|
|
}
|
||
|
|
// Down arrow
|
||
|
|
for (int row = 0; row < arrowSize; row++) {
|
||
|
|
renderer.drawLine(arrowX - row, arrowDownY + arrowSize - 1 - row, arrowX + row, arrowDownY + arrowSize - 1 - row);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Button hints
|
||
|
|
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SAVE), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||
|
|
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||
|
|
|
||
|
|
renderer.displayBuffer();
|
||
|
|
}
|
||
|
|
|
||
|
|
void SetTimeActivity::applyTime() {
|
||
|
|
time_t now = time(nullptr);
|
||
|
|
struct tm newTime = {};
|
||
|
|
struct tm* current = localtime(&now);
|
||
|
|
if (current != nullptr && current->tm_year > 100) {
|
||
|
|
newTime = *current;
|
||
|
|
} else {
|
||
|
|
// If time was never set, use a reasonable date (2025-01-01)
|
||
|
|
newTime.tm_year = 125; // years since 1900
|
||
|
|
newTime.tm_mon = 0;
|
||
|
|
newTime.tm_mday = 1;
|
||
|
|
}
|
||
|
|
newTime.tm_hour = hour;
|
||
|
|
newTime.tm_min = minute;
|
||
|
|
newTime.tm_sec = 0;
|
||
|
|
time_t newEpoch = mktime(&newTime);
|
||
|
|
struct timeval tv = {.tv_sec = newEpoch, .tv_usec = 0};
|
||
|
|
settimeofday(&tv, nullptr);
|
||
|
|
}
|