ESP32: добавить NAV v8 с account и Wi-Fi reconnect
This commit is contained in:
parent
e385bb6bf9
commit
f4e7210a40
@ -3,7 +3,7 @@
|
|||||||
- Краткое описание: минимальный UI-прототип для сабсервера на базе `LVGL + subserver touch`, с Wi-Fi flow, серверными адресами и общим экраном редактирования текста.
|
- Краткое описание: минимальный UI-прототип для сабсервера на базе `LVGL + subserver touch`, с Wi-Fi flow, серверными адресами и общим экраном редактирования текста.
|
||||||
- Что проверять:
|
- Что проверять:
|
||||||
- стартует экран `HOME`;
|
- стартует экран `HOME`;
|
||||||
- на `HOME` видны `login`, `subserver1`, `W BAT`, `STATUS`, Wi-Fi статус и кнопка `SETTINGS`;
|
- на `HOME` видны реальное значение логина или `login not set`, реальное значение сабсервера или `subserver not set`, при отсутствии секрета строка `secret not set`, а также `W BAT`, `STATUS`, Wi-Fi статус и кнопка `SETTINGS`;
|
||||||
- Wi-Fi статус на `HOME` корректно показывает одно из состояний:
|
- Wi-Fi статус на `HOME` корректно показывает одно из состояний:
|
||||||
- `Wi-Fi not configured`
|
- `Wi-Fi not configured`
|
||||||
- `Wi-Fi disconnected`
|
- `Wi-Fi disconnected`
|
||||||
@ -21,16 +21,25 @@
|
|||||||
- выбор SSID открывает общий экран редактирования текста для пароля;
|
- выбор SSID открывает общий экран редактирования текста для пароля;
|
||||||
- на этом экране видно старое значение, курсор стоит в конце;
|
- на этом экране видно старое значение, курсор стоит в конце;
|
||||||
- две верхние служебные строки над полем ввода отсутствуют;
|
- две верхние служебные строки над полем ввода отсутствуют;
|
||||||
|
- при вводе пароля Wi-Fi текст показывается открыто, без точек;
|
||||||
- большая клавиатура реально видна на экране и занимает большую часть высоты;
|
- большая клавиатура реально видна на экране и занимает большую часть высоты;
|
||||||
- буквы разбиты на 2 страницы;
|
- буквы разбиты на 2 страницы;
|
||||||
- режим символов тоже разбит на 2 страницы;
|
- режим символов тоже разбит на 2 страницы;
|
||||||
- на правой странице кнопки стоят в ровных вертикальных колонках;
|
- на правой странице кнопки стоят в ровных вертикальных колонках;
|
||||||
- свайп влево/вправо на экране ввода переключает страницы клавиатуры;
|
- свайп влево/вправо на экране ввода переключает страницы клавиатуры;
|
||||||
- при этом свайп страниц клавиатуры срабатывает только из нижней клавиатурной зоны, а не из верхней части экрана;
|
- при этом свайп страниц клавиатуры срабатывает только из нижней клавиатурной зоны, а не из верхней части экрана;
|
||||||
|
- при переключении `ABC/123` и `SHIFT` уже введённый текст не пропадает;
|
||||||
|
- при свайпе между левой и правой половиной клавиатуры уже введённый текст тоже не пропадает, в том числе для цифр, символов и заглавных букв;
|
||||||
|
- визуальный курсор в поле ввода не показывается;
|
||||||
|
- новые символы всегда дописываются только в конец строки;
|
||||||
|
- основные 3 ряда клавиш и нижний служебный ряд стали выше;
|
||||||
|
- внизу остаётся отдельная тёмная полоса с версией `NAV v7`, а рамка клавиатурного блока заканчивается выше неё;
|
||||||
- `ABC/123`, `SHIFT`, `DEL`, `SAVE`, `CANCEL` работают;
|
- `ABC/123`, `SHIFT`, `DEL`, `SAVE`, `CANCEL` работают;
|
||||||
- при успехе SSID и пароль сохраняются, а `HOME` показывает `Wi-Fi connected`;
|
- при успехе SSID и пароль сохраняются, а `HOME` показывает `Wi-Fi connected`;
|
||||||
- при ошибке показывается `Connection failed`;
|
- при ошибке показывается `Connection failed`;
|
||||||
- `CLEAR SAVED WI-FI` очищает сохранённые настройки;
|
- `CLEAR SAVED WI-FI` очищает сохранённые настройки;
|
||||||
|
- если сеть была ранее успешно сохранена, после потери связи устройство автоматически пытается переподключиться;
|
||||||
|
- первые повторные попытки идут раз в `10` секунд, а после долгого отсутствия связи интервал увеличивается до `30` секунд;
|
||||||
- нажатие `Server` открывает `SERVER_SCREEN`;
|
- нажатие `Server` открывает `SERVER_SCREEN`;
|
||||||
- в `SERVER_SCREEN` видны и редактируются два значения:
|
- в `SERVER_SCREEN` видны и редактируются два значения:
|
||||||
- `https://api.devnet.solana.com`
|
- `https://api.devnet.solana.com`
|
||||||
@ -38,7 +47,18 @@
|
|||||||
- нажатие `SOLANA RPC` открывает общий экран редактирования;
|
- нажатие `SOLANA RPC` открывает общий экран редактирования;
|
||||||
- нажатие `SHINE SERVER` открывает общий экран редактирования;
|
- нажатие `SHINE SERVER` открывает общий экран редактирования;
|
||||||
- после `SAVE` новые адреса сохраняются в NVS;
|
- после `SAVE` новые адреса сохраняются в NVS;
|
||||||
|
- нажатие `Account` открывает `ACCOUNT_SCREEN`;
|
||||||
|
- `ACCOUNT_SCREEN` показывает 3 кнопки:
|
||||||
|
- `Login (<value|not set>)`
|
||||||
|
- `Subserver (<value|not set>)`
|
||||||
|
- `Secret (<*****|not set>)`
|
||||||
|
- `Login` открывает общий экран редактирования и сохраняется в NVS;
|
||||||
|
- `Subserver` открывает промежуточный экран с `USE SUBSERVER1` и `EDIT MANUALLY`;
|
||||||
|
- `USE SUBSERVER1` возвращает стандартное значение `subserver1`;
|
||||||
|
- `EDIT MANUALLY` открывает общий экран редактирования и сохраняет значение в NVS;
|
||||||
|
- `Secret` открывает экран-заглушку, где сказано, что настройка ещё не реализована;
|
||||||
- свайп вправо из внутренних экранов возвращает в `SETTINGS_MENU`;
|
- свайп вправо из внутренних экранов возвращает в `SETTINGS_MENU`;
|
||||||
|
- свайп вправо из `ACCOUNT_SUBSERVER_SCREEN` и `ACCOUNT_SECRET_SCREEN` возвращает в `ACCOUNT_SCREEN`;
|
||||||
- если во время реального свайпа палец проходит по кнопке, это не должно открывать кнопку как обычный `click`.
|
- если во время реального свайпа палец проходит по кнопке, это не должно открывать кнопку как обычный `click`.
|
||||||
- Ожидаемый результат: новый скетч даёт чистый навигационный каркас и уже умеет настраивать Wi-Fi и серверные адреса на самой ESP32.
|
- Ожидаемый результат: новый скетч даёт чистый навигационный каркас и уже умеет настраивать Wi-Fi и серверные адреса на самой ESP32.
|
||||||
- Статус: pending
|
- Статус: pending
|
||||||
|
|||||||
@ -19,19 +19,22 @@
|
|||||||
|
|
||||||
## Экраны
|
## Экраны
|
||||||
|
|
||||||
Прототип содержит 6 экранов:
|
Прототип содержит 8 экранов:
|
||||||
- `HOME`
|
- `HOME`
|
||||||
- `SETTINGS_MENU`
|
- `SETTINGS_MENU`
|
||||||
- `WIFI_SCREEN`
|
- `WIFI_SCREEN`
|
||||||
- `SERVER_SCREEN`
|
- `SERVER_SCREEN`
|
||||||
- `ACCOUNT_SCREEN`
|
- `ACCOUNT_SCREEN`
|
||||||
|
- `ACCOUNT_SUBSERVER_SCREEN`
|
||||||
|
- `ACCOUNT_SECRET_SCREEN`
|
||||||
- `TEXT_EDIT_SCREEN`
|
- `TEXT_EDIT_SCREEN`
|
||||||
|
|
||||||
## HOME
|
## HOME
|
||||||
|
|
||||||
Показывает:
|
Показывает:
|
||||||
- сверху слева `login`;
|
- сверху слева значение логина или `login not set`;
|
||||||
- ниже `subserver1`;
|
- ниже значение сабсервера или `subserver not set`;
|
||||||
|
- третьей строкой `secret not set`, если секрет ещё не помечен как установленный;
|
||||||
- сверху справа простые индикаторы `W BAT`;
|
- сверху справа простые индикаторы `W BAT`;
|
||||||
- по центру крупный текст `STATUS`;
|
- по центру крупный текст `STATUS`;
|
||||||
- статус Wi-Fi;
|
- статус Wi-Fi;
|
||||||
@ -128,12 +131,44 @@
|
|||||||
## ACCOUNT_SCREEN
|
## ACCOUNT_SCREEN
|
||||||
|
|
||||||
Показывает:
|
Показывает:
|
||||||
- `Account`
|
- заголовок `ACCOUNT`;
|
||||||
- `Account screen`
|
- статусное сообщение;
|
||||||
|
- кнопку `Login (<value|not set>)`;
|
||||||
|
- кнопку `Subserver (<value|not set>)`;
|
||||||
|
- кнопку `Secret (<*****|not set>)`.
|
||||||
|
|
||||||
Переходы:
|
Переходы:
|
||||||
- свайп вправо -> `SETTINGS_MENU`
|
- свайп вправо -> `SETTINGS_MENU`
|
||||||
- кнопка `BACK` -> `SETTINGS_MENU`
|
- `Login` -> `TEXT_EDIT_SCREEN`
|
||||||
|
- `Subserver` -> `ACCOUNT_SUBSERVER_SCREEN`
|
||||||
|
- `Secret` -> `ACCOUNT_SECRET_SCREEN`
|
||||||
|
|
||||||
|
## ACCOUNT_SUBSERVER_SCREEN
|
||||||
|
|
||||||
|
Показывает:
|
||||||
|
- текущий `subserver`;
|
||||||
|
- рекомендацию оставить `subserver1`, если устройство одно;
|
||||||
|
- кнопку `USE SUBSERVER1`;
|
||||||
|
- кнопку `EDIT MANUALLY`;
|
||||||
|
- кнопку `BACK`.
|
||||||
|
|
||||||
|
Переходы:
|
||||||
|
- `USE SUBSERVER1` -> сохраняет `subserver1` и возвращает в `ACCOUNT_SCREEN`
|
||||||
|
- `EDIT MANUALLY` -> `TEXT_EDIT_SCREEN`
|
||||||
|
- свайп вправо -> `ACCOUNT_SCREEN`
|
||||||
|
|
||||||
|
## ACCOUNT_SECRET_SCREEN
|
||||||
|
|
||||||
|
Пока это заглушка.
|
||||||
|
|
||||||
|
Показывает:
|
||||||
|
- текущий статус секрета `set/not set`;
|
||||||
|
- сообщение, что настройка секрета пока не реализована;
|
||||||
|
- кнопку `BACK`.
|
||||||
|
|
||||||
|
Переходы:
|
||||||
|
- свайп вправо -> `ACCOUNT_SCREEN`
|
||||||
|
- `BACK` -> `ACCOUNT_SCREEN`
|
||||||
|
|
||||||
## TEXT_EDIT_SCREEN
|
## TEXT_EDIT_SCREEN
|
||||||
|
|
||||||
@ -147,7 +182,9 @@
|
|||||||
Показывает:
|
Показывает:
|
||||||
- заголовок;
|
- заголовок;
|
||||||
- поле ввода, уже заполненное старым значением;
|
- поле ввода, уже заполненное старым значением;
|
||||||
- курсор установлен в конец текста;
|
- новые символы всегда добавляются только в конец текста;
|
||||||
|
- визуальный курсор не показывается;
|
||||||
|
- пароль Wi-Fi показывается открыто, без маскировки точками;
|
||||||
- кнопки `SAVE`, `CANCEL`, `DEL`, `CLR`;
|
- кнопки `SAVE`, `CANCEL`, `DEL`, `CLR`;
|
||||||
- большую экранную клавиатуру.
|
- большую экранную клавиатуру.
|
||||||
|
|
||||||
@ -161,6 +198,8 @@
|
|||||||
- переключение страниц выполняется свайпом влево/вправо внутри `TEXT_EDIT_SCREEN`;
|
- переключение страниц выполняется свайпом влево/вправо внутри `TEXT_EDIT_SCREEN`;
|
||||||
- страница 1 содержит в основном буквы и базовые URL-символы;
|
- страница 1 содержит в основном буквы и базовые URL-символы;
|
||||||
- страница 2 содержит цифры и дополнительные URL/символьные кнопки;
|
- страница 2 содержит цифры и дополнительные URL/символьные кнопки;
|
||||||
|
- переключение `ABC/123` и `SHIFT` не должно очищать уже введённый текст;
|
||||||
|
- переключение страниц клавиатуры свайпом тоже не должно очищать уже введённый текст, включая цифры, символы и уже набранные заглавные буквы;
|
||||||
- есть специальные действия `DEL` и `CLR`.
|
- есть специальные действия `DEL` и `CLR`.
|
||||||
|
|
||||||
## Хранение Wi-Fi
|
## Хранение Wi-Fi
|
||||||
@ -168,29 +207,45 @@
|
|||||||
Используется `Preferences` (NVS памяти ESP32):
|
Используется `Preferences` (NVS памяти ESP32):
|
||||||
- `wifi_ssid`
|
- `wifi_ssid`
|
||||||
- `wifi_pass`
|
- `wifi_pass`
|
||||||
|
- `wifi_known_good`
|
||||||
|
|
||||||
При старте устройства, если сохранён SSID, выполняется попытка подключения к сохранённой сети.
|
При старте устройства, если сохранён SSID, выполняется попытка подключения к сохранённой сети.
|
||||||
|
|
||||||
|
Если сеть раньше уже была успешно подключена и помечена как валидная:
|
||||||
|
- после потери связи устройство автоматически пытается переподключиться;
|
||||||
|
- первые повторные попытки идут раз в `10` секунд;
|
||||||
|
- если связи нет долго, интервал увеличивается до `30` секунд.
|
||||||
|
|
||||||
## Хранение серверов
|
## Хранение серверов
|
||||||
|
|
||||||
Используется `Preferences` (NVS памяти ESP32):
|
Используется `Preferences` (NVS памяти ESP32):
|
||||||
- `solana_rpc`
|
- `solana_rpc`
|
||||||
- `shine_server`
|
- `shine_server`
|
||||||
|
|
||||||
|
## Хранение аккаунта
|
||||||
|
|
||||||
|
Используется `Preferences` (NVS памяти ESP32):
|
||||||
|
- `login`
|
||||||
|
- `subserver`
|
||||||
|
- `secret_set`
|
||||||
|
|
||||||
## Детали клавиатуры
|
## Детали клавиатуры
|
||||||
|
|
||||||
- клавиатура занимает примерно `2/3`-`3/4` высоты экрана;
|
- клавиатура занимает примерно `2/3`-`3/4` высоты экрана;
|
||||||
- сверху остаются только заголовок, подсказка и поле ввода;
|
- сверху остаются только заголовок и поле ввода;
|
||||||
- буквы занимают 3 ряда;
|
- буквы занимают 3 ряда;
|
||||||
- половина букв находится на левой странице, половина на правой;
|
- половина букв находится на левой странице, половина на правой;
|
||||||
- на правой странице кнопки тоже стоят в ровных колонках, без сдвига рядов вправо;
|
- на правой странице кнопки тоже стоят в ровных колонках, без сдвига рядов вправо;
|
||||||
- отдельный режим `symbols` тоже разделён на 2 страницы;
|
- отдельный режим `symbols` тоже разделён на 2 страницы;
|
||||||
|
- 3 основных ряда клавиш и нижний служебный ряд увеличены по высоте;
|
||||||
|
- клавиши дополнительно увеличены по высоте по сравнению с предыдущим промежуточным вариантом;
|
||||||
- четвёртый ряд содержит:
|
- четвёртый ряд содержит:
|
||||||
- переключение `ABC/123`
|
- переключение `ABC/123`
|
||||||
- `SHIFT`
|
- `SHIFT`
|
||||||
- `DEL`
|
- `DEL`
|
||||||
- `SAVE`
|
- `SAVE`
|
||||||
- `CANCEL`
|
- `CANCEL`
|
||||||
|
- ниже рамки клавиатурного блока остаётся отдельная тёмная полоса с версией `NAV v7`.
|
||||||
|
|
||||||
## Жесты
|
## Жесты
|
||||||
|
|
||||||
@ -207,6 +262,8 @@
|
|||||||
- `WIFI_SCREEN`: свайп вправо -> `SETTINGS_MENU`
|
- `WIFI_SCREEN`: свайп вправо -> `SETTINGS_MENU`
|
||||||
- `SERVER_SCREEN`: свайп вправо -> `SETTINGS_MENU`
|
- `SERVER_SCREEN`: свайп вправо -> `SETTINGS_MENU`
|
||||||
- `ACCOUNT_SCREEN`: свайп вправо -> `SETTINGS_MENU`
|
- `ACCOUNT_SCREEN`: свайп вправо -> `SETTINGS_MENU`
|
||||||
|
- `ACCOUNT_SUBSERVER_SCREEN`: свайп вправо -> `ACCOUNT_SCREEN`
|
||||||
|
- `ACCOUNT_SECRET_SCREEN`: свайп вправо -> `ACCOUNT_SCREEN`
|
||||||
- `TEXT_EDIT_SCREEN`: свайп влево/вправо -> переключение страниц клавиатуры
|
- `TEXT_EDIT_SCREEN`: свайп влево/вправо -> переключение страниц клавиатуры
|
||||||
- переключение страниц клавиатуры срабатывает только если свайп начался в зоне самой клавиатуры, а не по всему экрану редактора
|
- переключение страниц клавиатуры срабатывает только если свайп начался в зоне самой клавиатуры, а не по всему экрану редактора
|
||||||
|
|
||||||
|
|||||||
@ -25,11 +25,14 @@
|
|||||||
#define TAP_CANCEL_THRESHOLD 18
|
#define TAP_CANCEL_THRESHOLD 18
|
||||||
#define MAX_SCAN_RESULTS 8
|
#define MAX_SCAN_RESULTS 8
|
||||||
#define WIFI_CONNECT_TIMEOUT_MS 12000
|
#define WIFI_CONNECT_TIMEOUT_MS 12000
|
||||||
|
#define WIFI_RECONNECT_FAST_MS 10000
|
||||||
|
#define WIFI_RECONNECT_SLOW_MS 30000
|
||||||
|
#define WIFI_RECONNECT_SLOW_AFTER_MS 90000
|
||||||
#define TEXT_EDIT_PANEL_X 10
|
#define TEXT_EDIT_PANEL_X 10
|
||||||
#define TEXT_EDIT_PANEL_Y 126
|
#define TEXT_EDIT_PANEL_Y 112
|
||||||
#define TEXT_EDIT_PANEL_W 460
|
#define TEXT_EDIT_PANEL_W 460
|
||||||
#define TEXT_EDIT_PANEL_H 344
|
#define TEXT_EDIT_PANEL_H 330
|
||||||
#define TEST_VERSION "NAV v6"
|
#define TEST_VERSION "NAV v8"
|
||||||
|
|
||||||
enum Screen {
|
enum Screen {
|
||||||
SCREEN_HOME,
|
SCREEN_HOME,
|
||||||
@ -37,6 +40,8 @@ enum Screen {
|
|||||||
SCREEN_WIFI,
|
SCREEN_WIFI,
|
||||||
SCREEN_SERVER,
|
SCREEN_SERVER,
|
||||||
SCREEN_ACCOUNT,
|
SCREEN_ACCOUNT,
|
||||||
|
SCREEN_ACCOUNT_SUBSERVER,
|
||||||
|
SCREEN_ACCOUNT_SECRET,
|
||||||
SCREEN_TEXT_EDIT,
|
SCREEN_TEXT_EDIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,6 +65,12 @@ enum ActionId {
|
|||||||
ACTION_WIFI_CLEAR,
|
ACTION_WIFI_CLEAR,
|
||||||
ACTION_SERVER_EDIT_SOLANA,
|
ACTION_SERVER_EDIT_SOLANA,
|
||||||
ACTION_SERVER_EDIT_SHINE,
|
ACTION_SERVER_EDIT_SHINE,
|
||||||
|
ACTION_ACCOUNT_EDIT_LOGIN,
|
||||||
|
ACTION_ACCOUNT_EDIT_SUBSERVER,
|
||||||
|
ACTION_ACCOUNT_EDIT_SECRET,
|
||||||
|
ACTION_ACCOUNT_SUBSERVER_USE_DEFAULT,
|
||||||
|
ACTION_ACCOUNT_SUBSERVER_EDIT_MANUAL,
|
||||||
|
ACTION_BACK_ACCOUNT,
|
||||||
ACTION_EDITOR_SAVE,
|
ACTION_EDITOR_SAVE,
|
||||||
ACTION_EDITOR_CANCEL,
|
ACTION_EDITOR_CANCEL,
|
||||||
};
|
};
|
||||||
@ -74,6 +85,8 @@ enum EditContext {
|
|||||||
EDIT_CONTEXT_WIFI_PASSWORD,
|
EDIT_CONTEXT_WIFI_PASSWORD,
|
||||||
EDIT_CONTEXT_SOLANA_RPC,
|
EDIT_CONTEXT_SOLANA_RPC,
|
||||||
EDIT_CONTEXT_SHINE_SERVER,
|
EDIT_CONTEXT_SHINE_SERVER,
|
||||||
|
EDIT_CONTEXT_LOGIN,
|
||||||
|
EDIT_CONTEXT_SUBSERVER,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KeyboardMode {
|
enum KeyboardMode {
|
||||||
@ -118,6 +131,16 @@ static WifiViewMode gWifiViewMode = WIFI_VIEW_OVERVIEW;
|
|||||||
static String gSolanaRpcUrl = "https://api.devnet.solana.com";
|
static String gSolanaRpcUrl = "https://api.devnet.solana.com";
|
||||||
static String gShineServerUrl = "https://shineup.me";
|
static String gShineServerUrl = "https://shineup.me";
|
||||||
static String gServerStatusMessage = "Edit RPC or shine host";
|
static String gServerStatusMessage = "Edit RPC or shine host";
|
||||||
|
static String gLoginValue;
|
||||||
|
static String gSubserverValue = "subserver1";
|
||||||
|
static bool gSecretConfigured = false;
|
||||||
|
static String gAccountStatusMessage = "Edit account fields";
|
||||||
|
static bool gWifiKnownGood = false;
|
||||||
|
static bool gWifiReconnectEnabled = false;
|
||||||
|
static bool gWifiOperationBusy = false;
|
||||||
|
static unsigned long gWifiDisconnectedSinceMs = 0;
|
||||||
|
static unsigned long gWifiLastReconnectAttemptMs = 0;
|
||||||
|
static wl_status_t gLastWifiStatus = WL_IDLE_STATUS;
|
||||||
|
|
||||||
static EditContext gEditContext = EDIT_CONTEXT_NONE;
|
static EditContext gEditContext = EDIT_CONTEXT_NONE;
|
||||||
static Screen gEditReturnScreen = SCREEN_HOME;
|
static Screen gEditReturnScreen = SCREEN_HOME;
|
||||||
@ -136,11 +159,14 @@ static void loadPrefs();
|
|||||||
static void saveWifiPrefs();
|
static void saveWifiPrefs();
|
||||||
static void clearWifiPrefs();
|
static void clearWifiPrefs();
|
||||||
static void saveServerPrefs();
|
static void saveServerPrefs();
|
||||||
|
static void saveAccountPrefs();
|
||||||
static void beginSavedWifi();
|
static void beginSavedWifi();
|
||||||
static void scanWifiNetworks();
|
static void scanWifiNetworks();
|
||||||
static bool connectWifiNow(const String &ssid, const String &password);
|
static bool connectWifiNow(const String &ssid, const String &password);
|
||||||
static String wifiHomeStatus();
|
static String wifiHomeStatus();
|
||||||
static String wifiSavedLabel();
|
static String wifiSavedLabel();
|
||||||
|
static void updateWifiReconnectState();
|
||||||
|
static void manageWifiReconnect();
|
||||||
static void openEditor(EditContext context,
|
static void openEditor(EditContext context,
|
||||||
Screen returnScreen,
|
Screen returnScreen,
|
||||||
const String &title,
|
const String &title,
|
||||||
@ -149,6 +175,13 @@ static void openEditor(EditContext context,
|
|||||||
bool isPassword);
|
bool isPassword);
|
||||||
static void applyEditorValue();
|
static void applyEditorValue();
|
||||||
static bool isTextEditKeyboardSwipeArea(int16_t x, int16_t y);
|
static bool isTextEditKeyboardSwipeArea(int16_t x, int16_t y);
|
||||||
|
static void syncEditValueFromTextarea();
|
||||||
|
static void keepCursorAtEnd();
|
||||||
|
static void restoreTextareaFromEditValue();
|
||||||
|
static String loginDisplayValue();
|
||||||
|
static String subserverDisplayValue();
|
||||||
|
static String homeSecretStatus();
|
||||||
|
static String secretButtonValue();
|
||||||
|
|
||||||
static void lvglFlushCb(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *colorP) {
|
static void lvglFlushCb(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *colorP) {
|
||||||
uint32_t w = area->x2 - area->x1 + 1;
|
uint32_t w = area->x2 - area->x1 + 1;
|
||||||
@ -263,13 +296,18 @@ static void showMessageAt(const String &text, lv_coord_t y) {
|
|||||||
static void loadPrefs() {
|
static void loadPrefs() {
|
||||||
gWifiSavedSsid = gPrefs.getString("wifi_ssid", "");
|
gWifiSavedSsid = gPrefs.getString("wifi_ssid", "");
|
||||||
gWifiSavedPassword = gPrefs.getString("wifi_pass", "");
|
gWifiSavedPassword = gPrefs.getString("wifi_pass", "");
|
||||||
|
gWifiKnownGood = gPrefs.getBool("wifi_known_good", false);
|
||||||
gSolanaRpcUrl = gPrefs.getString("solana_rpc", "https://api.devnet.solana.com");
|
gSolanaRpcUrl = gPrefs.getString("solana_rpc", "https://api.devnet.solana.com");
|
||||||
gShineServerUrl = gPrefs.getString("shine_server", "https://shineup.me");
|
gShineServerUrl = gPrefs.getString("shine_server", "https://shineup.me");
|
||||||
|
gLoginValue = gPrefs.getString("login", "");
|
||||||
|
gSubserverValue = gPrefs.getString("subserver", "subserver1");
|
||||||
|
gSecretConfigured = gPrefs.getBool("secret_set", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveWifiPrefs() {
|
static void saveWifiPrefs() {
|
||||||
gPrefs.putString("wifi_ssid", gWifiSavedSsid);
|
gPrefs.putString("wifi_ssid", gWifiSavedSsid);
|
||||||
gPrefs.putString("wifi_pass", gWifiSavedPassword);
|
gPrefs.putString("wifi_pass", gWifiSavedPassword);
|
||||||
|
gPrefs.putBool("wifi_known_good", gWifiKnownGood);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveServerPrefs() {
|
static void saveServerPrefs() {
|
||||||
@ -277,22 +315,36 @@ static void saveServerPrefs() {
|
|||||||
gPrefs.putString("shine_server", gShineServerUrl);
|
gPrefs.putString("shine_server", gShineServerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void saveAccountPrefs() {
|
||||||
|
gPrefs.putString("login", gLoginValue);
|
||||||
|
gPrefs.putString("subserver", gSubserverValue);
|
||||||
|
gPrefs.putBool("secret_set", gSecretConfigured);
|
||||||
|
}
|
||||||
|
|
||||||
static void clearWifiPrefs() {
|
static void clearWifiPrefs() {
|
||||||
gWifiSavedSsid = "";
|
gWifiSavedSsid = "";
|
||||||
gWifiSavedPassword = "";
|
gWifiSavedPassword = "";
|
||||||
gWifiSelectedSsid = "";
|
gWifiSelectedSsid = "";
|
||||||
|
gWifiKnownGood = false;
|
||||||
|
gWifiReconnectEnabled = false;
|
||||||
|
gWifiDisconnectedSinceMs = 0;
|
||||||
|
gWifiLastReconnectAttemptMs = 0;
|
||||||
saveWifiPrefs();
|
saveWifiPrefs();
|
||||||
WiFi.disconnect(true, false);
|
WiFi.disconnect(true, false);
|
||||||
gWifiStatusMessage = "Saved Wi-Fi cleared";
|
gWifiStatusMessage = "Saved Wi-Fi cleared";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void beginSavedWifi() {
|
static void beginSavedWifi() {
|
||||||
if (gWifiSavedSsid.isEmpty()) {
|
if (gWifiSavedSsid.isEmpty() || !gWifiKnownGood) {
|
||||||
|
gWifiReconnectEnabled = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(gWifiSavedSsid.c_str(), gWifiSavedPassword.c_str());
|
WiFi.begin(gWifiSavedSsid.c_str(), gWifiSavedPassword.c_str());
|
||||||
|
gWifiReconnectEnabled = true;
|
||||||
|
gWifiDisconnectedSinceMs = millis();
|
||||||
|
gWifiLastReconnectAttemptMs = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String wifiHomeStatus() {
|
static String wifiHomeStatus() {
|
||||||
@ -312,9 +364,78 @@ static String wifiSavedLabel() {
|
|||||||
return String("Saved: ") + gWifiSavedSsid;
|
return String("Saved: ") + gWifiSavedSsid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String loginDisplayValue() {
|
||||||
|
return gLoginValue.isEmpty() ? "login not set" : gLoginValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String subserverDisplayValue() {
|
||||||
|
return gSubserverValue.isEmpty() ? "subserver not set" : gSubserverValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String homeSecretStatus() {
|
||||||
|
return gSecretConfigured ? "" : "secret not set";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String secretButtonValue() {
|
||||||
|
return gSecretConfigured ? "*****" : "not set";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateWifiReconnectState() {
|
||||||
|
wl_status_t status = WiFi.status();
|
||||||
|
if (status == WL_CONNECTED) {
|
||||||
|
if (gLastWifiStatus != WL_CONNECTED) {
|
||||||
|
gWifiStatusMessage = String("Connected: ") + WiFi.localIP().toString();
|
||||||
|
}
|
||||||
|
gWifiDisconnectedSinceMs = 0;
|
||||||
|
gLastWifiStatus = status;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gLastWifiStatus == WL_CONNECTED && gWifiReconnectEnabled) {
|
||||||
|
gWifiDisconnectedSinceMs = millis();
|
||||||
|
gWifiLastReconnectAttemptMs = 0;
|
||||||
|
gWifiStatusMessage = "Wi-Fi lost. Reconnecting...";
|
||||||
|
}
|
||||||
|
gLastWifiStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manageWifiReconnect() {
|
||||||
|
updateWifiReconnectState();
|
||||||
|
|
||||||
|
if (!gWifiReconnectEnabled || gWifiSavedSsid.isEmpty() || gWifiOperationBusy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gWifiDisconnectedSinceMs == 0) {
|
||||||
|
gWifiDisconnectedSinceMs = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long disconnectedFor = millis() - gWifiDisconnectedSinceMs;
|
||||||
|
unsigned long interval = disconnectedFor >= WIFI_RECONNECT_SLOW_AFTER_MS
|
||||||
|
? WIFI_RECONNECT_SLOW_MS
|
||||||
|
: WIFI_RECONNECT_FAST_MS;
|
||||||
|
if (gWifiLastReconnectAttemptMs != 0 &&
|
||||||
|
millis() - gWifiLastReconnectAttemptMs < interval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gWifiLastReconnectAttemptMs = millis();
|
||||||
|
gWifiStatusMessage = disconnectedFor >= WIFI_RECONNECT_SLOW_AFTER_MS
|
||||||
|
? "Wi-Fi retry every 30s"
|
||||||
|
: "Wi-Fi retry every 10s";
|
||||||
|
WiFi.disconnect(false, false);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(gWifiSavedSsid.c_str(), gWifiSavedPassword.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
static void scanWifiNetworks() {
|
static void scanWifiNetworks() {
|
||||||
gScanResultCount = 0;
|
gScanResultCount = 0;
|
||||||
gWifiStatusMessage = "Scanning networks...";
|
gWifiStatusMessage = "Scanning networks...";
|
||||||
|
gWifiOperationBusy = true;
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.disconnect(false, false);
|
WiFi.disconnect(false, false);
|
||||||
delay(100);
|
delay(100);
|
||||||
@ -323,6 +444,7 @@ static void scanWifiNetworks() {
|
|||||||
if (found <= 0) {
|
if (found <= 0) {
|
||||||
gWifiStatusMessage = "No networks found";
|
gWifiStatusMessage = "No networks found";
|
||||||
gWifiViewMode = WIFI_VIEW_OVERVIEW;
|
gWifiViewMode = WIFI_VIEW_OVERVIEW;
|
||||||
|
gWifiOperationBusy = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +455,7 @@ static void scanWifiNetworks() {
|
|||||||
WiFi.scanDelete();
|
WiFi.scanDelete();
|
||||||
gWifiStatusMessage = String("Found ") + found + " networks";
|
gWifiStatusMessage = String("Found ") + found + " networks";
|
||||||
gWifiViewMode = WIFI_VIEW_SCAN_RESULTS;
|
gWifiViewMode = WIFI_VIEW_SCAN_RESULTS;
|
||||||
|
gWifiOperationBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool connectWifiNow(const String &ssid, const String &password) {
|
static bool connectWifiNow(const String &ssid, const String &password) {
|
||||||
@ -340,6 +463,7 @@ static bool connectWifiNow(const String &ssid, const String &password) {
|
|||||||
rebuildScreen();
|
rebuildScreen();
|
||||||
lv_timer_handler();
|
lv_timer_handler();
|
||||||
|
|
||||||
|
gWifiOperationBusy = true;
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.disconnect(false, false);
|
WiFi.disconnect(false, false);
|
||||||
delay(150);
|
delay(150);
|
||||||
@ -350,8 +474,14 @@ static bool connectWifiNow(const String &ssid, const String &password) {
|
|||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
gWifiSavedSsid = ssid;
|
gWifiSavedSsid = ssid;
|
||||||
gWifiSavedPassword = password;
|
gWifiSavedPassword = password;
|
||||||
|
gWifiKnownGood = true;
|
||||||
|
gWifiReconnectEnabled = true;
|
||||||
|
gWifiDisconnectedSinceMs = 0;
|
||||||
|
gWifiLastReconnectAttemptMs = 0;
|
||||||
|
gLastWifiStatus = WL_CONNECTED;
|
||||||
saveWifiPrefs();
|
saveWifiPrefs();
|
||||||
gWifiStatusMessage = String("Connected: ") + WiFi.localIP().toString();
|
gWifiStatusMessage = String("Connected: ") + WiFi.localIP().toString();
|
||||||
|
gWifiOperationBusy = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
delay(200);
|
delay(200);
|
||||||
@ -359,6 +489,7 @@ static bool connectWifiNow(const String &ssid, const String &password) {
|
|||||||
|
|
||||||
WiFi.disconnect(false, false);
|
WiFi.disconnect(false, false);
|
||||||
gWifiStatusMessage = "Connection failed";
|
gWifiStatusMessage = "Connection failed";
|
||||||
|
gWifiOperationBusy = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +540,24 @@ static void applyEditorValue() {
|
|||||||
showScreen(SCREEN_SERVER);
|
showScreen(SCREEN_SERVER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gEditContext == EDIT_CONTEXT_LOGIN) {
|
||||||
|
value.trim();
|
||||||
|
gLoginValue = value;
|
||||||
|
saveAccountPrefs();
|
||||||
|
gAccountStatusMessage = gLoginValue.isEmpty() ? "Login cleared" : "Login saved";
|
||||||
|
showScreen(SCREEN_ACCOUNT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gEditContext == EDIT_CONTEXT_SUBSERVER) {
|
||||||
|
value.trim();
|
||||||
|
gSubserverValue = value;
|
||||||
|
saveAccountPrefs();
|
||||||
|
gAccountStatusMessage = gSubserverValue.isEmpty() ? "Subserver cleared" : "Subserver saved";
|
||||||
|
showScreen(SCREEN_ACCOUNT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cancelEditor() {
|
static void cancelEditor() {
|
||||||
@ -419,6 +568,25 @@ static void cancelEditor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void syncEditValueFromTextarea() {
|
||||||
|
if (gInputTextArea) {
|
||||||
|
gEditValue = String(lv_textarea_get_text(gInputTextArea));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keepCursorAtEnd() {
|
||||||
|
if (gInputTextArea) {
|
||||||
|
lv_textarea_set_cursor_pos(gInputTextArea, LV_TEXTAREA_CURSOR_LAST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restoreTextareaFromEditValue() {
|
||||||
|
if (gInputTextArea) {
|
||||||
|
lv_textarea_set_text(gInputTextArea, gEditValue.c_str());
|
||||||
|
keepCursorAtEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void networkSelectCb(lv_event_t *event) {
|
static void networkSelectCb(lv_event_t *event) {
|
||||||
if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick) {
|
if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick) {
|
||||||
return;
|
return;
|
||||||
@ -450,10 +618,14 @@ static void editorKeyCb(lv_event_t *event) {
|
|||||||
|
|
||||||
if (strcmp(token, "<DEL>") == 0) {
|
if (strcmp(token, "<DEL>") == 0) {
|
||||||
lv_textarea_del_char(gInputTextArea);
|
lv_textarea_del_char(gInputTextArea);
|
||||||
|
syncEditValueFromTextarea();
|
||||||
|
keepCursorAtEnd();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strcmp(token, "<CLR>") == 0) {
|
if (strcmp(token, "<CLR>") == 0) {
|
||||||
lv_textarea_set_text(gInputTextArea, "");
|
lv_textarea_set_text(gInputTextArea, "");
|
||||||
|
syncEditValueFromTextarea();
|
||||||
|
keepCursorAtEnd();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strcmp(token, "<SAVE>") == 0) {
|
if (strcmp(token, "<SAVE>") == 0) {
|
||||||
@ -465,12 +637,14 @@ static void editorKeyCb(lv_event_t *event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strcmp(token, "<MODE>") == 0) {
|
if (strcmp(token, "<MODE>") == 0) {
|
||||||
|
syncEditValueFromTextarea();
|
||||||
gKeyboardMode = (gKeyboardMode == KEYBOARD_MODE_ALPHA) ? KEYBOARD_MODE_SYMBOLS : KEYBOARD_MODE_ALPHA;
|
gKeyboardMode = (gKeyboardMode == KEYBOARD_MODE_ALPHA) ? KEYBOARD_MODE_SYMBOLS : KEYBOARD_MODE_ALPHA;
|
||||||
gKeyboardPage = 0;
|
gKeyboardPage = 0;
|
||||||
rebuildScreen();
|
rebuildScreen();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strcmp(token, "<SHIFT>") == 0) {
|
if (strcmp(token, "<SHIFT>") == 0) {
|
||||||
|
syncEditValueFromTextarea();
|
||||||
gKeyboardShift = !gKeyboardShift;
|
gKeyboardShift = !gKeyboardShift;
|
||||||
rebuildScreen();
|
rebuildScreen();
|
||||||
return;
|
return;
|
||||||
@ -481,7 +655,10 @@ static void editorKeyCb(lv_event_t *event) {
|
|||||||
out.toUpperCase();
|
out.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keepCursorAtEnd();
|
||||||
lv_textarea_add_text(gInputTextArea, out.c_str());
|
lv_textarea_add_text(gInputTextArea, out.c_str());
|
||||||
|
syncEditValueFromTextarea();
|
||||||
|
keepCursorAtEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void actionButtonCb(lv_event_t *event) {
|
static void actionButtonCb(lv_event_t *event) {
|
||||||
@ -504,6 +681,9 @@ static void actionButtonCb(lv_event_t *event) {
|
|||||||
case ACTION_OPEN_ACCOUNT:
|
case ACTION_OPEN_ACCOUNT:
|
||||||
showScreen(SCREEN_ACCOUNT);
|
showScreen(SCREEN_ACCOUNT);
|
||||||
break;
|
break;
|
||||||
|
case ACTION_BACK_ACCOUNT:
|
||||||
|
showScreen(SCREEN_ACCOUNT);
|
||||||
|
break;
|
||||||
case ACTION_BACK_HOME:
|
case ACTION_BACK_HOME:
|
||||||
showScreen(SCREEN_HOME);
|
showScreen(SCREEN_HOME);
|
||||||
break;
|
break;
|
||||||
@ -524,7 +704,7 @@ static void actionButtonCb(lv_event_t *event) {
|
|||||||
openEditor(EDIT_CONTEXT_SOLANA_RPC,
|
openEditor(EDIT_CONTEXT_SOLANA_RPC,
|
||||||
SCREEN_SERVER,
|
SCREEN_SERVER,
|
||||||
"EDIT SOLANA RPC",
|
"EDIT SOLANA RPC",
|
||||||
"Cursor starts at the end.",
|
"",
|
||||||
gSolanaRpcUrl,
|
gSolanaRpcUrl,
|
||||||
false);
|
false);
|
||||||
break;
|
break;
|
||||||
@ -532,10 +712,38 @@ static void actionButtonCb(lv_event_t *event) {
|
|||||||
openEditor(EDIT_CONTEXT_SHINE_SERVER,
|
openEditor(EDIT_CONTEXT_SHINE_SERVER,
|
||||||
SCREEN_SERVER,
|
SCREEN_SERVER,
|
||||||
"EDIT SHINE HOST",
|
"EDIT SHINE HOST",
|
||||||
"Cursor starts at the end.",
|
"",
|
||||||
gShineServerUrl,
|
gShineServerUrl,
|
||||||
false);
|
false);
|
||||||
break;
|
break;
|
||||||
|
case ACTION_ACCOUNT_EDIT_LOGIN:
|
||||||
|
openEditor(EDIT_CONTEXT_LOGIN,
|
||||||
|
SCREEN_ACCOUNT,
|
||||||
|
"EDIT LOGIN",
|
||||||
|
"",
|
||||||
|
gLoginValue,
|
||||||
|
false);
|
||||||
|
break;
|
||||||
|
case ACTION_ACCOUNT_EDIT_SUBSERVER:
|
||||||
|
showScreen(SCREEN_ACCOUNT_SUBSERVER);
|
||||||
|
break;
|
||||||
|
case ACTION_ACCOUNT_EDIT_SECRET:
|
||||||
|
showScreen(SCREEN_ACCOUNT_SECRET);
|
||||||
|
break;
|
||||||
|
case ACTION_ACCOUNT_SUBSERVER_USE_DEFAULT:
|
||||||
|
gSubserverValue = "subserver1";
|
||||||
|
saveAccountPrefs();
|
||||||
|
gAccountStatusMessage = "Subserver set to subserver1";
|
||||||
|
showScreen(SCREEN_ACCOUNT);
|
||||||
|
break;
|
||||||
|
case ACTION_ACCOUNT_SUBSERVER_EDIT_MANUAL:
|
||||||
|
openEditor(EDIT_CONTEXT_SUBSERVER,
|
||||||
|
SCREEN_ACCOUNT,
|
||||||
|
"EDIT SUBSERVER",
|
||||||
|
"",
|
||||||
|
gSubserverValue,
|
||||||
|
false);
|
||||||
|
break;
|
||||||
case ACTION_EDITOR_SAVE:
|
case ACTION_EDITOR_SAVE:
|
||||||
applyEditorValue();
|
applyEditorValue();
|
||||||
break;
|
break;
|
||||||
@ -569,6 +777,9 @@ static lv_obj_t *makeButton(const char *text,
|
|||||||
|
|
||||||
lv_obj_t *label = lv_label_create(btn);
|
lv_obj_t *label = lv_label_create(btn);
|
||||||
lv_label_set_text(label, text);
|
lv_label_set_text(label, text);
|
||||||
|
lv_obj_set_width(label, w - 24);
|
||||||
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
|
||||||
lv_obj_set_style_text_font(label, font, 0);
|
lv_obj_set_style_text_font(label, font, 0);
|
||||||
lv_obj_set_style_text_color(label, lv_color_hex(0xFFFFFF), 0);
|
lv_obj_set_style_text_color(label, lv_color_hex(0xFFFFFF), 0);
|
||||||
lv_obj_center(label);
|
lv_obj_center(label);
|
||||||
@ -622,17 +833,25 @@ static void drawHome() {
|
|||||||
setRootStyle();
|
setRootStyle();
|
||||||
|
|
||||||
lv_obj_t *login = lv_label_create(gRoot);
|
lv_obj_t *login = lv_label_create(gRoot);
|
||||||
lv_label_set_text(login, "login");
|
lv_label_set_text(login, loginDisplayValue().c_str());
|
||||||
lv_obj_set_style_text_font(login, &lv_font_montserrat_18, 0);
|
lv_obj_set_style_text_font(login, &lv_font_montserrat_18, 0);
|
||||||
lv_obj_set_style_text_color(login, lv_color_hex(0xFFFFFF), 0);
|
lv_obj_set_style_text_color(login, lv_color_hex(0xFFFFFF), 0);
|
||||||
lv_obj_align(login, LV_ALIGN_TOP_LEFT, 24, 18);
|
lv_obj_align(login, LV_ALIGN_TOP_LEFT, 24, 18);
|
||||||
|
|
||||||
lv_obj_t *subserver = lv_label_create(gRoot);
|
lv_obj_t *subserver = lv_label_create(gRoot);
|
||||||
lv_label_set_text(subserver, "subserver1");
|
lv_label_set_text(subserver, subserverDisplayValue().c_str());
|
||||||
lv_obj_set_style_text_font(subserver, &lv_font_montserrat_18, 0);
|
lv_obj_set_style_text_font(subserver, &lv_font_montserrat_18, 0);
|
||||||
lv_obj_set_style_text_color(subserver, lv_color_hex(0xD5DEE7), 0);
|
lv_obj_set_style_text_color(subserver, lv_color_hex(0xD5DEE7), 0);
|
||||||
lv_obj_align_to(subserver, login, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 6);
|
lv_obj_align_to(subserver, login, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 6);
|
||||||
|
|
||||||
|
if (!gSecretConfigured) {
|
||||||
|
lv_obj_t *secret = lv_label_create(gRoot);
|
||||||
|
lv_label_set_text(secret, homeSecretStatus().c_str());
|
||||||
|
lv_obj_set_style_text_font(secret, &lv_font_montserrat_16, 0);
|
||||||
|
lv_obj_set_style_text_color(secret, lv_color_hex(0xB8C6D3), 0);
|
||||||
|
lv_obj_align_to(secret, subserver, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
makeTopIcons();
|
makeTopIcons();
|
||||||
makeTitle("STATUS", 150, &lv_font_montserrat_28);
|
makeTitle("STATUS", 150, &lv_font_montserrat_28);
|
||||||
showMessageAt(wifiHomeStatus(), 204);
|
showMessageAt(wifiHomeStatus(), 204);
|
||||||
@ -747,10 +966,38 @@ static void drawServerScreen() {
|
|||||||
|
|
||||||
static void drawAccountScreen() {
|
static void drawAccountScreen() {
|
||||||
setRootStyle();
|
setRootStyle();
|
||||||
makeTitle("ACCOUNT", 56, &lv_font_montserrat_28);
|
|
||||||
makeBody("Account screen", 132, 400);
|
makeTitle("ACCOUNT", 18, &lv_font_montserrat_24);
|
||||||
makeBody("Swipe right to return to Settings.", 204, 400);
|
showMessageAt(gAccountStatusMessage, 56);
|
||||||
makeButton("BACK", 140, 344, 200, 72, 0x5A6570, ACTION_BACK_SETTINGS, &lv_font_montserrat_22);
|
|
||||||
|
String loginButton = String("Login (") + (gLoginValue.isEmpty() ? "not set" : gLoginValue) + ")";
|
||||||
|
String subserverButton = String("Subserver (") + (gSubserverValue.isEmpty() ? "not set" : gSubserverValue) + ")";
|
||||||
|
String secretButton = String("Secret (") + secretButtonValue() + ")";
|
||||||
|
|
||||||
|
makeButton(loginButton.c_str(), 22, 118, 436, 84, 0x355C7D, ACTION_ACCOUNT_EDIT_LOGIN, &lv_font_montserrat_20);
|
||||||
|
makeButton(subserverButton.c_str(), 22, 222, 436, 84, 0x355C7D, ACTION_ACCOUNT_EDIT_SUBSERVER, &lv_font_montserrat_20);
|
||||||
|
makeButton(secretButton.c_str(), 22, 326, 436, 84, 0x355C7D, ACTION_ACCOUNT_EDIT_SECRET, &lv_font_montserrat_20);
|
||||||
|
makeBody("Swipe right to return to Settings.", 420, 420);
|
||||||
|
makeVersionTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drawAccountSubserverScreen() {
|
||||||
|
setRootStyle();
|
||||||
|
makeTitle("SUBSERVER", 18, &lv_font_montserrat_24);
|
||||||
|
showMessageAt(String("Current: ") + subserverDisplayValue(), 56);
|
||||||
|
makeBody("If you only use one subserver, keep the default name subserver1.", 98, 420);
|
||||||
|
makeButton("USE SUBSERVER1", 22, 202, 436, 84, 0x2A9D8F, ACTION_ACCOUNT_SUBSERVER_USE_DEFAULT, &lv_font_montserrat_22);
|
||||||
|
makeButton("EDIT MANUALLY", 22, 306, 436, 84, 0x355C7D, ACTION_ACCOUNT_SUBSERVER_EDIT_MANUAL, &lv_font_montserrat_22);
|
||||||
|
makeButton("BACK", 140, 402, 200, 54, 0x5A6570, ACTION_BACK_ACCOUNT, &lv_font_montserrat_20);
|
||||||
|
makeVersionTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drawAccountSecretScreen() {
|
||||||
|
setRootStyle();
|
||||||
|
makeTitle("SECRET", 18, &lv_font_montserrat_24);
|
||||||
|
showMessageAt(String("Status: ") + (gSecretConfigured ? "set" : "not set"), 56);
|
||||||
|
makeBody("Secret setup is not implemented yet.", 116, 420);
|
||||||
|
makeButton("BACK", 140, 360, 200, 72, 0x5A6570, ACTION_BACK_ACCOUNT, &lv_font_montserrat_22);
|
||||||
makeVersionTag();
|
makeVersionTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,14 +1035,14 @@ static void drawTextEditorKeyboard(lv_coord_t originY) {
|
|||||||
static const char *symRightRow1[] = {"?", "&", "=", "+", "-"};
|
static const char *symRightRow1[] = {"?", "&", "=", "+", "-"};
|
||||||
static const char *symRightRow2[] = {"%", "#", "~", ":", "/"};
|
static const char *symRightRow2[] = {"%", "#", "~", ":", "/"};
|
||||||
|
|
||||||
const lv_coord_t keyH = 50;
|
const lv_coord_t keyH = 62;
|
||||||
const lv_coord_t keyW5 = 84;
|
const lv_coord_t keyW5 = 84;
|
||||||
const lv_coord_t keyW4 = 104;
|
const lv_coord_t keyW4 = 84;
|
||||||
const lv_coord_t gap = 8;
|
const lv_coord_t gap = 8;
|
||||||
const lv_coord_t row0Y = originY;
|
const lv_coord_t row0Y = originY;
|
||||||
const lv_coord_t row1Y = originY + 58;
|
const lv_coord_t row1Y = originY + 68;
|
||||||
const lv_coord_t row2Y = originY + 116;
|
const lv_coord_t row2Y = originY + 136;
|
||||||
const lv_coord_t row3Y = originY + 180;
|
const lv_coord_t row3Y = originY + 208;
|
||||||
const bool uppercase = gKeyboardMode == KEYBOARD_MODE_ALPHA && gKeyboardShift;
|
const bool uppercase = gKeyboardMode == KEYBOARD_MODE_ALPHA && gKeyboardShift;
|
||||||
|
|
||||||
if (gKeyboardMode == KEYBOARD_MODE_ALPHA) {
|
if (gKeyboardMode == KEYBOARD_MODE_ALPHA) {
|
||||||
@ -820,11 +1067,11 @@ static void drawTextEditorKeyboard(lv_coord_t originY) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeKeyboardButton(gKeyboardMode == KEYBOARD_MODE_ALPHA ? "123" : "ABC", "<MODE>", 20, row3Y, 88, 54, 0x5C6F82, &lv_font_montserrat_18);
|
makeKeyboardButton(gKeyboardMode == KEYBOARD_MODE_ALPHA ? "123" : "ABC", "<MODE>", 20, row3Y, 88, 64, 0x5C6F82, &lv_font_montserrat_18);
|
||||||
makeKeyboardButton(gKeyboardShift ? "SHIFT*" : "SHIFT", "<SHIFT>", 116, row3Y, 88, 54, 0x7A5C9B, &lv_font_montserrat_16);
|
makeKeyboardButton(gKeyboardShift ? "SHIFT*" : "SHIFT", "<SHIFT>", 116, row3Y, 88, 64, 0x7A5C9B, &lv_font_montserrat_16);
|
||||||
makeKeyboardButton("DEL", "<DEL>", 212, row3Y, 76, 54, 0x7D3A3A, &lv_font_montserrat_18);
|
makeKeyboardButton("DEL", "<DEL>", 212, row3Y, 76, 64, 0x7D3A3A, &lv_font_montserrat_18);
|
||||||
makeKeyboardButton("SAVE", "<SAVE>", 296, row3Y, 76, 54, 0x2A9D8F, &lv_font_montserrat_18);
|
makeKeyboardButton("SAVE", "<SAVE>", 296, row3Y, 76, 64, 0x2A9D8F, &lv_font_montserrat_18);
|
||||||
makeKeyboardButton("CANCEL", "<CANCEL>", 380, row3Y, 80, 54, 0x5A6570, &lv_font_montserrat_16);
|
makeKeyboardButton("CANCEL", "<CANCEL>", 380, row3Y, 80, 64, 0x5A6570, &lv_font_montserrat_16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawTextEditScreen() {
|
static void drawTextEditScreen() {
|
||||||
@ -839,13 +1086,21 @@ static void drawTextEditScreen() {
|
|||||||
lv_textarea_set_one_line(gInputTextArea, true);
|
lv_textarea_set_one_line(gInputTextArea, true);
|
||||||
lv_textarea_set_text(gInputTextArea, gEditValue.c_str());
|
lv_textarea_set_text(gInputTextArea, gEditValue.c_str());
|
||||||
lv_textarea_set_cursor_pos(gInputTextArea, LV_TEXTAREA_CURSOR_LAST);
|
lv_textarea_set_cursor_pos(gInputTextArea, LV_TEXTAREA_CURSOR_LAST);
|
||||||
lv_textarea_set_password_mode(gInputTextArea, gEditIsPassword);
|
lv_textarea_set_password_mode(gInputTextArea, false);
|
||||||
|
lv_textarea_set_cursor_click_pos(gInputTextArea, false);
|
||||||
|
lv_textarea_set_text_selection(gInputTextArea, false);
|
||||||
lv_obj_set_style_text_font(gInputTextArea, &lv_font_montserrat_18, 0);
|
lv_obj_set_style_text_font(gInputTextArea, &lv_font_montserrat_18, 0);
|
||||||
lv_obj_set_style_bg_color(gInputTextArea, lv_color_hex(0x132131), 0);
|
lv_obj_set_style_bg_color(gInputTextArea, lv_color_hex(0x132131), 0);
|
||||||
lv_obj_set_style_text_color(gInputTextArea, lv_color_hex(0xFFFFFF), 0);
|
lv_obj_set_style_text_color(gInputTextArea, lv_color_hex(0xFFFFFF), 0);
|
||||||
lv_obj_set_style_border_color(gInputTextArea, lv_color_hex(0x6E8AA3), 0);
|
lv_obj_set_style_border_color(gInputTextArea, lv_color_hex(0x6E8AA3), 0);
|
||||||
lv_obj_set_style_border_width(gInputTextArea, 2, 0);
|
lv_obj_set_style_border_width(gInputTextArea, 2, 0);
|
||||||
|
lv_obj_set_style_bg_opa(gInputTextArea, LV_OPA_TRANSP, LV_PART_CURSOR);
|
||||||
|
lv_obj_set_style_border_opa(gInputTextArea, LV_OPA_TRANSP, LV_PART_CURSOR);
|
||||||
|
lv_obj_set_style_outline_opa(gInputTextArea, LV_OPA_TRANSP, LV_PART_CURSOR);
|
||||||
|
lv_obj_set_style_pad_left(gInputTextArea, 12, 0);
|
||||||
|
lv_obj_set_style_pad_right(gInputTextArea, 12, 0);
|
||||||
lv_obj_add_state(gInputTextArea, LV_STATE_FOCUSED);
|
lv_obj_add_state(gInputTextArea, LV_STATE_FOCUSED);
|
||||||
|
restoreTextareaFromEditValue();
|
||||||
|
|
||||||
lv_obj_t *panel = lv_obj_create(gRoot);
|
lv_obj_t *panel = lv_obj_create(gRoot);
|
||||||
lv_obj_set_size(panel, TEXT_EDIT_PANEL_W, TEXT_EDIT_PANEL_H);
|
lv_obj_set_size(panel, TEXT_EDIT_PANEL_W, TEXT_EDIT_PANEL_H);
|
||||||
@ -857,7 +1112,7 @@ static void drawTextEditScreen() {
|
|||||||
lv_obj_set_style_border_color(panel, lv_color_hex(0x2E455A), 0);
|
lv_obj_set_style_border_color(panel, lv_color_hex(0x2E455A), 0);
|
||||||
lv_obj_clear_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_clear_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
|
||||||
drawTextEditorKeyboard(TEXT_EDIT_PANEL_Y + 10);
|
drawTextEditorKeyboard(TEXT_EDIT_PANEL_Y + 8);
|
||||||
|
|
||||||
makeVersionTag();
|
makeVersionTag();
|
||||||
}
|
}
|
||||||
@ -885,6 +1140,12 @@ static void rebuildScreen() {
|
|||||||
case SCREEN_ACCOUNT:
|
case SCREEN_ACCOUNT:
|
||||||
drawAccountScreen();
|
drawAccountScreen();
|
||||||
break;
|
break;
|
||||||
|
case SCREEN_ACCOUNT_SUBSERVER:
|
||||||
|
drawAccountSubserverScreen();
|
||||||
|
break;
|
||||||
|
case SCREEN_ACCOUNT_SECRET:
|
||||||
|
drawAccountSecretScreen();
|
||||||
|
break;
|
||||||
case SCREEN_TEXT_EDIT:
|
case SCREEN_TEXT_EDIT:
|
||||||
drawTextEditScreen();
|
drawTextEditScreen();
|
||||||
break;
|
break;
|
||||||
@ -945,10 +1206,17 @@ static void handleAccountSwipe(SwipeDirection swipe) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handleAccountSubscreenSwipe(SwipeDirection swipe) {
|
||||||
|
if (swipe == SWIPE_RIGHT) {
|
||||||
|
showScreen(SCREEN_ACCOUNT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void handleTextEditSwipe(SwipeDirection swipe) {
|
static void handleTextEditSwipe(SwipeDirection swipe) {
|
||||||
if (!isTextEditKeyboardSwipeArea(gTouchStartX, gTouchStartY)) {
|
if (!isTextEditKeyboardSwipeArea(gTouchStartX, gTouchStartY)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
syncEditValueFromTextarea();
|
||||||
if (swipe == SWIPE_LEFT) {
|
if (swipe == SWIPE_LEFT) {
|
||||||
gKeyboardPage = min(gKeyboardPage + 1, 1);
|
gKeyboardPage = min(gKeyboardPage + 1, 1);
|
||||||
rebuildScreen();
|
rebuildScreen();
|
||||||
@ -986,6 +1254,10 @@ static void handleSwipe(SwipeDirection swipe) {
|
|||||||
case SCREEN_ACCOUNT:
|
case SCREEN_ACCOUNT:
|
||||||
handleAccountSwipe(swipe);
|
handleAccountSwipe(swipe);
|
||||||
break;
|
break;
|
||||||
|
case SCREEN_ACCOUNT_SUBSERVER:
|
||||||
|
case SCREEN_ACCOUNT_SECRET:
|
||||||
|
handleAccountSubscreenSwipe(swipe);
|
||||||
|
break;
|
||||||
case SCREEN_TEXT_EDIT:
|
case SCREEN_TEXT_EDIT:
|
||||||
handleTextEditSwipe(swipe);
|
handleTextEditSwipe(swipe);
|
||||||
break;
|
break;
|
||||||
@ -1010,6 +1282,7 @@ void setup() {
|
|||||||
gPrefs.begin("shine-nav-ui", false);
|
gPrefs.begin("shine-nav-ui", false);
|
||||||
loadPrefs();
|
loadPrefs();
|
||||||
beginSavedWifi();
|
beginSavedWifi();
|
||||||
|
gLastWifiStatus = WiFi.status();
|
||||||
|
|
||||||
lv_init();
|
lv_init();
|
||||||
|
|
||||||
@ -1047,6 +1320,7 @@ void setup() {
|
|||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
lv_timer_handler();
|
lv_timer_handler();
|
||||||
|
manageWifiReconnect();
|
||||||
|
|
||||||
if (gPendingSwipe != SWIPE_NONE) {
|
if (gPendingSwipe != SWIPE_NONE) {
|
||||||
SwipeDirection swipe = gPendingSwipe;
|
SwipeDirection swipe = gPendingSwipe;
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.143
|
client.version=1.2.144
|
||||||
server.version=1.2.135
|
server.version=1.2.136
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user