ESP32: экран подтверждения регистрации
This commit is contained in:
parent
b83543d018
commit
0c9afea67a
@ -13,11 +13,12 @@
|
|||||||
7. Открыть `Кошелёк`, нажать `Проверить` и убедиться, что баланс реально читается из `Solana RPC`; затем открыть `QR и URI` и проверить, что QR-код отрисовывается и сканируется как `solana:`-ссылка.
|
7. Открыть `Кошелёк`, нажать `Проверить` и убедиться, что баланс реально читается из `Solana RPC`; затем открыть `QR и URI` и проверить, что QR-код отрисовывается и сканируется как `solana:`-ссылка.
|
||||||
8. При необходимости отдельно проверить тестовые кнопки `+/- SOL`: они меняют локальный баланс для UX-сценариев, но после следующей реальной RPC-проверки баланс должен вернуться к сетевому значению.
|
8. При необходимости отдельно проверить тестовые кнопки `+/- SOL`: они меняют локальный баланс для UX-сценариев, но после следующей реальной RPC-проверки баланс должен вернуться к сетевому значению.
|
||||||
9. Вернуться на главный экран и проверить, что до выполнения всех условий кнопка регистрации недоступна, а после выполнения становится доступной; также убедиться, что между двумя нижними кнопками есть небольшой зазор.
|
9. Вернуться на главный экран и проверить, что до выполнения всех условий кнопка регистрации недоступна, а после выполнения становится доступной; также убедиться, что между двумя нижними кнопками есть небольшой зазор.
|
||||||
10. Нажать кнопку регистрации и убедиться, что она запускает on-chain flow сразу без отдельного confirm-экрана, а после завершения статус меняется на `Homeserver активен`, онлайн-статус становится активным, и на экране аккаунта появляются краткие отпечатки `PDA/TX`.
|
10. Нажать кнопку регистрации и убедиться, что открывается отдельный экран проверки, где ещё раз видно `login`, статус свободного `PDA`, баланс, `homeserver1` с пометкой о стандартном значении и сообщение, если `Wi-Fi` не подключён.
|
||||||
11. После регистрации проверить через `Solana`/UI проекта, что `user_pda` для этого логина реально создана, сохранена в `NVS` и соответствует `device`-адресу устройства.
|
11. На экране проверки нажать `ЗАРЕГИСТРИРОВАТЬ В СИЯНИИ` и убедиться, что после этого появляется отдельный экран результата с успехом либо подробной ошибкой.
|
||||||
12. Открыть `Запросы`, поочерёдно открыть оба демонстрационных запроса и проверить, что кнопки `Разрешить` и `Отклонить` меняют их статус.
|
12. После успешной регистрации проверить через `Solana`/UI проекта, что `user_pda` для этого логина реально создана, сохранена в `NVS` и соответствует `device`-адресу устройства, а `tx signature` тоже сохранён.
|
||||||
13. При необходимости открыть `Настройки -> Сменить PIN` и убедиться, что новый PIN сохраняется, хотя вход по PIN временно не используется на старте.
|
13. Открыть `Запросы`, поочерёдно открыть оба демонстрационных запроса и проверить, что кнопки `Разрешить` и `Отклонить` меняют их статус.
|
||||||
14. Выполнить `Полный сброс` и убедиться, что все поля, секрет, баланс, онлайн и регистрация очищаются.
|
14. При необходимости открыть `Настройки -> Сменить PIN` и убедиться, что новый PIN сохраняется, хотя вход по PIN временно не используется на старте.
|
||||||
|
15. Выполнить `Полный сброс` и убедиться, что все поля, секрет, баланс, онлайн и регистрация очищаются.
|
||||||
|
|
||||||
- ожидаемый результат:
|
- ожидаемый результат:
|
||||||
новый `ESP32`-скетч стабильно запускается, показывает читаемый интерфейс хотя бы в ASCII-транслитерации, сохраняет данные во внутренней памяти устройства, реально подключается к `Wi-Fi`, реально проверяет `API/RPC/WS`, реально читает баланс из `Solana RPC`, рисует рабочий `QR` для `solana:`-URI и позволяет вручную пройти полный сценарий on-chain регистрации homeserver.
|
новый `ESP32`-скетч стабильно запускается, показывает читаемый интерфейс хотя бы в ASCII-транслитерации, сохраняет данные во внутренней памяти устройства, реально подключается к `Wi-Fi`, реально проверяет `API/RPC/WS`, реально читает баланс из `Solana RPC`, рисует рабочий `QR` для `solana:`-URI и позволяет вручную пройти полный сценарий on-chain регистрации homeserver.
|
||||||
|
|||||||
@ -84,7 +84,8 @@ enum Screen {
|
|||||||
SCREEN_SECRET_GENERATE_RUNNING,
|
SCREEN_SECRET_GENERATE_RUNNING,
|
||||||
SCREEN_SECRET_GENERATE_CANCEL_CONFIRM,
|
SCREEN_SECRET_GENERATE_CANCEL_CONFIRM,
|
||||||
SCREEN_TEXT_EDIT,
|
SCREEN_TEXT_EDIT,
|
||||||
SCREEN_REGISTER_ACCOUNT_PLACEHOLDER,
|
SCREEN_REGISTER_ACCOUNT_CONFIRM,
|
||||||
|
SCREEN_REGISTER_ACCOUNT_RESULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SwipeDirection {
|
enum SwipeDirection {
|
||||||
@ -123,6 +124,7 @@ enum ActionId {
|
|||||||
ACTION_BACK_ACCOUNT,
|
ACTION_BACK_ACCOUNT,
|
||||||
ACTION_REFRESH_BALANCE,
|
ACTION_REFRESH_BALANCE,
|
||||||
ACTION_REGISTER_ACCOUNT,
|
ACTION_REGISTER_ACCOUNT,
|
||||||
|
ACTION_REGISTER_ACCOUNT_EXECUTE,
|
||||||
ACTION_EDITOR_SAVE,
|
ACTION_EDITOR_SAVE,
|
||||||
ACTION_EDITOR_CANCEL,
|
ACTION_EDITOR_CANCEL,
|
||||||
};
|
};
|
||||||
@ -246,6 +248,14 @@ static bool gShowRegisterAccountButton = false;
|
|||||||
static String gUserPdaAddress;
|
static String gUserPdaAddress;
|
||||||
static String gRegistrationSignature;
|
static String gRegistrationSignature;
|
||||||
static String gShineStatusLine = "SHiNE: account not configured";
|
static String gShineStatusLine = "SHiNE: account not configured";
|
||||||
|
static String gRegisterConfirmMessage;
|
||||||
|
static String gRegisterConfirmBalanceLine;
|
||||||
|
static String gRegisterConfirmPdaLine;
|
||||||
|
static String gRegisterConfirmHomeserverLine;
|
||||||
|
static bool gRegisterConfirmCanSubmit = false;
|
||||||
|
static String gRegisterResultMessage;
|
||||||
|
static String gRegisterResultDetails;
|
||||||
|
static bool gRegisterResultSuccess = false;
|
||||||
static String gShineSessionId;
|
static String gShineSessionId;
|
||||||
static String gShineSessionKey;
|
static String gShineSessionKey;
|
||||||
static String gShineStoragePwd;
|
static String gShineStoragePwd;
|
||||||
@ -340,6 +350,7 @@ static String shineWsUrl();
|
|||||||
static String shineHomeLine();
|
static String shineHomeLine();
|
||||||
static String balanceHomeLine();
|
static String balanceHomeLine();
|
||||||
static uint64_t shineNowMs();
|
static uint64_t shineNowMs();
|
||||||
|
static bool loadWalletBalanceLamports(uint64_t &lamportsOut, String &messageOut);
|
||||||
static void shortVecEncode(size_t value, std::vector<uint8_t> &out);
|
static void shortVecEncode(size_t value, std::vector<uint8_t> &out);
|
||||||
static void pushU32LE(std::vector<uint8_t> &out, uint32_t value);
|
static void pushU32LE(std::vector<uint8_t> &out, uint32_t value);
|
||||||
static void pushU64LE(std::vector<uint8_t> &out, uint64_t value);
|
static void pushU64LE(std::vector<uint8_t> &out, uint64_t value);
|
||||||
@ -385,6 +396,7 @@ static bool signMessageEd25519(const std::vector<uint8_t> &message, const uint8_
|
|||||||
static String encodeTransactionBase64(const uint8_t signature[64], const std::vector<uint8_t> &message);
|
static String encodeTransactionBase64(const uint8_t signature[64], const std::vector<uint8_t> &message);
|
||||||
static bool awaitTransactionConfirmation(const String &signatureB58, String &messageOut);
|
static bool awaitTransactionConfirmation(const String &signatureB58, String &messageOut);
|
||||||
static bool registerHomeserverOnSolana(String &messageOut);
|
static bool registerHomeserverOnSolana(String &messageOut);
|
||||||
|
static void prepareRegisterAccountScreen();
|
||||||
static String buildSessionKeyStringFromPublicBase64(const String &pubB64);
|
static String buildSessionKeyStringFromPublicBase64(const String &pubB64);
|
||||||
static bool deriveKeypairFromSeed32(const uint8_t seed32[32], uint8_t pub32[32], uint8_t sec64[64]);
|
static bool deriveKeypairFromSeed32(const uint8_t seed32[32], uint8_t pub32[32], uint8_t sec64[64]);
|
||||||
static bool deriveSeedKeypairFromBase58(const String &seedB58, uint8_t seed32[32], uint8_t pub32[32], uint8_t sec64[64]);
|
static bool deriveSeedKeypairFromBase58(const String &seedB58, uint8_t seed32[32], uint8_t pub32[32], uint8_t sec64[64]);
|
||||||
@ -846,6 +858,14 @@ static void markAccountStateDirty() {
|
|||||||
gShowRegisterAccountButton = false;
|
gShowRegisterAccountButton = false;
|
||||||
gUserPdaAddress = "";
|
gUserPdaAddress = "";
|
||||||
gRegistrationSignature = "";
|
gRegistrationSignature = "";
|
||||||
|
gRegisterConfirmMessage = "";
|
||||||
|
gRegisterConfirmBalanceLine = "";
|
||||||
|
gRegisterConfirmPdaLine = "";
|
||||||
|
gRegisterConfirmHomeserverLine = "";
|
||||||
|
gRegisterConfirmCanSubmit = false;
|
||||||
|
gRegisterResultMessage = "";
|
||||||
|
gRegisterResultDetails = "";
|
||||||
|
gRegisterResultSuccess = false;
|
||||||
clearShineSessionState(true);
|
clearShineSessionState(true);
|
||||||
gShineStatusLine = "SHiNE: account not configured";
|
gShineStatusLine = "SHiNE: account not configured";
|
||||||
}
|
}
|
||||||
@ -947,15 +967,26 @@ static String formatSolValue(uint64_t lamports) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool refreshWalletBalance(String &messageOut) {
|
static bool refreshWalletBalance(String &messageOut) {
|
||||||
messageOut = "";
|
uint64_t lamports = 0;
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (!loadWalletBalanceLamports(lamports, messageOut)) {
|
||||||
gBalanceStatusMessage = "Balance: Wi-Fi disconnected";
|
gBalanceStatusMessage = messageOut;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gBalanceStatusMessage = formatSolValue(lamports);
|
||||||
messageOut = gBalanceStatusMessage;
|
messageOut = gBalanceStatusMessage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool loadWalletBalanceLamports(uint64_t &lamportsOut, String &messageOut) {
|
||||||
|
messageOut = "";
|
||||||
|
lamportsOut = 0;
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
messageOut = "Баланс: Wi-Fi не подключен";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (gDevicePubB58.isEmpty()) {
|
if (gDevicePubB58.isEmpty()) {
|
||||||
gBalanceStatusMessage = "Balance: secret not set";
|
messageOut = "Баланс: секрет не задан";
|
||||||
messageOut = gBalanceStatusMessage;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,20 +994,15 @@ static bool refreshWalletBalance(String &messageOut) {
|
|||||||
String payload;
|
String payload;
|
||||||
String req = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getBalance\",\"params\":[\"" + gDevicePubB58 + "\",{\"commitment\":\"confirmed\"}]}";
|
String req = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getBalance\",\"params\":[\"" + gDevicePubB58 + "\",{\"commitment\":\"confirmed\"}]}";
|
||||||
if (!httpPostJson(gSolanaRpcUrl, req, code, payload)) {
|
if (!httpPostJson(gSolanaRpcUrl, req, code, payload)) {
|
||||||
gBalanceStatusMessage = "Balance: failed to load";
|
messageOut = "Баланс: RPC не ответил";
|
||||||
messageOut = gBalanceStatusMessage;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t lamports = 0;
|
if (!jsonInt64Field(payload, "value", lamportsOut)) {
|
||||||
if (!jsonInt64Field(payload, "value", lamports)) {
|
messageOut = "Баланс: не удалось прочитать";
|
||||||
gBalanceStatusMessage = "Balance: failed to load";
|
|
||||||
messageOut = gBalanceStatusMessage;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gBalanceStatusMessage = formatSolValue(lamports);
|
|
||||||
messageOut = gBalanceStatusMessage;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1525,6 +1551,76 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prepareRegisterAccountScreen() {
|
||||||
|
gRegisterResultMessage = "";
|
||||||
|
gRegisterResultDetails = "";
|
||||||
|
gRegisterResultSuccess = false;
|
||||||
|
gRegisterConfirmMessage = "";
|
||||||
|
gRegisterConfirmBalanceLine = "";
|
||||||
|
gRegisterConfirmPdaLine = "";
|
||||||
|
gRegisterConfirmHomeserverLine = "";
|
||||||
|
gRegisterConfirmCanSubmit = false;
|
||||||
|
|
||||||
|
String cleanLogin = normalizeLoginValue(gLoginValue);
|
||||||
|
if (cleanLogin.isEmpty()) {
|
||||||
|
gRegisterConfirmMessage = "Логин не задан";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!gSecretConfigured) {
|
||||||
|
gRegisterConfirmMessage = "Секрет не задан";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
gRegisterConfirmMessage = "Wi-Fi не подключен";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String balanceMessage;
|
||||||
|
uint64_t lamports = 0;
|
||||||
|
if (!loadWalletBalanceLamports(lamports, balanceMessage)) {
|
||||||
|
gRegisterConfirmMessage = balanceMessage;
|
||||||
|
} else {
|
||||||
|
gRegisterConfirmBalanceLine = formatSolValue(lamports);
|
||||||
|
if (lamports < 20000000ULL) {
|
||||||
|
gRegisterConfirmMessage = "Баланс меньше 0.020 SOL";
|
||||||
|
} else {
|
||||||
|
gRegisterConfirmMessage = "Баланс подходит: 0.020 SOL или выше";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gHomeserverValue.isEmpty()) {
|
||||||
|
gRegisterConfirmHomeserverLine = "Homeserver не задан";
|
||||||
|
} else if (gHomeserverValue == "homeserver1") {
|
||||||
|
gRegisterConfirmHomeserverLine = "Homeserver: homeserver1 (стандартное значение)";
|
||||||
|
} else {
|
||||||
|
gRegisterConfirmHomeserverLine = String("Homeserver: ") + gHomeserverValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShinePdaUserState pdaState;
|
||||||
|
String pdaError;
|
||||||
|
if (!readShineUserPda(cleanLogin, pdaState, pdaError)) {
|
||||||
|
gRegisterConfirmPdaLine = pdaError.isEmpty() ? "PDA: не удалось проверить" : String("PDA: ") + pdaError;
|
||||||
|
if (gRegisterConfirmMessage.isEmpty()) {
|
||||||
|
gRegisterConfirmMessage = pdaError.isEmpty() ? "Не удалось проверить PDA" : pdaError;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdaState.found) {
|
||||||
|
gRegisterConfirmPdaLine = "PDA уже занят, этот login не свободен";
|
||||||
|
if (gRegisterConfirmMessage.isEmpty()) {
|
||||||
|
gRegisterConfirmMessage = "Login уже зарегистрирован";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gRegisterConfirmPdaLine = "PDA свободен для регистрации";
|
||||||
|
if (gRegisterConfirmMessage.isEmpty()) {
|
||||||
|
gRegisterConfirmMessage = "Все проверки пройдены";
|
||||||
|
}
|
||||||
|
gRegisterConfirmCanSubmit = true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool parseShineUserPdaBytes(const std::vector<uint8_t> &bytes, ShinePdaUserState &outState, String &errorOut) {
|
static bool parseShineUserPdaBytes(const std::vector<uint8_t> &bytes, ShinePdaUserState &outState, String &errorOut) {
|
||||||
outState = ShinePdaUserState{};
|
outState = ShinePdaUserState{};
|
||||||
errorOut = "";
|
errorOut = "";
|
||||||
@ -2982,19 +3078,30 @@ static void actionButtonCb(lv_event_t *event) {
|
|||||||
showScreen(SCREEN_SETTINGS_MENU);
|
showScreen(SCREEN_SETTINGS_MENU);
|
||||||
break;
|
break;
|
||||||
case ACTION_REGISTER_ACCOUNT:
|
case ACTION_REGISTER_ACCOUNT:
|
||||||
gAccountStatusMessage = "Регистрация запущена...";
|
prepareRegisterAccountScreen();
|
||||||
gShineStatusLine = "SHiNE: регистрация запущена";
|
showScreen(SCREEN_REGISTER_ACCOUNT_CONFIRM);
|
||||||
{
|
break;
|
||||||
|
case ACTION_REGISTER_ACCOUNT_EXECUTE: {
|
||||||
String registerMessage;
|
String registerMessage;
|
||||||
if (registerHomeserverOnSolana(registerMessage)) {
|
if (registerHomeserverOnSolana(registerMessage)) {
|
||||||
gAccountStatusMessage = registerMessage;
|
gRegisterResultSuccess = true;
|
||||||
|
gRegisterResultMessage = "Регистрация в Сиянии завершена";
|
||||||
|
gRegisterResultDetails = registerMessage;
|
||||||
|
gAccountStatusMessage = "Регистрация завершена";
|
||||||
} else {
|
} else {
|
||||||
|
gRegisterResultSuccess = false;
|
||||||
|
gRegisterResultMessage = "Регистрация не выполнена";
|
||||||
|
gRegisterResultDetails = registerMessage;
|
||||||
gAccountStatusMessage = registerMessage;
|
gAccountStatusMessage = registerMessage;
|
||||||
gShineStatusLine = String("SHiNE: ") + registerMessage;
|
|
||||||
}
|
|
||||||
rebuildScreen();
|
|
||||||
}
|
}
|
||||||
|
gRegisterConfirmMessage = "";
|
||||||
|
gRegisterConfirmBalanceLine = "";
|
||||||
|
gRegisterConfirmPdaLine = "";
|
||||||
|
gRegisterConfirmHomeserverLine = "";
|
||||||
|
gRegisterConfirmCanSubmit = false;
|
||||||
|
showScreen(SCREEN_REGISTER_ACCOUNT_RESULT);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case ACTION_OPEN_WIFI:
|
case ACTION_OPEN_WIFI:
|
||||||
gWifiViewMode = WIFI_VIEW_OVERVIEW;
|
gWifiViewMode = WIFI_VIEW_OVERVIEW;
|
||||||
showScreen(SCREEN_WIFI);
|
showScreen(SCREEN_WIFI);
|
||||||
@ -3525,12 +3632,50 @@ static void drawSecretGenerateCancelConfirmScreen() {
|
|||||||
makeVersionTag();
|
makeVersionTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawRegisterAccountPlaceholderScreen() {
|
static void drawRegisterAccountConfirmScreen() {
|
||||||
setRootStyle();
|
setRootStyle();
|
||||||
makeTitle("REGISTER ACCOUNT", 22, &lv_font_montserrat_24);
|
makeTitle("REGISTER ACCOUNT", 22, &lv_font_montserrat_24);
|
||||||
makeBody("Registration now starts directly from the home screen button.", 112, 420);
|
String topLine = gRegisterConfirmMessage.isEmpty() ? String("Проверка регистрации") : gRegisterConfirmMessage;
|
||||||
makeBody("This screen is kept only as a fallback status page.", 156, 420);
|
makeBody(topLine.c_str(), 96, 420);
|
||||||
makeButton("BACK", 140, 360, 200, 72, 0x5A6570, ACTION_BACK_HOME, &lv_font_montserrat_22);
|
if (!gRegisterConfirmPdaLine.isEmpty()) {
|
||||||
|
makeBody(gRegisterConfirmPdaLine.c_str(), 138, 420);
|
||||||
|
}
|
||||||
|
if (!gRegisterConfirmBalanceLine.isEmpty()) {
|
||||||
|
makeBody(gRegisterConfirmBalanceLine.c_str(), 180, 420);
|
||||||
|
}
|
||||||
|
if (!gRegisterConfirmHomeserverLine.isEmpty()) {
|
||||||
|
makeBody(gRegisterConfirmHomeserverLine.c_str(), 222, 420);
|
||||||
|
}
|
||||||
|
if (gRegisterConfirmCanSubmit) {
|
||||||
|
makeButton("ЗАРЕГИСТРИРОВАТЬ В СИЯНИИ", 22, 296, 436, 74, 0x2A9D8F, ACTION_REGISTER_ACCOUNT_EXECUTE, &lv_font_montserrat_18);
|
||||||
|
} else {
|
||||||
|
makeButton("НЕДОСТУПНО", 22, 296, 436, 74, 0x4A5560, ACTION_NONE, &lv_font_montserrat_20);
|
||||||
|
}
|
||||||
|
makeButton("BACK", 140, 384, 200, 54, 0x5A6570, ACTION_BACK_HOME, &lv_font_montserrat_20);
|
||||||
|
makeVersionTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drawRegisterAccountResultScreen() {
|
||||||
|
setRootStyle();
|
||||||
|
makeTitle("REGISTER RESULT", 22, &lv_font_montserrat_24);
|
||||||
|
String resultTopLine = gRegisterResultSuccess ? String("Регистрация завершилась успешно") : String("Регистрация завершилась с ошибкой");
|
||||||
|
makeBody(resultTopLine.c_str(), 96, 420);
|
||||||
|
makeBody(gRegisterResultMessage.c_str(), 140, 420);
|
||||||
|
if (!gRegisterResultDetails.isEmpty()) {
|
||||||
|
makeBody(gRegisterResultDetails.c_str(), 184, 420);
|
||||||
|
}
|
||||||
|
if (gRegisterResultSuccess) {
|
||||||
|
if (!gUserPdaAddress.isEmpty()) {
|
||||||
|
String pdaLine = String("user_pda: ") + abbreviateValue(gUserPdaAddress, 12, 8);
|
||||||
|
makeBody(pdaLine.c_str(), 228, 420);
|
||||||
|
}
|
||||||
|
if (!gRegistrationSignature.isEmpty()) {
|
||||||
|
String txLine = String("tx: ") + abbreviateValue(gRegistrationSignature, 12, 8);
|
||||||
|
makeBody(txLine.c_str(), 270, 420);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
makeButton("BACK HOME", 22, 372, 200, 58, 0x5A6570, ACTION_BACK_HOME, &lv_font_montserrat_20);
|
||||||
|
makeButton("ACCOUNT", 258, 372, 200, 58, 0x2A6F97, ACTION_OPEN_ACCOUNT, &lv_font_montserrat_20);
|
||||||
makeVersionTag();
|
makeVersionTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3694,8 +3839,11 @@ static void rebuildScreen() {
|
|||||||
case SCREEN_TEXT_EDIT:
|
case SCREEN_TEXT_EDIT:
|
||||||
drawTextEditScreen();
|
drawTextEditScreen();
|
||||||
break;
|
break;
|
||||||
case SCREEN_REGISTER_ACCOUNT_PLACEHOLDER:
|
case SCREEN_REGISTER_ACCOUNT_CONFIRM:
|
||||||
drawRegisterAccountPlaceholderScreen();
|
drawRegisterAccountConfirmScreen();
|
||||||
|
break;
|
||||||
|
case SCREEN_REGISTER_ACCOUNT_RESULT:
|
||||||
|
drawRegisterAccountResultScreen();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3821,7 +3969,8 @@ static void handleSwipe(SwipeDirection swipe) {
|
|||||||
case SCREEN_TEXT_EDIT:
|
case SCREEN_TEXT_EDIT:
|
||||||
handleTextEditSwipe(swipe);
|
handleTextEditSwipe(swipe);
|
||||||
break;
|
break;
|
||||||
case SCREEN_REGISTER_ACCOUNT_PLACEHOLDER:
|
case SCREEN_REGISTER_ACCOUNT_CONFIRM:
|
||||||
|
case SCREEN_REGISTER_ACCOUNT_RESULT:
|
||||||
handleHomeSwipe(swipe);
|
handleHomeSwipe(swipe);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,6 +102,8 @@
|
|||||||
13. `PIN_EDIT`
|
13. `PIN_EDIT`
|
||||||
14. `TEXT_INPUT`
|
14. `TEXT_INPUT`
|
||||||
15. `CONFIRM`
|
15. `CONFIRM`
|
||||||
|
16. `REGISTER_ACCOUNT_CONFIRM`
|
||||||
|
17. `REGISTER_ACCOUNT_RESULT`
|
||||||
|
|
||||||
## Общие правила интерфейса
|
## Общие правила интерфейса
|
||||||
|
|
||||||
@ -166,6 +168,52 @@
|
|||||||
- вместо призыва к регистрации показывается статус `Homeserver активен`.
|
- вместо призыва к регистрации показывается статус `Homeserver активен`.
|
||||||
- две нижние кнопки внизу экрана не прилегают вплотную друг к другу, между ними есть небольшой зазор.
|
- две нижние кнопки внизу экрана не прилегают вплотную друг к другу, между ними есть небольшой зазор.
|
||||||
|
|
||||||
|
## Экран REGISTER_ACCOUNT_CONFIRM
|
||||||
|
|
||||||
|
Показывает предварительную проверку перед отправкой транзакции регистрации.
|
||||||
|
|
||||||
|
Отображается:
|
||||||
|
|
||||||
|
- повторный `login`;
|
||||||
|
- сообщение о том, что логин свободен или уже занят;
|
||||||
|
- баланс кошелька с проверкой порога `0.020 SOL`;
|
||||||
|
- имя homeserver;
|
||||||
|
- пометка, если используется стандартное значение `homeserver1`;
|
||||||
|
- отдельное предупреждение, если `Wi-Fi` не подключён.
|
||||||
|
|
||||||
|
Кнопки:
|
||||||
|
|
||||||
|
- `ЗАРЕГИСТРИРОВАТЬ В СИЯНИИ`
|
||||||
|
- `BACK`
|
||||||
|
|
||||||
|
Поведение:
|
||||||
|
|
||||||
|
- если `Wi-Fi` не подключён, на экране прямо показывается уведомление об этом и кнопка регистрации недоступна;
|
||||||
|
- если `login` уже занят в `shine_users`, регистрация недоступна;
|
||||||
|
- если баланс меньше `0.020 SOL`, на экране показывается соответствующая ошибка;
|
||||||
|
- если все проверки пройдены, кнопка регистрации активна и запускает on-chain регистрацию.
|
||||||
|
|
||||||
|
## Экран REGISTER_ACCOUNT_RESULT
|
||||||
|
|
||||||
|
Показывает результат отправки регистрации.
|
||||||
|
|
||||||
|
Отображается:
|
||||||
|
|
||||||
|
- текст успеха или ошибки;
|
||||||
|
- подробное сообщение;
|
||||||
|
- при успехе краткий `user_pda`;
|
||||||
|
- при успехе краткий `tx signature`.
|
||||||
|
|
||||||
|
Кнопки:
|
||||||
|
|
||||||
|
- `BACK HOME`
|
||||||
|
- `ACCOUNT`
|
||||||
|
|
||||||
|
Поведение:
|
||||||
|
|
||||||
|
- после успешной регистрации данные `user_pda` и `tx signature` сохраняются в `NVS`;
|
||||||
|
- при ошибке на экране показывается причина отказа.
|
||||||
|
|
||||||
## Экран STATUS
|
## Экран STATUS
|
||||||
|
|
||||||
Показывает сводку:
|
Показывает сводку:
|
||||||
@ -441,7 +489,10 @@ QR должен быть сканируемым, а не декоративны
|
|||||||
11. при необходимости пополнить баланс;
|
11. при необходимости пополнить баланс;
|
||||||
12. вернуться на `HOME`;
|
12. вернуться на `HOME`;
|
||||||
13. нажать `REGISTER ACCOUNT`;
|
13. нажать `REGISTER ACCOUNT`;
|
||||||
14. после завершения увидеть статус `Homeserver активен`.
|
14. на экране проверки ещё раз увидеть `login`, статус свободного `PDA`, баланс, `homeserver1` и при необходимости сообщение о неподключённом `Wi-Fi`;
|
||||||
|
15. нажать `ЗАРЕГИСТРИРОВАТЬ В СИЯНИИ`;
|
||||||
|
16. после завершения увидеть либо экран успеха с `user_pda` и `tx signature`, либо подробную ошибку;
|
||||||
|
17. после успешной регистрации увидеть статус `Homeserver активен`.
|
||||||
|
|
||||||
Примечание:
|
Примечание:
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.164
|
client.version=1.2.165
|
||||||
server.version=1.2.153
|
server.version=1.2.154
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user