Add customization screens for stocks and indices with on-screen keyboard
- Stock ticker customization with QWERTY keyboard input (up to 5 tickers) - Index selection from scrollable multi-select list (up to 5 indices) - Friendly index names displayed (S&P 500, Dow Jones, NASDAQ, etc.) - CUSTOMIZE button in dashboard footer - Config persisted to ESP32 Preferences - REFRESHING... message shown when returning from customization - Auto-refresh every 5 minutes
This commit is contained in:
parent
99fd266b47
commit
fcde8cf66b
1 changed files with 530 additions and 48 deletions
560
src/main.cpp
560
src/main.cpp
|
|
@ -1,7 +1,8 @@
|
|||
/**
|
||||
* Bitcoin Dashboard for Elecrow 7-inch HMI Display
|
||||
* Three-column layout with antialiased fonts
|
||||
*/
|
||||
* Bitcoin Dashboard for Elecrow 7-inch HMI Display
|
||||
* Three-column layout with antialiased fonts
|
||||
* Customization screen for stocks and indices
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <LovyanGFX.hpp>
|
||||
|
|
@ -22,6 +23,12 @@
|
|||
#define TFT_GOLD 0xFEA0
|
||||
#define TFT_SILVER 0xC618
|
||||
#define TFT_GREEN 0x07E0
|
||||
#define TFT_DARKGRAY 0x2104
|
||||
#define TFT_GRAY 0x8410
|
||||
|
||||
#define MAX_STOCKS 5
|
||||
#define MAX_INDICES 5
|
||||
#define MAX_TICKER_LEN 8
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device {
|
||||
public:
|
||||
|
|
@ -114,12 +121,51 @@ static LGFX lcd;
|
|||
static Preferences preferences;
|
||||
|
||||
double btcPrice = 0, goldPrice = 0, silverPrice = 0;
|
||||
double mstrPrice = 0, strtPrice = 0;
|
||||
double nasdaqPrice = 0, dowPrice = 0, spxPrice = 0;
|
||||
double stockPrices[MAX_STOCKS] = {0};
|
||||
double indexPrices[MAX_INDICES] = {0};
|
||||
|
||||
char stockTickers[MAX_STOCKS][MAX_TICKER_LEN + 1] = {"MSTR", "STRC", "", "", ""};
|
||||
char indexTickers[MAX_INDICES][MAX_TICKER_LEN + 1] = {"^IXIC", "^DJI", "^GSPC", "", ""};
|
||||
bool indexSelected[MAX_INDICES] = {true, true, true, false, false};
|
||||
|
||||
const char* availableIndices[] = {
|
||||
"^GSPC", "^DJI", "^IXIC", "^RUT", "^VIX",
|
||||
"^FTSE", "^GDAXI", "^FCHI", "^N225", "^HSI",
|
||||
"^AXJO", "^KS11", "^TWII", "^STI", "^MXX"
|
||||
};
|
||||
const char* indexNames[] = {
|
||||
"S&P 500", "Dow Jones", "NASDAQ", "Russell 2000", "VIX",
|
||||
"FTSE 100", "DAX", "CAC 40", "Nikkei 225", "Hang Seng",
|
||||
"ASX 200", "KOSPI", "Taiwan Weighted", "Straits Times", "IPC Mexico"
|
||||
};
|
||||
const int numAvailableIndices = 15;
|
||||
|
||||
const char* getIndexFriendlyName(const char* ticker) {
|
||||
for (int i = 0; i < numAvailableIndices; i++) {
|
||||
if (strcmp(ticker, availableIndices[i]) == 0) {
|
||||
return indexNames[i];
|
||||
}
|
||||
}
|
||||
return ticker;
|
||||
}
|
||||
|
||||
unsigned long lastRefresh = 0;
|
||||
const unsigned long REFRESH_INTERVAL = 300000;
|
||||
|
||||
enum ScreenState {
|
||||
SCREEN_DASHBOARD,
|
||||
SCREEN_CUSTOMIZE_STOCKS,
|
||||
SCREEN_CUSTOMIZE_INDICES
|
||||
};
|
||||
ScreenState currentScreen = SCREEN_DASHBOARD;
|
||||
|
||||
int selectedStockSlot = -1;
|
||||
int selectedIndexSlot = -1;
|
||||
char keyboardBuffer[MAX_TICKER_LEN + 1] = "";
|
||||
int keyboardPos = 0;
|
||||
int indexScrollOffset = 0;
|
||||
bool needsRefresh = false;
|
||||
|
||||
String formatPriceUS(double price, int decimals = 2, bool includeDollar = true) {
|
||||
if (price <= 0) return "...";
|
||||
|
||||
|
|
@ -183,16 +229,216 @@ bool fetchPrice(const char* symbol, double* result) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void loadConfig() {
|
||||
preferences.begin("dashboard", true);
|
||||
|
||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||
String key = "stock" + String(i);
|
||||
String val = preferences.getString(key.c_str(), "");
|
||||
if (val.length() > 0 && val.length() <= MAX_TICKER_LEN) {
|
||||
strcpy(stockTickers[i], val.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_INDICES; i++) {
|
||||
String key = "index" + String(i);
|
||||
String val = preferences.getString(key.c_str(), "");
|
||||
if (val.length() > 0 && val.length() <= MAX_TICKER_LEN) {
|
||||
strcpy(indexTickers[i], val.c_str());
|
||||
indexSelected[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
preferences.end();
|
||||
}
|
||||
|
||||
void saveConfig() {
|
||||
preferences.begin("dashboard", false);
|
||||
|
||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||
String key = "stock" + String(i);
|
||||
preferences.putString(key.c_str(), stockTickers[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_INDICES; i++) {
|
||||
String key = "index" + String(i);
|
||||
if (indexSelected[i]) {
|
||||
preferences.putString(key.c_str(), indexTickers[i]);
|
||||
} else {
|
||||
preferences.putString(key.c_str(), "");
|
||||
}
|
||||
}
|
||||
|
||||
preferences.end();
|
||||
}
|
||||
|
||||
void updatePrices() {
|
||||
if (WiFi.status() != WL_CONNECTED) return;
|
||||
fetchPrice("BTC-USD", &btcPrice);
|
||||
fetchPrice("GC=F", &goldPrice);
|
||||
fetchPrice("SI=F", &silverPrice);
|
||||
fetchPrice("MSTR", &mstrPrice);
|
||||
fetchPrice("STRC", &strtPrice);
|
||||
fetchPrice("^IXIC", &nasdaqPrice);
|
||||
fetchPrice("^DJI", &dowPrice);
|
||||
fetchPrice("^GSPC", &spxPrice);
|
||||
|
||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||
if (strlen(stockTickers[i]) > 0) {
|
||||
fetchPrice(stockTickers[i], &stockPrices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_INDICES; i++) {
|
||||
if (indexSelected[i] && strlen(indexTickers[i]) > 0) {
|
||||
fetchPrice(indexTickers[i], &indexPrices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawKeyboard(int y) {
|
||||
const char* rows[] = {
|
||||
"QWERTYUIOP",
|
||||
"ASDFGHJKL",
|
||||
"ZXCVBNM",
|
||||
"1234567890"
|
||||
};
|
||||
const int numRows = 4;
|
||||
const int keySize = 32;
|
||||
const int keyGap = 2;
|
||||
|
||||
for (int r = 0; r < numRows; r++) {
|
||||
int rowLen = strlen(rows[r]);
|
||||
int rowWidth = rowLen * (keySize + keyGap) - keyGap;
|
||||
int startX = (SCREEN_WIDTH - rowWidth) / 2;
|
||||
int keyY = y + r * (keySize + keyGap);
|
||||
|
||||
for (int k = 0; k < rowLen; k++) {
|
||||
int keyX = startX + k * (keySize + keyGap);
|
||||
lcd.fillSmoothRoundRect(keyX, keyY, keySize, keySize, 4, TFT_DARKGRAY);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_DARKGRAY);
|
||||
lcd.setFont(&fonts::DejaVu12);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawChar(rows[r][k], keyX + keySize/2, keyY + keySize/2);
|
||||
}
|
||||
}
|
||||
|
||||
int btnY = y + numRows * (keySize + keyGap) + 4;
|
||||
int delX = SCREEN_WIDTH / 2 - 125;
|
||||
int enterX = SCREEN_WIDTH / 2 + 5;
|
||||
|
||||
lcd.fillSmoothRoundRect(delX, btnY, 120, 32, 6, TFT_ORANGE);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.drawString("DEL", delX + 60, btnY + 16);
|
||||
|
||||
lcd.fillSmoothRoundRect(enterX, btnY, 120, 32, 6, TFT_GREEN);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_GREEN);
|
||||
lcd.drawString("SAVE", enterX + 60, btnY + 16);
|
||||
}
|
||||
|
||||
void drawStockCustomizeScreen() {
|
||||
lcd.fillScreen(TFT_BLACK);
|
||||
|
||||
lcd.fillSmoothRoundRect(0, 0, SCREEN_WIDTH, 50, 8, TFT_ORANGE);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||
lcd.setFont(&fonts::DejaVu24);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("CUSTOMIZE STOCKS (up to 5)", SCREEN_WIDTH / 2, 25);
|
||||
|
||||
int slotY = 60;
|
||||
int slotHeight = 36;
|
||||
|
||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||
int y = slotY + i * (slotHeight + 8);
|
||||
uint16_t bgColor = (selectedStockSlot == i) ? TFT_ORANGE : TFT_DARKGRAY;
|
||||
|
||||
lcd.fillSmoothRoundRect(200, y, 400, slotHeight, 6, bgColor);
|
||||
lcd.setTextColor(TFT_WHITE, bgColor);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_left);
|
||||
lcd.drawString(String(i + 1) + ":", 210, y + slotHeight/2);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
|
||||
String displayText;
|
||||
if (selectedStockSlot == i) {
|
||||
displayText = String(keyboardBuffer);
|
||||
if (displayText.length() == 0) displayText = "_";
|
||||
} else {
|
||||
displayText = strlen(stockTickers[i]) > 0 ? String(stockTickers[i]) : "(tap to edit)";
|
||||
}
|
||||
lcd.drawString(displayText, 400, y + slotHeight/2);
|
||||
}
|
||||
|
||||
drawKeyboard(slotY + MAX_STOCKS * (slotHeight + 8) + 20);
|
||||
|
||||
lcd.fillSmoothRoundRect(20, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GRAY);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_GRAY);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("BACK", 95, SCREEN_HEIGHT - 30);
|
||||
|
||||
lcd.fillSmoothRoundRect(SCREEN_WIDTH - 170, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GREEN);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_GREEN);
|
||||
lcd.drawString("INDICES >", SCREEN_WIDTH - 95, SCREEN_HEIGHT - 30);
|
||||
}
|
||||
|
||||
void drawIndexCustomizeScreen() {
|
||||
lcd.fillScreen(TFT_BLACK);
|
||||
|
||||
lcd.fillSmoothRoundRect(0, 0, SCREEN_WIDTH, 50, 8, TFT_ORANGE);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||
lcd.setFont(&fonts::DejaVu24);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("CUSTOMIZE INDICES (select up to 5)", SCREEN_WIDTH / 2, 25);
|
||||
|
||||
int listY = 60;
|
||||
int itemHeight = 40;
|
||||
int visibleItems = 8;
|
||||
|
||||
for (int i = 0; i < visibleItems; i++) {
|
||||
int idx = indexScrollOffset + i;
|
||||
if (idx >= numAvailableIndices) break;
|
||||
|
||||
int y = listY + i * (itemHeight + 4);
|
||||
bool isSelected = false;
|
||||
for (int j = 0; j < MAX_INDICES; j++) {
|
||||
if (indexSelected[j] && strcmp(indexTickers[j], availableIndices[idx]) == 0) {
|
||||
isSelected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t bgColor = isSelected ? TFT_GREEN : TFT_DARKGRAY;
|
||||
lcd.fillSmoothRoundRect(150, y, 500, itemHeight, 6, bgColor);
|
||||
lcd.setTextColor(TFT_WHITE, bgColor);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_left);
|
||||
lcd.drawString(indexNames[idx], 170, y + itemHeight/2);
|
||||
|
||||
if (isSelected) {
|
||||
lcd.setTextDatum(textdatum_t::middle_right);
|
||||
lcd.drawString("SELECTED", 630, y + itemHeight/2);
|
||||
}
|
||||
}
|
||||
|
||||
if (indexScrollOffset > 0) {
|
||||
lcd.fillSmoothRoundRect(380, listY - 30, 40, 24, 4, TFT_GRAY);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_GRAY);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("^", 400, listY - 18);
|
||||
}
|
||||
|
||||
if (indexScrollOffset + visibleItems < numAvailableIndices) {
|
||||
lcd.fillSmoothRoundRect(380, listY + visibleItems * (itemHeight + 4) + 8, 40, 24, 4, TFT_GRAY);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_GRAY);
|
||||
lcd.drawString("v", 400, listY + visibleItems * (itemHeight + 4) + 20);
|
||||
}
|
||||
|
||||
lcd.fillSmoothRoundRect(20, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GRAY);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_GRAY);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("SAVE", 95, SCREEN_HEIGHT - 30);
|
||||
|
||||
lcd.fillSmoothRoundRect(SCREEN_WIDTH - 170, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GRAY);
|
||||
lcd.drawString("CANCEL", SCREEN_WIDTH - 95, SCREEN_HEIGHT - 30);
|
||||
}
|
||||
|
||||
void drawDashboard() {
|
||||
|
|
@ -210,7 +456,7 @@ void drawDashboard() {
|
|||
int col2X = 280;
|
||||
int col3X = 540;
|
||||
int labelY = 60;
|
||||
int priceY = labelY + 32;
|
||||
int priceY = labelY + 28;
|
||||
|
||||
lcd.setTextColor(TFT_ORANGE, TFT_BLACK);
|
||||
lcd.setFont(&fonts::Roboto_Thin_24);
|
||||
|
|
@ -218,37 +464,247 @@ void drawDashboard() {
|
|||
lcd.drawString(formatPriceUS(btcPrice, 0), col1X, priceY);
|
||||
|
||||
lcd.setTextColor(TFT_GOLD, TFT_BLACK);
|
||||
lcd.drawString("Gold:", col1X, labelY + 70);
|
||||
lcd.drawString(formatPriceUS(goldPrice, 2), col1X, priceY + 70);
|
||||
lcd.drawString("Gold:", col1X, labelY + 65);
|
||||
lcd.drawString(formatPriceUS(goldPrice, 2), col1X, priceY + 65);
|
||||
|
||||
lcd.setTextColor(TFT_SILVER, TFT_BLACK);
|
||||
lcd.drawString("Silver:", col1X, labelY + 140);
|
||||
lcd.drawString(formatPriceUS(silverPrice, 2), col1X, priceY + 140);
|
||||
lcd.drawString("Silver:", col1X, labelY + 130);
|
||||
lcd.drawString(formatPriceUS(silverPrice, 2), col1X, priceY + 130);
|
||||
|
||||
lcd.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||
lcd.drawString("MSTR:", col2X, labelY);
|
||||
lcd.drawString(formatPriceUS(mstrPrice, 2), col2X, priceY);
|
||||
int stockY = labelY;
|
||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||
if (strlen(stockTickers[i]) > 0) {
|
||||
lcd.drawString(String(stockTickers[i]) + ":", col2X, stockY);
|
||||
lcd.drawString(formatPriceUS(stockPrices[i], 2), col2X, stockY + 28);
|
||||
stockY += 65;
|
||||
}
|
||||
}
|
||||
|
||||
lcd.drawString("STRC:", col2X, labelY + 70);
|
||||
lcd.drawString(formatPriceUS(strtPrice, 2), col2X, priceY + 70);
|
||||
|
||||
lcd.drawString("NASDAQ:", col3X, labelY);
|
||||
lcd.drawString(formatPriceUS(nasdaqPrice, 2), col3X, priceY);
|
||||
|
||||
lcd.drawString("DOW:", col3X, labelY + 70);
|
||||
lcd.drawString(formatPriceUS(dowPrice, 2), col3X, priceY + 70);
|
||||
|
||||
lcd.drawString("SPX:", col3X, labelY + 140);
|
||||
lcd.drawString(formatPriceUS(spxPrice, 2), col3X, priceY + 140);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
int indexY = labelY;
|
||||
for (int i = 0; i < MAX_INDICES; i++) {
|
||||
if (indexSelected[i] && strlen(indexTickers[i]) > 0) {
|
||||
lcd.drawString(String(getIndexFriendlyName(indexTickers[i])) + ":", col3X, indexY);
|
||||
lcd.drawString(formatPriceUS(indexPrices[i], 2), col3X, indexY + 28);
|
||||
indexY += 65;
|
||||
}
|
||||
}
|
||||
|
||||
lcd.fillSmoothRoundRect(0, SCREEN_HEIGHT - 40, SCREEN_WIDTH, 40, 8, TFT_ORANGE);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_left);
|
||||
String wifiStatus = WiFi.status() == WL_CONNECTED ? "Connected" : "DISCONNECTED";
|
||||
String wifiStatus = WiFi.status() == WL_CONNECTED ? "OK" : "OFFLINE";
|
||||
lcd.drawString("WiFi: " + wifiStatus, 20, SCREEN_HEIGHT - 20);
|
||||
|
||||
lcd.fillSmoothRoundRect(SCREEN_WIDTH - 160, SCREEN_HEIGHT - 36, 140, 32, 6, TFT_DARKGRAY);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("TOUCH TO REFRESH", SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
|
||||
lcd.drawString("CUSTOMIZE", SCREEN_WIDTH - 90, SCREEN_HEIGHT - 20);
|
||||
}
|
||||
|
||||
bool handleKeyboardTouch(int32_t x, int32_t y, int keyboardY) {
|
||||
const char* rows[] = {
|
||||
"QWERTYUIOP",
|
||||
"ASDFGHJKL",
|
||||
"ZXCVBNM",
|
||||
"1234567890"
|
||||
};
|
||||
const int numRows = 4;
|
||||
const int keySize = 32;
|
||||
const int keyGap = 2;
|
||||
|
||||
for (int r = 0; r < numRows; r++) {
|
||||
int rowLen = strlen(rows[r]);
|
||||
int rowWidth = rowLen * (keySize + keyGap) - keyGap;
|
||||
int startX = (SCREEN_WIDTH - rowWidth) / 2;
|
||||
int keyY = keyboardY + r * (keySize + keyGap);
|
||||
|
||||
for (int k = 0; k < rowLen; k++) {
|
||||
int keyX = startX + k * (keySize + keyGap);
|
||||
if (x >= keyX && x < keyX + keySize && y >= keyY && y < keyY + keySize) {
|
||||
if (keyboardPos < MAX_TICKER_LEN) {
|
||||
keyboardBuffer[keyboardPos++] = rows[r][k];
|
||||
keyboardBuffer[keyboardPos] = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int btnY = keyboardY + numRows * (keySize + keyGap) + 4;
|
||||
int delX = SCREEN_WIDTH / 2 - 125;
|
||||
int enterX = SCREEN_WIDTH / 2 + 5;
|
||||
|
||||
if (x >= delX && x < delX + 120 && y >= btnY && y < btnY + 32) {
|
||||
if (keyboardPos > 0) {
|
||||
keyboardPos--;
|
||||
keyboardBuffer[keyboardPos] = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x >= enterX && x < enterX + 120 && y >= btnY && y < btnY + 32) {
|
||||
if (selectedStockSlot >= 0) {
|
||||
strcpy(stockTickers[selectedStockSlot], keyboardBuffer);
|
||||
selectedStockSlot = -1;
|
||||
keyboardPos = 0;
|
||||
keyboardBuffer[0] = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handleStockCustomizeTouch(int32_t x, int32_t y) {
|
||||
int slotY = 60;
|
||||
int slotHeight = 36;
|
||||
|
||||
if (x >= 20 && x < 170 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) {
|
||||
if (selectedStockSlot >= 0 && keyboardPos > 0) {
|
||||
strcpy(stockTickers[selectedStockSlot], keyboardBuffer);
|
||||
}
|
||||
saveConfig();
|
||||
currentScreen = SCREEN_DASHBOARD;
|
||||
needsRefresh = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x >= SCREEN_WIDTH - 170 && x < SCREEN_WIDTH - 20 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) {
|
||||
if (selectedStockSlot >= 0 && keyboardPos > 0) {
|
||||
strcpy(stockTickers[selectedStockSlot], keyboardBuffer);
|
||||
}
|
||||
saveConfig();
|
||||
currentScreen = SCREEN_CUSTOMIZE_INDICES;
|
||||
indexScrollOffset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||
int sy = slotY + i * (slotHeight + 8);
|
||||
if (x >= 200 && x < 600 && y >= sy && y < sy + slotHeight) {
|
||||
if (selectedStockSlot >= 0 && selectedStockSlot != i && keyboardPos > 0) {
|
||||
strcpy(stockTickers[selectedStockSlot], keyboardBuffer);
|
||||
}
|
||||
selectedStockSlot = i;
|
||||
strcpy(keyboardBuffer, stockTickers[i]);
|
||||
keyboardPos = strlen(keyboardBuffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedStockSlot >= 0) {
|
||||
int keyboardY = slotY + MAX_STOCKS * (slotHeight + 8) + 20;
|
||||
if (handleKeyboardTouch(x, y, keyboardY)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handleIndexCustomizeTouch(int32_t x, int32_t y) {
|
||||
int listY = 60;
|
||||
int itemHeight = 40;
|
||||
int visibleItems = 8;
|
||||
|
||||
if (x >= 20 && x < 170 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) {
|
||||
saveConfig();
|
||||
currentScreen = SCREEN_DASHBOARD;
|
||||
needsRefresh = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x >= SCREEN_WIDTH - 170 && x < SCREEN_WIDTH - 20 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) {
|
||||
currentScreen = SCREEN_DASHBOARD;
|
||||
loadConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x >= 380 && x < 420 && y >= listY - 30 && y < listY - 6) {
|
||||
if (indexScrollOffset > 0) {
|
||||
indexScrollOffset--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x >= 380 && x < 420 && y >= listY + visibleItems * (itemHeight + 4) + 8 && y < listY + visibleItems * (itemHeight + 4) + 32) {
|
||||
if (indexScrollOffset + visibleItems < numAvailableIndices) {
|
||||
indexScrollOffset++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < visibleItems; i++) {
|
||||
int idx = indexScrollOffset + i;
|
||||
if (idx >= numAvailableIndices) break;
|
||||
|
||||
int iy = listY + i * (itemHeight + 4);
|
||||
if (x >= 150 && x < 650 && y >= iy && y < iy + itemHeight) {
|
||||
bool alreadySelected = false;
|
||||
int selectedSlot = -1;
|
||||
|
||||
for (int j = 0; j < MAX_INDICES; j++) {
|
||||
if (indexSelected[j] && strcmp(indexTickers[j], availableIndices[idx]) == 0) {
|
||||
alreadySelected = true;
|
||||
selectedSlot = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadySelected) {
|
||||
indexSelected[selectedSlot] = false;
|
||||
indexTickers[selectedSlot][0] = '\0';
|
||||
} else {
|
||||
int count = 0;
|
||||
for (int j = 0; j < MAX_INDICES; j++) {
|
||||
if (indexSelected[j]) count++;
|
||||
}
|
||||
|
||||
if (count < MAX_INDICES) {
|
||||
for (int j = 0; j < MAX_INDICES; j++) {
|
||||
if (!indexSelected[j]) {
|
||||
strcpy(indexTickers[j], availableIndices[idx]);
|
||||
indexSelected[j] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void showRefreshingMessage() {
|
||||
lcd.fillSmoothRoundRect(0, SCREEN_HEIGHT - 40, SCREEN_WIDTH, 40, 8, TFT_ORANGE);
|
||||
lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.drawString("REFRESHING...", SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
|
||||
}
|
||||
|
||||
void refreshDataAndShow() {
|
||||
drawDashboard();
|
||||
showRefreshingMessage();
|
||||
updatePrices();
|
||||
lastRefresh = millis();
|
||||
drawDashboard();
|
||||
}
|
||||
|
||||
bool handleDashboardTouch(int32_t x, int32_t y) {
|
||||
if (x >= SCREEN_WIDTH - 160 && x < SCREEN_WIDTH - 20 && y >= SCREEN_HEIGHT - 36 && y < SCREEN_HEIGHT - 4) {
|
||||
currentScreen = SCREEN_CUSTOMIZE_STOCKS;
|
||||
selectedStockSlot = -1;
|
||||
keyboardPos = 0;
|
||||
keyboardBuffer[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
|
@ -273,6 +729,8 @@ void setup() {
|
|||
lcd.setFont(&fonts::DejaVu18);
|
||||
lcd.drawString("Starting...", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
|
||||
|
||||
loadConfig();
|
||||
|
||||
preferences.begin("wifi", true);
|
||||
String ssid = preferences.getString("ssid", "");
|
||||
String pass = preferences.getString("password", "");
|
||||
|
|
@ -314,21 +772,45 @@ void setup() {
|
|||
void loop() {
|
||||
int32_t x, y;
|
||||
|
||||
if (lcd.getTouch(&x, &y)) {
|
||||
lcd.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
lcd.setFont(&fonts::DejaVu24);
|
||||
lcd.setTextDatum(textdatum_t::middle_center);
|
||||
lcd.fillRect(0, SCREEN_HEIGHT / 2 - 20, SCREEN_WIDTH, 40, TFT_BLACK);
|
||||
lcd.drawString("Refreshing...", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
|
||||
if (needsRefresh && currentScreen == SCREEN_DASHBOARD) {
|
||||
needsRefresh = false;
|
||||
drawDashboard();
|
||||
refreshDataAndShow();
|
||||
}
|
||||
|
||||
if (lcd.getTouch(&x, &y)) {
|
||||
switch (currentScreen) {
|
||||
case SCREEN_DASHBOARD:
|
||||
handleDashboardTouch(x, y);
|
||||
break;
|
||||
case SCREEN_CUSTOMIZE_STOCKS:
|
||||
handleStockCustomizeTouch(x, y);
|
||||
break;
|
||||
case SCREEN_CUSTOMIZE_INDICES:
|
||||
handleIndexCustomizeTouch(x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!needsRefresh) {
|
||||
switch (currentScreen) {
|
||||
case SCREEN_DASHBOARD:
|
||||
updatePrices();
|
||||
lastRefresh = millis();
|
||||
drawDashboard();
|
||||
|
||||
delay(500);
|
||||
break;
|
||||
case SCREEN_CUSTOMIZE_STOCKS:
|
||||
drawStockCustomizeScreen();
|
||||
break;
|
||||
case SCREEN_CUSTOMIZE_INDICES:
|
||||
drawIndexCustomizeScreen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (millis() - lastRefresh > REFRESH_INTERVAL) {
|
||||
delay(300);
|
||||
}
|
||||
|
||||
if (currentScreen == SCREEN_DASHBOARD && millis() - lastRefresh > REFRESH_INTERVAL) {
|
||||
updatePrices();
|
||||
lastRefresh = millis();
|
||||
drawDashboard();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue