diff --git a/Apps/Brainfuck/manifest.properties b/Apps/Brainfuck/manifest.properties index 1e2fee1..63e3367 100644 --- a/Apps/Brainfuck/manifest.properties +++ b/Apps/Brainfuck/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.brainfuck -app.version.name=0.8.0 -app.version.code=8 +app.id=tactility.brainfuck +app.version.name=0.9.0 +app.version.code=9 app.name=Brainfuck interpreter app.description=Brainfuck esoteric language interpreter diff --git a/Apps/Breakout/manifest.properties b/Apps/Breakout/manifest.properties index 12b6fde..717a50d 100644 --- a/Apps/Breakout/manifest.properties +++ b/Apps/Breakout/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.breakout -app.version.name=0.9.0 -app.version.code=9 +app.id=tactility.breakout +app.version.name=0.10.0 +app.version.code=10 app.name=Breakout app.description=Classic brick-breaking arcade game diff --git a/Apps/Calculator/main/Source/Calculator.cpp b/Apps/Calculator/main/Source/Calculator.cpp index 7187c81..08cb4d0 100644 --- a/Apps/Calculator/main/Source/Calculator.cpp +++ b/Apps/Calculator/main/Source/Calculator.cpp @@ -14,63 +14,96 @@ constexpr auto* TAG = "Calculator"; static int precedence(char op) { if (op == '+' || op == '-') return 1; if (op == '*' || op == '/') return 2; + if (op == '~') return 3; // unary minus marker, binds tighter than * and / return 0; } -static std::deque infixToRPN(const std::string& infix) { +static bool infixToRPN(const std::string& infix, std::deque& output) { std::stack opStack; - std::deque output; + output.clear(); std::string token; size_t i = 0; + bool expectOperand = true; // true at start, after '(', or after a binary/unary operator while (i < infix.length()) { char ch = infix[i]; - if (isdigit(ch)) { + if (isdigit((unsigned char)ch) || ch == '.') { token.clear(); - while (i < infix.length() && (isdigit(infix[i]) || infix[i] == '.')) { token += infix[i++]; } + bool hasDecimalPoint = false; + while (i < infix.length()) { + char current = infix[i]; + if (isdigit((unsigned char)current)) { + token += current; + } else if (current == '.' && !hasDecimalPoint) { + hasDecimalPoint = true; + token += current; + } else { + break; + } + ++i; + } + if (i < infix.length() && infix[i] == '.') return false; + if (token.find_first_of("0123456789") == std::string::npos) return false; // no digits, e.g. "." output.push_back(token); + expectOperand = false; continue; } - if (ch == '(') { opStack.push(ch); } else if (ch == ')') { + if (ch == '(') { + opStack.push(ch); + expectOperand = true; + } else if (ch == ')') { while (!opStack.empty() && opStack.top() != '(') { output.push_back(std::string(1, opStack.top())); opStack.pop(); } - opStack.pop(); + if (opStack.empty()) return false; // unmatched ')' + opStack.pop(); // remove matching '(' + expectOperand = false; + } else if (ch == '-' && expectOperand) { + // unary minus: push a marker that binds only to the next operand + opStack.push('~'); + expectOperand = true; } else if (strchr("+-*/", ch)) { while (!opStack.empty() && precedence(opStack.top()) >= precedence(ch)) { output.push_back(std::string(1, opStack.top())); opStack.pop(); } opStack.push(ch); + expectOperand = true; } i++; } while (!opStack.empty()) { + if (opStack.top() == '(') return false; // unmatched '(' output.push_back(std::string(1, opStack.top())); opStack.pop(); } - return output; + return true; } -static double evaluateRPN(std::deque rpnQueue) { +static bool evaluateRPN(std::deque rpnQueue, double& result) { std::stack values; while (!rpnQueue.empty()) { std::string token = rpnQueue.front(); rpnQueue.pop_front(); - if (isdigit(token[0])) { + if (isdigit((unsigned char)token[0]) || token[0] == '.') { double d; sscanf(token.c_str(), "%lf", &d); values.push(d); + } else if (token[0] == '~') { + if (values.empty()) return false; + double a = values.top(); + values.pop(); + values.push(-a); } else if (strchr("+-*/", token[0])) { - if (values.size() < 2) return 0; + if (values.size() < 2) return false; double b = values.top(); values.pop(); @@ -80,15 +113,22 @@ static double evaluateRPN(std::deque rpnQueue) { if (token[0] == '+') values.push(a + b); else if (token[0] == '-') values.push(a - b); else if (token[0] == '*') values.push(a * b); - else if (token[0] == '/' && b != 0) values.push(a / b); + else if (token[0] == '/') { + if (b == 0) return false; + values.push(a / b); + } } } - return values.empty() ? 0 : values.top(); + if (values.size() != 1) return false; + result = values.top(); + return true; } -static double computeFormula(Context* ctx) { - return evaluateRPN(infixToRPN(std::string(ctx->formulaBuffer))); +static bool computeFormula(Context* ctx, double& result) { + std::deque rpn; + if (!infixToRPN(std::string(ctx->formulaBuffer), rpn) || rpn.empty()) return false; + return evaluateRPN(std::move(rpn), result); } static void resetCalculator(Context* ctx) { @@ -96,24 +136,27 @@ static void resetCalculator(Context* ctx) { lv_label_set_text(ctx->displayLabel, "0"); lv_label_set_text(ctx->resultLabel, ""); ctx->newInput = true; + ctx->hasLastResult = false; } static void evaluateExpression(Context* ctx) { - double result = computeFormula(ctx); + double result; + if (!computeFormula(ctx, result)) { + lv_label_set_text(ctx->displayLabel, "Error"); + lv_label_set_text(ctx->resultLabel, ctx->formulaBuffer); + ctx->newInput = true; + return; + } - size_t formulaLen = strlen(ctx->formulaBuffer); - size_t maxAvailable = sizeof(ctx->formulaBuffer) - formulaLen - 1; + char equationBuffer[192]; + snprintf(equationBuffer, sizeof(equationBuffer), "%s = %.8g", ctx->formulaBuffer, result); - if (maxAvailable > 10) { - char resultBuffer[32]; - snprintf(resultBuffer, sizeof(resultBuffer), " = %.8g", result); - strncat(ctx->formulaBuffer, resultBuffer, maxAvailable); - } else { - snprintf(ctx->formulaBuffer, sizeof(ctx->formulaBuffer), "%.8g", result); - } + snprintf(ctx->formulaBuffer, sizeof(ctx->formulaBuffer), "%.8g", result); + snprintf(ctx->lastResult, sizeof(ctx->lastResult), "%.8g", result); + ctx->hasLastResult = true; lv_label_set_text(ctx->displayLabel, "0"); - lv_label_set_text(ctx->resultLabel, ctx->formulaBuffer); + lv_label_set_text(ctx->resultLabel, equationBuffer); ctx->newInput = true; } @@ -128,6 +171,17 @@ static void handleInput(Context* ctx, const char* txt) { return; } + char resToken[sizeof(ctx->lastResult) + 2]; + if (strcmp(txt, "RES") == 0) { + if (!ctx->hasLastResult) return; + if (ctx->lastResult[0] == '-') { + snprintf(resToken, sizeof(resToken), "(%s)", ctx->lastResult); + } else { + snprintf(resToken, sizeof(resToken), "%s", ctx->lastResult); + } + txt = resToken; + } + if (strlen(ctx->formulaBuffer) + strlen(txt) < sizeof(ctx->formulaBuffer) - 1) { if (ctx->newInput) { memset(ctx->formulaBuffer, 0, sizeof(ctx->formulaBuffer)); @@ -188,7 +242,7 @@ void calculatorCreateWidgets(lv_obj_t* parent, void* userData) { "7", "8", "9", "*", "\n", "4", "5", "6", "-", "\n", "1", "2", "3", "+", "\n", - "0", "=", "", "", "" + "0", ".", "RES", "=", "" }; lv_obj_t* buttonmatrix = lv_buttonmatrix_create(parent); diff --git a/Apps/Calculator/main/Source/Calculator.h b/Apps/Calculator/main/Source/Calculator.h index dfd7760..20ae2b5 100644 --- a/Apps/Calculator/main/Source/Calculator.h +++ b/Apps/Calculator/main/Source/Calculator.h @@ -10,6 +10,8 @@ struct Context { lv_obj_t* resultLabel = nullptr; char formulaBuffer[128] = {0}; // Stores the full input expression bool newInput = true; + char lastResult[32] = {0}; // Last computed result, empty if none available + bool hasLastResult = false; }; /** window_manager_create()'s WindowCreateWidgetsFn - @a userData is the Context* for this instance. */ diff --git a/Apps/Calculator/manifest.properties b/Apps/Calculator/manifest.properties index 591ed0d..557736c 100644 --- a/Apps/Calculator/manifest.properties +++ b/Apps/Calculator/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.calculator -app.version.name=0.9.0 -app.version.code=9 +app.id=tactility.calculator +app.version.name=0.10.0 +app.version.code=10 app.name=Calculator diff --git a/Apps/Diceware/manifest.properties b/Apps/Diceware/manifest.properties index 62401f3..4212b53 100644 --- a/Apps/Diceware/manifest.properties +++ b/Apps/Diceware/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.diceware -app.version.name=0.10.0 -app.version.code=10 +app.id=tactility.diceware +app.version.name=0.11.0 +app.version.code=11 app.name=Diceware diff --git a/Apps/EpubReader/manifest.properties b/Apps/EpubReader/manifest.properties index 863fbd9..3b4fada 100644 --- a/Apps/EpubReader/manifest.properties +++ b/Apps/EpubReader/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32s3,esp32p4 -app.id=one.tactility.epubreader -app.version.name=0.7.0 -app.version.code=7 +app.id=tactility.epubreader +app.version.name=0.8.0 +app.version.code=8 app.name=Epub Reader app.description=Epub and text file reader. Requires PSRAM! diff --git a/Apps/EspNowBridge/manifest.properties b/Apps/EspNowBridge/manifest.properties index 3c8169c..7b5fffa 100644 --- a/Apps/EspNowBridge/manifest.properties +++ b/Apps/EspNowBridge/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32p4 -app.id=one.tactility.espnowbridge -app.version.name=0.5.0 -app.version.code=5 +app.id=tactility.espnowbridge +app.version.name=0.6.0 +app.version.code=6 app.name=ESP-NOW Bridge app.description=Companion app for updating P4 device C6 co-processor firmware to enable ESP-NOW bridge support. diff --git a/Apps/GPIO/manifest.properties b/Apps/GPIO/manifest.properties index 2211386..753fac2 100644 --- a/Apps/GPIO/manifest.properties +++ b/Apps/GPIO/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.gpio -app.version.name=0.11.0 -app.version.code=11 +app.id=tactility.gpio +app.version.name=0.12.0 +app.version.code=12 app.name=GPIO diff --git a/Apps/GraphicsDemo/manifest.properties b/Apps/GraphicsDemo/manifest.properties index 28382af..51f34a2 100644 --- a/Apps/GraphicsDemo/manifest.properties +++ b/Apps/GraphicsDemo/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.graphicsdemo -app.version.name=0.9.0 -app.version.code=9 +app.id=tactility.graphicsdemo +app.version.name=0.10.0 +app.version.code=10 app.name=Graphics Demo diff --git a/Apps/HelloWorld/manifest.properties b/Apps/HelloWorld/manifest.properties index 81dab11..3f46bdf 100644 --- a/Apps/HelloWorld/manifest.properties +++ b/Apps/HelloWorld/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.helloworld -app.version.name=0.9.0 -app.version.code=9 +app.id=tactility.helloworld +app.version.name=0.10.0 +app.version.code=10 app.name=Hello World diff --git a/Apps/M5UnitTest/manifest.properties b/Apps/M5UnitTest/manifest.properties index 65809dc..2c842b7 100644 --- a/Apps/M5UnitTest/manifest.properties +++ b/Apps/M5UnitTest/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32s3,esp32p4 -app.id=one.tactility.m5unittest -app.version.name=0.7.0 -app.version.code=7 +app.id=tactility.m5unittest +app.version.name=0.8.0 +app.version.code=8 app.name=M5 Unit Test diff --git a/Apps/Magic8Ball/manifest.properties b/Apps/Magic8Ball/manifest.properties index 3abdc42..229b59d 100644 --- a/Apps/Magic8Ball/manifest.properties +++ b/Apps/Magic8Ball/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.magic8ball -app.version.name=0.8.0 -app.version.code=8 +app.id=tactility.magic8ball +app.version.name=0.9.0 +app.version.code=9 app.name=Magic 8-Ball diff --git a/Apps/MediaKeys/manifest.properties b/Apps/MediaKeys/manifest.properties index 216f01a..dbd84fa 100644 --- a/Apps/MediaKeys/manifest.properties +++ b/Apps/MediaKeys/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32s3,esp32p4 -app.id=one.tactility.mediakeys -app.version.name=0.8.0 -app.version.code=8 +app.id=tactility.mediakeys +app.version.name=0.9.0 +app.version.code=9 app.name=Media Keys app.description=Bluetooth media keys. Touch or Physical Keyboard control\nB - previous, P - play/pause, N - next, M - mute, D - volume down, U - volume up.\nQ or ESC to exit focus. diff --git a/Apps/MystifyDemo/manifest.properties b/Apps/MystifyDemo/manifest.properties index e89769a..9867d2c 100644 --- a/Apps/MystifyDemo/manifest.properties +++ b/Apps/MystifyDemo/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.mystifydemo -app.version.name=0.10.0 -app.version.code=10 +app.id=tactility.mystifydemo +app.version.name=0.11.0 +app.version.code=11 app.name=Mystify Demo diff --git a/Apps/SerialConsole/main/Source/ConnectView.cpp b/Apps/SerialConsole/main/Source/ConnectView.cpp index de5ab99..b1c083d 100644 --- a/Apps/SerialConsole/main/Source/ConnectView.cpp +++ b/Apps/SerialConsole/main/Source/ConnectView.cpp @@ -6,9 +6,9 @@ #include #include +#include #include #include -#include #include #include @@ -19,11 +19,11 @@ namespace { constexpr TickType_t LVGL_DEFAULT_LOCK_TIME = 500; // 500 ticks = 500 ms bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.serialconsole", "serial_console.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/serial_console.properties"; + outPath = std::string(path); return true; } diff --git a/Apps/SerialConsole/manifest.properties b/Apps/SerialConsole/manifest.properties index 17ee83d..08d09cb 100644 --- a/Apps/SerialConsole/manifest.properties +++ b/Apps/SerialConsole/manifest.properties @@ -1,7 +1,7 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.serialconsole -app.version.name=0.11.0 -app.version.code=11 +app.id=tactility.serialconsole +app.version.name=0.12.0 +app.version.code=12 app.name=Serial Console diff --git a/Apps/Snake/main/Source/Snake.cpp b/Apps/Snake/main/Source/Snake.cpp index e629115..9be7aaf 100644 --- a/Apps/Snake/main/Source/Snake.cpp +++ b/Apps/Snake/main/Source/Snake.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -45,11 +45,11 @@ uint32_t getActionIconPadding(UiDensity uiDensity) { } bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.snake", "snake.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/snake.properties"; + outPath = std::string(path); return true; } @@ -264,7 +264,7 @@ void snakeTeardown(Context* ctx) { void snakeShowSelectionDialog(Context* ctx) { const char* argv[] = { "Snake", "How to Play", "Easy", "Medium", "Hard", "Hell" }; - app_manager_start_for_result("SelectionDialog", ctx->appInstanceId, 6, argv, &ctx->selectionDialogId); + app_manager_start_for_result("tactility.selectiondialog", ctx->appInstanceId, 6, argv, &ctx->selectionDialogId); } void snakeShowHelpDialog(Context* ctx) { @@ -275,7 +275,7 @@ void snakeShowHelpDialog(Context* ctx) { "Don't hit yourself!", "OK", }; - app_manager_start_for_result("AlertDialog", ctx->appInstanceId, 3, argv, &ctx->helpDialogId); + app_manager_start_for_result("tactility.alertdialog", ctx->appInstanceId, 3, argv, &ctx->helpDialogId); } void snakeClearGame(Context* ctx) { diff --git a/Apps/Snake/manifest.properties b/Apps/Snake/manifest.properties index 001482e..678fd45 100644 --- a/Apps/Snake/manifest.properties +++ b/Apps/Snake/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.snake -app.version.name=0.12.0 -app.version.code=12 +app.id=tactility.snake +app.version.name=0.13.0 +app.version.code=13 app.name=Snake app.description=Classic Snake game diff --git a/Apps/TamaTac/main/Source/Achievements.cpp b/Apps/TamaTac/main/Source/Achievements.cpp index 3c36b70..85e5ff4 100644 --- a/Apps/TamaTac/main/Source/Achievements.cpp +++ b/Apps/TamaTac/main/Source/Achievements.cpp @@ -5,7 +5,7 @@ #include "Achievements.h" #include "TamaTac.h" -#include +#include #include #include #include @@ -13,11 +13,11 @@ namespace { bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.tamatac", "achievements.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/tamatac_achievements.properties"; + outPath = std::string(path); return true; } diff --git a/Apps/TamaTac/main/Source/CemeteryView.cpp b/Apps/TamaTac/main/Source/CemeteryView.cpp index c80a2e4..4c0cba1 100644 --- a/Apps/TamaTac/main/Source/CemeteryView.cpp +++ b/Apps/TamaTac/main/Source/CemeteryView.cpp @@ -5,7 +5,7 @@ #include "CemeteryView.h" #include "TamaTac.h" -#include +#include #include #include #include @@ -13,11 +13,11 @@ namespace { bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.tamatac", "cemetery.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/tamatac_cemetery.properties"; + outPath = std::string(path); return true; } diff --git a/Apps/TamaTac/main/Source/PetLogic.cpp b/Apps/TamaTac/main/Source/PetLogic.cpp index f3bf0d2..efb0c00 100644 --- a/Apps/TamaTac/main/Source/PetLogic.cpp +++ b/Apps/TamaTac/main/Source/PetLogic.cpp @@ -4,7 +4,7 @@ */ #include "PetLogic.h" -#include +#include #include #include #include @@ -13,11 +13,11 @@ namespace { bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.tamatac", "pet.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/tamatac_pet.properties"; + outPath = std::string(path); return true; } diff --git a/Apps/TamaTac/main/Source/SettingsView.cpp b/Apps/TamaTac/main/Source/SettingsView.cpp index b640c5c..1feac18 100644 --- a/Apps/TamaTac/main/Source/SettingsView.cpp +++ b/Apps/TamaTac/main/Source/SettingsView.cpp @@ -5,18 +5,18 @@ #include "SettingsView.h" #include "TamaTac.h" -#include +#include #include #include namespace { bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.tamatac", "tamatac.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/tamatac_settings.properties"; + outPath = std::string(path); return true; } diff --git a/Apps/TamaTac/manifest.properties b/Apps/TamaTac/manifest.properties index bf28336..b11549a 100644 --- a/Apps/TamaTac/manifest.properties +++ b/Apps/TamaTac/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.tamatac -app.version.name=0.7.0 -app.version.code=7 +app.id=tactility.tamatac +app.version.name=0.8.0 +app.version.code=8 app.name=TamaTac app.description=Virtual pet inspired by Tamagotchi. Only runs on devices with PSRAM. diff --git a/Apps/TodoList/manifest.properties b/Apps/TodoList/manifest.properties index d621a4d..800451f 100644 --- a/Apps/TodoList/manifest.properties +++ b/Apps/TodoList/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.todolist -app.version.name=0.9.0 -app.version.code=9 +app.id=tactility.todolist +app.version.name=0.10.0 +app.version.code=10 app.name=Todo List app.description=Simple task list manager diff --git a/Apps/TwoEleven/main/Source/TwoEleven.cpp b/Apps/TwoEleven/main/Source/TwoEleven.cpp index de1039c..8210bdb 100644 --- a/Apps/TwoEleven/main/Source/TwoEleven.cpp +++ b/Apps/TwoEleven/main/Source/TwoEleven.cpp @@ -5,12 +5,13 @@ #include "TwoEleven.h" #include +#include #include #include #include +#include #include #include -#include #include #include @@ -22,11 +23,11 @@ constexpr size_t SIZE_COUNT = 4; constexpr uint16_t gridSizes[SIZE_COUNT] = { 3, 4, 5, 6 }; bool getPreferencesPath(std::string& outPath) { - char root[128]; - if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) { + char path[128]; + if (app_paths_get_user_data_path("tactility.twoeleven", "two_eleven.properties", path, sizeof(path)) != ERROR_NONE) { return false; } - outPath = std::string(root) + "/two_eleven.properties"; + outPath = std::string(path); return true; } @@ -116,7 +117,7 @@ void twoElevenEventCb(lv_event_t* e) { snprintf(message, sizeof(message), "YOU WIN!\n\nSCORE: %" PRId32 "\nBEST: %" PRId32, score, getHighScore(ctx, ctx->currentGridSize)); } const char* argv[] = { title, message, "OK" }; - app_manager_start_for_result("AlertDialog", ctx->appInstanceId, 3, argv, &ctx->gameOverDialogId); + app_manager_start_for_result("tactility.alertdialog", ctx->appInstanceId, 3, argv, &ctx->gameOverDialogId); } else if (ctx->gameOverDialogId == 0 && twoeleven_get_status(ctx->gameObject)) { int32_t prevHighScore = getHighScore(ctx, ctx->currentGridSize); bool isNewHighScore = score > prevHighScore; @@ -136,7 +137,7 @@ void twoElevenEventCb(lv_event_t* e) { snprintf(message, sizeof(message), "GAME OVER!\n\nSCORE: %" PRId32 "\nBEST: %" PRId32, score, getHighScore(ctx, ctx->currentGridSize)); } const char* argv[] = { title, message, "OK" }; - app_manager_start_for_result("AlertDialog", ctx->appInstanceId, 3, argv, &ctx->gameOverDialogId); + app_manager_start_for_result("tactility.alertdialog", ctx->appInstanceId, 3, argv, &ctx->gameOverDialogId); } else { // Update score display lv_label_set_text_fmt(ctx->scoreLabel, "SCORE: %" PRId32, score); @@ -214,6 +215,7 @@ void createGame(Context* ctx, lv_obj_t* parent, uint16_t size, lv_obj_t* tb) { } // namespace void twoElevenCreateWidgets(lv_obj_t* parent, void* userData) { + ESP_LOGI("TwoEleven", "twoElevenCreateWidgets called, parent=%p", parent); auto* ctx = static_cast(userData); lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE); @@ -267,7 +269,7 @@ void twoElevenTeardown(Context* ctx) { void twoElevenShowSelectionDialog(Context* ctx) { const char* argv[] = { "2048", "How to Play", "3x3", "4x4", "5x5", "6x6" }; - app_manager_start_for_result("SelectionDialog", ctx->appInstanceId, 6, argv, &ctx->selectionDialogId); + app_manager_start_for_result("tactility.selectiondialog", ctx->appInstanceId, 6, argv, &ctx->selectionDialogId); } void twoElevenShowHelpDialog(Context* ctx) { @@ -278,7 +280,7 @@ void twoElevenShowHelpDialog(Context* ctx) { "Reach 2048 to win!", "OK", }; - app_manager_start_for_result("AlertDialog", ctx->appInstanceId, 3, argv, &ctx->helpDialogId); + app_manager_start_for_result("tactility.alertdialog", ctx->appInstanceId, 3, argv, &ctx->helpDialogId); } void twoElevenClearGame(Context* ctx) { diff --git a/Apps/TwoEleven/manifest.properties b/Apps/TwoEleven/manifest.properties index 500dcd7..e2a2583 100644 --- a/Apps/TwoEleven/manifest.properties +++ b/Apps/TwoEleven/manifest.properties @@ -1,8 +1,8 @@ manifest.version=0.2 target.sdk=0.8.0-dev target.platforms=esp32,esp32s3,esp32c6,esp32p4 -app.id=one.tactility.twoeleven -app.version.name=0.11.0 -app.version.code=11 +app.id=tactility.twoeleven +app.version.name=0.12.0 +app.version.code=12 app.name=2048 app.description=A fun, customizable 2048 sliding tile game for tactility!\nSlide tiles to combine numbers and reach 2048.\nChoose grid sizes: 3x3 (easy), 4x4 (classic), 5x5, or 6x6 (expert). diff --git a/Libraries/TactilityCpp/Include/TactilityCpp/App.h b/Libraries/TactilityCpp/Include/TactilityCpp/App.h deleted file mode 100644 index ada4f41..0000000 --- a/Libraries/TactilityCpp/Include/TactilityCpp/App.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include - -class App { -public: - virtual void onCreate(AppHandle app) {} - virtual void onDestroy(AppHandle app) {} - virtual void onShow(AppHandle context, lv_obj_t* parent) {} - virtual void onHide(AppHandle context) {} - virtual void onResult(AppHandle app, void* _Nullable data, AppLaunchId launchId, AppResult result, BundleHandle resultData) {} -}; - -template -concept AppClass = std::is_base_of::value; - -template -void onAppCreate(AppHandle app, void* _Nullable data) { - static_cast(data)->onCreate(app); -} - -template -void onAppDestroy(AppHandle app, void* _Nullable data) { - static_cast(data)->onDestroy(app); -} - -template -void onAppShow(AppHandle context, void* _Nullable data, lv_obj_t* parent) { - static_cast(data)->onShow(context, parent); -} - -template -void onAppHide(AppHandle context, void* _Nullable data) { - static_cast(data)->onHide(context); -} - -template -void onAppResult(AppHandle app, void* _Nullable data, AppLaunchId launchId, AppResult result, BundleHandle resultData) { - static_cast(data)->onResult(app, data, launchId, result, resultData); -} - -template -void* createAppData() { - return new T(); -} - -template -void destroyAppData(void* appData) { - auto* app = static_cast(appData); - delete app; -} - -template -void registerApp() { - tt_app_register((AppRegistration) { - .createData = createAppData, - .destroyData = destroyAppData, - .onCreate = onAppCreate, - .onDestroy = onAppDestroy, - .onShow = onAppShow, - .onHide = onAppHide, - .onResult = onAppResult - }); -} diff --git a/Libraries/TactilityCpp/Include/TactilityCpp/LvglLock.h b/Libraries/TactilityCpp/Include/TactilityCpp/LvglLock.h deleted file mode 100644 index 05d7b1a..0000000 --- a/Libraries/TactilityCpp/Include/TactilityCpp/LvglLock.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -class LvglLock final : public tt::Lock { - -public: - - using tt::Lock::lock; - - bool lock(TickType_t timeout) const override { - return lvgl_try_lock(timeout); - } - - void unlock() const override { - lvgl_unlock(); - } -}; - - diff --git a/Libraries/TactilityCpp/Include/TactilityCpp/Preferences.h b/Libraries/TactilityCpp/Include/TactilityCpp/Preferences.h deleted file mode 100644 index 7752baa..0000000 --- a/Libraries/TactilityCpp/Include/TactilityCpp/Preferences.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class Preferences { - - PreferencesHandle handle = nullptr; - -public: - // Open preferences with the given identifier/namespace - explicit Preferences(const char* identifier) : handle(tt_preferences_alloc(identifier)) {} - - // Non-copyable (owns a handle) - Preferences(const Preferences&) = delete; - Preferences& operator=(const Preferences&) = delete; - - // Movable - Preferences(Preferences&& other) noexcept : handle(other.handle) { - other.handle = nullptr; - } - - Preferences& operator=(Preferences&& other) noexcept { - if (this != &other) { - if (handle) { - tt_preferences_free(handle); - } - handle = other.handle; - other.handle = nullptr; - } - return *this; - } - - ~Preferences() { - if (handle) { - tt_preferences_free(handle); - } - } - - bool optBool(const char* key, bool& out) const { - return tt_preferences_opt_bool(handle, key, &out); - } - - bool getBool(const char* key, bool defaultValue = false) const { - bool value = defaultValue; - (void) tt_preferences_opt_bool(handle, key, &value); - return value; - } - - void putBool(const char* key, bool value) const { - tt_preferences_put_bool(handle, key, value); - } - - bool optInt32(const char* key, int32_t& out) const { - return tt_preferences_opt_int32(handle, key, &out); - } - - int32_t getInt32(const char* key, int32_t defaultValue = 0) const { - int32_t value = defaultValue; - (void) tt_preferences_opt_int32(handle, key, &value); - return value; - } - - void putInt32(const char* key, int32_t value) const { - tt_preferences_put_int32(handle, key, value); - } - - bool optString(const char* key, char* out, uint32_t outSize) const { - return tt_preferences_opt_string(handle, key, out, outSize); - } - - template - bool optString(const char* key, char (&out)[N]) const { - return tt_preferences_opt_string(handle, key, out, static_cast(N)); - } - - std::string getString(const char* key, size_t maxSize, const std::string& defaultValue = std::string()) const { - if (maxSize == 0) return defaultValue; - std::string buf; - buf.resize(maxSize); - if (tt_preferences_opt_string(handle, key, buf.data(), static_cast(maxSize))) { - buf.resize(std::strlen(buf.c_str())); - return buf; - } - return defaultValue; - } - - void putString(const char* key, const char* value) const { - tt_preferences_put_string(handle, key, value); - } - void putString(const char* key, const std::string& value) const { - tt_preferences_put_string(handle, key, value.c_str()); - } -}; - diff --git a/Libraries/TactilityCpp/Include/TactilityCpp/Uart.h b/Libraries/TactilityCpp/Include/TactilityCpp/Uart.h deleted file mode 100644 index c2a39b7..0000000 --- a/Libraries/TactilityCpp/Include/TactilityCpp/Uart.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class Uart { - UartHandle handle; - -public: - - explicit Uart(UartHandle handle) : handle(handle) {} - - ~Uart() { - tt_hal_uart_free(handle); - } - - static std::unique_ptr open(size_t index) { - auto handle = tt_hal_uart_alloc(index); - return std::make_unique(handle); - } - - static std::vector getNames() { - std::vector names; - size_t count = tt_hal_uart_get_count(); - for (size_t i = 0; i < count; i++) { - char buffer[64]; - if (tt_hal_uart_get_name(i, buffer, sizeof(buffer))) { - names.push_back(std::string(buffer)); - } - } - return names; - } - - bool start() const { - return tt_hal_uart_start(handle); - } - - bool isStarted() const { - return tt_hal_uart_is_started(handle); - } - - bool stop() const { - return tt_hal_uart_stop(handle); - } - - size_t readBytes(char* buffer, size_t bufferSize, TickType_t timeout) const { - return tt_hal_uart_read_bytes(handle, buffer, bufferSize, timeout); - } - - bool readByte(char* output, TickType_t timeout) const { - return tt_hal_uart_read_bytes(handle, output, 1, timeout); - } - - size_t writeBytes(const char* buffer, size_t bufferSize, TickType_t timeout) const { - return tt_hal_uart_write_bytes(handle, buffer, bufferSize, timeout); - } - - size_t available() const { - return tt_hal_uart_available(handle); - } - - bool setBaudRate(size_t baud_rate) const { - return tt_hal_uart_set_baud_rate(handle, baud_rate); - } - - uint32_t getBaudRate() const { - return tt_hal_uart_get_baud_rate(handle); - } - - void flushInput() const { - tt_hal_uart_flush_input(handle); - } -}; diff --git a/Libraries/TactilityCpp/LICENSE.md b/Libraries/TactilityCpp/LICENSE.md deleted file mode 100644 index f5f4b8b..0000000 --- a/Libraries/TactilityCpp/LICENSE.md +++ /dev/null @@ -1,195 +0,0 @@ -Apache License -============== - -_Version 2.0, January 2004_ -_<>_ - -### Terms and Conditions for use, reproduction, and distribution - -#### 1. Definitions - -“License” shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -“Licensor” shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -“Legal Entity” shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, “control” means **(i)** the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the -outstanding shares, or **(iii)** beneficial ownership of such entity. - -“You” (or “Your”) shall mean an individual or Legal Entity exercising -permissions granted by this License. - -“Source” form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -“Object” form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -“Work” shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -“Derivative Works” shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -“Contribution” shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -“submitted” means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as “Not a Contribution.” - -“Contributor” shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -#### 2. Grant of Copyright License - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -#### 3. Grant of Patent License - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -#### 4. Redistribution - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -* **(a)** You must give any other recipients of the Work or Derivative Works a copy of -this License; and -* **(b)** You must cause any modified files to carry prominent notices stating that You -changed the files; and -* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -#### 5. Submission of Contributions - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -#### 6. Trademarks - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -#### 7. Disclaimer of Warranty - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -#### 8. Limitation of Liability - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -#### 9. Accepting Warranty or Additional Liability - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -_END OF TERMS AND CONDITIONS_ - -### APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets `[]` replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same “printed page” as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/Libraries/TactilityCpp/README.md b/Libraries/TactilityCpp/README.md deleted file mode 100644 index dd9385e..0000000 --- a/Libraries/TactilityCpp/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# TactilityCpp - -TactilityCpp is a wrapper around TactilityC. - -It's licensed with [Apache License Version 2.0](LICENSE.md).