Skip to content

Commit 2d80770

Browse files
Add support for international date/time formatting
1 parent f1dd892 commit 2d80770

File tree

10 files changed

+111
-35
lines changed

10 files changed

+111
-35
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ In order to run this project on your device, you will need to setup an applicati
4646
- Home view with track metadata and album art
4747
- Cover Art only view
4848
- Clock view with time and playback progress
49+
- Supports 12-hour and 24-hour time formats
4950
- Diagnostics view with system stats and Spotify state
5051

5152
- **OAuth 2.0 Authorization Flow**
@@ -60,6 +61,7 @@ In order to run this project on your device, you will need to setup an applicati
6061
- Modular architecture allows easy addition of new Views (UI screens)
6162
- Built-in monitoring tools for measuring system performance and UI responsiveness
6263
- Structured and tag-based logging system for easier debugging and analysis
64+
- Optional `user.ini` file for easy credential and time zone management
6365

6466

6567
<!--Design Context Diagram -->

data/user.ini.template

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ client_secret = Enter your Spotify Client Secret here
2626
; System Settings:
2727
; Timezone format - see
2828
; https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
29+
; For US date and time formatting, include:
30+
; ui_date_time_format = US
2931
; ----------------------------------------------------------------------
3032
[system]
31-
timezone = CST6CDT,M3.2.0,M11.1.0
33+
timezone = CST6CDT,M3.2.0,M11.1.0
34+
ui_date_time_format = US

documentation/UserSettings.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ The template includes guidance on privacy levels and where to enter your credent
3434
| `[spotify]` | `client_id` | Your Spotify Developer App Client ID |
3535
| | `client_secret` | Your Spotify Developer App Client Secret |
3636
| `[system]` | `timezone` | POSIX timezone format string (see example or link below) |
37+
| | `ui_date_time_format` | Optional: `US` for 12-hour clock and month-first date format; omit or use other values for international formatting |
3738

3839
> 🔗 Refer to the [POSIX timezone list](https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv) for formatting guidance.
3940
@@ -113,6 +114,9 @@ client_secret = abcdefghijklmnopqrstuv1234567890
113114
; System Settings:
114115
; Timezone format - see
115116
; https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
117+
; For US date and time formatting, include:
118+
; ui_date_time_format = US
116119
; ----------------------------------------------------------------------
117120
[system]
118-
timezone = CST6CDT,M3.2.0,M11.1.0
121+
timezone = CST6CDT,M3.2.0,M11.1.0
122+
ui_date_time_format = US

src/DisplayUI.cpp

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,10 +1200,22 @@ void DisplayUI::rDrawString( const char *str,
12001200
** Draws the current time using clock font and updates only when values change.
12011201
** ===================================================================
12021202
*/
1203-
void DisplayUI::drawClockTime(bool isForceRepaint)
1203+
void DisplayUI::drawClockTime(bool isUSFormat, bool isForceRepaint)
12041204
{
1205+
const int fontSize = 128;
1206+
const int fontWidth = 76;
12051207

1206-
std::string hours = getCurrentTimestamp("%l").c_str();
1208+
int offset = 0;
1209+
std::string hours = "";
1210+
if (isUSFormat)
1211+
{
1212+
hours = getCurrentTimestamp("%l").c_str();
1213+
}
1214+
else
1215+
{
1216+
hours = getCurrentTimestamp("%H").c_str();
1217+
offset = 50;
1218+
}
12071219
std::string minutes = getCurrentTimestamp("%M").c_str();
12081220
std::string ampm = getCurrentTimestamp("%p").c_str();
12091221
std::string seconds = getCurrentTimestamp("%S").c_str();
@@ -1212,51 +1224,55 @@ void DisplayUI::drawClockTime(bool isForceRepaint)
12121224
static std::string lastMinutes = "";
12131225
static std::string lastAmpm = "";
12141226

1215-
const int fontSize = 128;
1216-
const int fontWidth = 76;
1217-
1227+
// Hours
12181228
if ((lastHours != hours)
12191229
|| isForceRepaint)
12201230
{
1221-
_tft->fillRect(20, 35, fontWidth * 2, 100, toValue(getBackground()));
1222-
drawClockString(hours.c_str(), 20, 25, fontSize, TFTColor::White, getBackground());
1231+
_tft->fillRect(20 + offset, 35, fontWidth * 2, 100, toValue(getBackground()));
1232+
drawClockString(hours.c_str(), 20 + offset, 25, fontSize, TFTColor::White, getBackground());
12231233
lastHours = hours;
12241234
}
12251235

1236+
// Seconds indicator :
12261237
static bool isLastColonVisible = true;
12271238
int iSeconds = std::stoi(seconds);
12281239
bool isCurrentColonVisible = (iSeconds % 2 == 0);
12291240
if (isCurrentColonVisible != isLastColonVisible
12301241
|| isForceRepaint)
12311242
{
1232-
_tft->fillRect(180, 53, 35, 84, toValue(getBackground()));
1243+
_tft->fillRect(180 + offset, 53, 35, 84, toValue(getBackground()));
12331244
const char* colonChar = isCurrentColonVisible ? ":" : " ";
1234-
drawClockString(colonChar, 160, 20, fontSize, TFTColor::Yellow, getBackground());
1245+
drawClockString(colonChar, 160 + offset, 20, fontSize, TFTColor::Yellow, getBackground());
12351246
isLastColonVisible = isCurrentColonVisible;
12361247
}
12371248

1249+
// Minutes
12381250
if ((lastMinutes != minutes)
12391251
|| isForceRepaint)
12401252
{
1241-
_tft->fillRect(225, 35, fontWidth * 2, 100, toValue(getBackground()));
1242-
drawClockString(minutes.c_str(), 220, 25, fontSize, TFTColor::White, getBackground());
1253+
_tft->fillRect(225 + offset, 35, fontWidth * 2, 100, toValue(getBackground()));
1254+
drawClockString(minutes.c_str(), 220 + offset, 25, fontSize, TFTColor::White, getBackground());
12431255
lastMinutes = minutes;
12441256
}
12451257

1246-
if ((lastAmpm != ampm)
1247-
|| isForceRepaint)
1248-
{
1249-
_tft->fillRect(380, 40, fontWidth, 100, toValue(getBackground())); //toValue(getBackground()));
1250-
if (ampm == "AM")
1251-
{
1252-
drawClockString(ampm.c_str(), 380, 35, fontSize / 2, TFTColor::Yellow, getBackground());
1253-
}
1254-
else
1255-
{
1256-
drawClockString(ampm.c_str(), 380, 80, fontSize / 2, TFTColor::Yellow, getBackground());
1257-
}
1258-
1259-
lastAmpm = ampm;
1258+
// AM/PM if US Format
1259+
if (isUSFormat)
1260+
{
1261+
if ((lastAmpm != ampm)
1262+
|| isForceRepaint)
1263+
{
1264+
_tft->fillRect(380, 40, fontWidth, 100, toValue(getBackground())); //toValue(getBackground()));
1265+
if (ampm == "AM")
1266+
{
1267+
drawClockString(ampm.c_str(), 380, 35, fontSize / 2, TFTColor::Yellow, getBackground());
1268+
}
1269+
else
1270+
{
1271+
drawClockString(ampm.c_str(), 380, 80, fontSize / 2, TFTColor::Yellow, getBackground());
1272+
}
1273+
1274+
lastAmpm = ampm;
1275+
}
12601276
}
12611277
}
12621278

src/DisplayUI.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class DisplayUI {
161161
TFTColor bg,
162162
const char *clearMask);
163163

164-
void drawClockTime(bool isForceRepaint);
164+
void drawClockTime(bool isUSFormat, bool isForceRepaint);
165165

166166
void showTouchDown(TFTColor color = TFTColor::SC_TouchDown);
167167
void showTouchUp();

src/UIViews/ClockView.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "ThingPulse/util.h"
2323
#include "SpotifyArtMgr.h"
2424
#include "Renderers/BackButtonRenderer.h"
25+
#include "Vault.h"
2526

2627
/*
2728
** ===================================================================
@@ -87,7 +88,7 @@ void ClockView::drawUI()
8788
if (millis() > _requestDueTime)
8889
{
8990
handleDate(false);
90-
_pUI->drawClockTime(false);
91+
_pUI->drawClockTime(Vault::getInstance().isUSDateTimeFormattingUsed(),false);
9192
char s[50];
9293
snprintf(s, sizeof(s), "%s", getCurrentTimestamp("%Y-%m-%d %H:%M:%S").c_str());
9394
}
@@ -290,7 +291,12 @@ void ClockView::handlePlayStatus(bool isForcedUpdate)
290291
*/
291292
void ClockView::handleDate(bool isForceRefresh)
292293
{
293-
std::string dateStr = getCurrentTimestamp("%A %B %d %Y").c_str();
294+
std::string format = UI_DATE_FORMAT;
295+
if (Vault::getInstance().isUSDateTimeFormattingUsed())
296+
{
297+
format = UI_DATE_FORMAT_US;
298+
}
299+
std::string dateStr = getCurrentTimestamp(format.c_str()).c_str();
294300
static std::string lastDate = "";
295301

296302
if ((lastDate != dateStr)
@@ -386,7 +392,7 @@ void ClockView::enteringView()
386392
// Make sure the UI is painted fresh
387393
_pUI->setBackground(TFTColor::DarkestGreen, false);
388394
_pUI->clearScreenHome();
389-
_pUI->drawClockTime(true);
395+
_pUI->drawClockTime(Vault::getInstance().isUSDateTimeFormattingUsed(), true);
390396
_pUI->markUIDirty(true); // force refresh to get album details
391397

392398
}

src/UIViews/HomeView.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "Renderers/PreviousTrackButtonRenderer.h"
2525
#include "Renderers/PlayPauseButtonRenderer.h"
2626
#include "Renderers/NextTrackButtonRenderer.h"
27+
#include "Vault.h"
2728

2829
/*
2930
** ===================================================================
@@ -341,19 +342,26 @@ void HomeView::handlePlayStatus()
341342
** changed.
342343
**
343344
** Notes:
344-
** - The time is displayed in the format "XX:XX PM".
345+
** - The time is displayed in the format "XX:XX PM" if US formatting is used.
345346
** - If the current time differs from the last displayed time or
346347
** if a forced repaint is requested, the time is redrawn.
347348
** ===================================================================
348349
*/
349350
void HomeView::handleClock(bool isPaintForced)
350351
{
351-
std::string timeStr = getCurrentTimestamp("%l:%M %p").c_str();
352+
std::string format = UI_TIME_FORMAT;
353+
int offset = 10;
354+
if (Vault::getInstance().isUSDateTimeFormattingUsed())
355+
{
356+
format = UI_TIME_FORMAT_US;
357+
offset = 0;
358+
}
359+
std::string timeStr = getCurrentTimestamp(format.c_str()).c_str();
352360
static std::string lastTime = "X:XX/X:XX";
353361
if ((lastTime != timeStr)
354362
|| (isPaintForced))
355363
{
356-
_pUI->lDrawString(timeStr.c_str(), 310, 287, 20, TFTColor::DarkGreen, TFTColor::Black,"XX:XX PM");
364+
_pUI->lDrawString(timeStr.c_str(), 310 + offset, 287, 20, TFTColor::DarkGreen, TFTColor::Black,"XX:XX PM");
357365
lastTime = timeStr;
358366
}
359367
}

src/Vault.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ void Vault::initialize()
203203
{
204204
strncpy(_timezone.data(), value.c_str(), _timezone.size() - 1);
205205
}
206+
else if (key == "ui_date_time_format")
207+
{
208+
value.toLowerCase();
209+
_dateTimeFormatUS = (value == "us");
210+
}
206211
}
207212
else if (section == "vault")
208213
{
@@ -714,3 +719,19 @@ std::array<uint8_t, 16> Vault::getAesKey(bool tiedToDevice)
714719
return finalKey;
715720
}
716721

722+
/*
723+
** ===================================================================
724+
** isUSDateTimeFormattingUsed()
725+
**
726+
** Determines whether US-style date/time formatting should be used.
727+
** ===================================================================
728+
*/
729+
bool Vault::isUSDateTimeFormattingUsed()
730+
{
731+
if (_useHardcodedValues)
732+
{
733+
return Use_US_Date_Time_Format;
734+
}
735+
736+
return _dateTimeFormatUS;
737+
}

src/Vault.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class Vault
7979
String getSpotifyClientID();
8080
String getSpotifyClientSecret();
8181
String getTimezone();
82+
bool isUSDateTimeFormattingUsed();
8283

8384
private:
8485
Vault();
@@ -87,7 +88,8 @@ class Vault
8788
String decrypt(const String& encryptedBase64, bool tiedToDevice);
8889
void printEncryptionHints();
8990
bool _useHardcodedValues = true;
90-
VaultPrivacyLevel _privacyLevel = VaultPrivacyLevel::None;
91+
VaultPrivacyLevel _privacyLevel = VaultPrivacyLevel::None;
92+
bool _dateTimeFormatUS = false;
9193
std::array<char, VAULT_MAX_CRED_LENGTH> _ssid{};
9294
std::array<char, VAULT_MAX_CRED_LENGTH> _wifiPwd{};
9395
std::array<char, VAULT_MAX_CRED_LENGTH> _clientId{};

src/settings.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ static const char *SPOTIFY_CLIENT_SECRET = "SPOTIFY_CLIENT_SECRET goes here";
4141
// https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
4242
#define TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3"
4343

44+
// format specifiers: https://cplusplus.com/reference/ctime/strftime/
45+
// values below are tested. updating the formatting may affect UI layout.
46+
47+
// Set to true to use US date/time formatting (12 hour times and US dates)
48+
static const bool Use_US_Date_Time_Format = false;
49+
50+
// Formatting consistent with norms in the United States
51+
#define UI_DATE_FORMAT_US "%A %B %d %Y"
52+
#define UI_TIME_FORMAT_US "%l:%M %p"
53+
54+
// Formatting consistent with many countries outside the United States
55+
#define UI_DATE_FORMAT "%A %d %B %Y"
56+
#define UI_TIME_FORMAT "%H:%M"
57+
4458
/*
4559
** ===================================================================
4660
** Version and Name Information

0 commit comments

Comments
 (0)