Feature additions (#434)
Lots of things "ported" over from the "enhanced" fork. With some adjustments here and there. KeyboardBacklight driver (for T-Deck only currently) Trackball driver (for T-Deck only currently) Keyboard backlight sleep/wake (for T-Deck only currently...also requires keyboard firmware update) Display sleep/wake Files - create file/folder Keyboard settings (for T-Deck only currently) Time & Date settings tweaks Locale settings tweaks Systeminfo additions Espnow wifi coexist initI2cDevices - moved to T-deck init.cpp / initBoot KeyboardInitService - removed, moved to T-deck init.cpp / initBoot Adjusted TIMER_UPDATE_INTERVAL to 2 seconds. Added lock to ActionCreateFolder Maybe missed some things in the list. Display wake could do with some kind of block on wake first touch to prevent UI elements being hit when waking device with touch. Same with encoder/trackball/keyboard press i guess. The original code was written by @cscott0108 at https://github.com/cscott0108/tactility-enhanced-t-deck
This commit is contained in:
@@ -15,7 +15,9 @@
|
||||
#include <Tactility/StringUtils.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <Tactility/file/FileLock.h>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
@@ -62,6 +64,16 @@ static void onNavigateUpPressedCallback(TT_UNUSED lv_event_t* event) {
|
||||
view->onNavigateUpPressed();
|
||||
}
|
||||
|
||||
static void onNewFilePressedCallback(lv_event_t* event) {
|
||||
auto* view = static_cast<View*>(lv_event_get_user_data(event));
|
||||
view->onNewFilePressed();
|
||||
}
|
||||
|
||||
static void onNewFolderPressedCallback(lv_event_t* event) {
|
||||
auto* view = static_cast<View*>(lv_event_get_user_data(event));
|
||||
view->onNewFolderPressed();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
void View::viewFile(const std::string& path, const std::string& filename) {
|
||||
@@ -179,7 +191,38 @@ void View::createDirEntryWidget(lv_obj_t* list, dirent& dir_entry) {
|
||||
} else {
|
||||
symbol = LV_SYMBOL_FILE;
|
||||
}
|
||||
lv_obj_t* button = lv_list_add_button(list, symbol, dir_entry.d_name);
|
||||
|
||||
// Get file size for regular files
|
||||
std::string label_text = dir_entry.d_name;
|
||||
if (dir_entry.d_type == file::TT_DT_REG) {
|
||||
std::string file_path = file::getChildPath(state->getCurrentPath(), dir_entry.d_name);
|
||||
struct stat st;
|
||||
if (stat(file_path.c_str(), &st) == 0) {
|
||||
// Format file size in human-readable format
|
||||
const char* size_suffix;
|
||||
double size;
|
||||
if (st.st_size < 1024) {
|
||||
size = st.st_size;
|
||||
size_suffix = " B";
|
||||
} else if (st.st_size < 1024 * 1024) {
|
||||
size = st.st_size / 1024.0;
|
||||
size_suffix = " KB";
|
||||
} else {
|
||||
size = st.st_size / (1024.0 * 1024.0);
|
||||
size_suffix = " MB";
|
||||
}
|
||||
|
||||
char size_str[32];
|
||||
if (st.st_size < 1024) {
|
||||
snprintf(size_str, sizeof(size_str), " (%d%s)", (int)size, size_suffix);
|
||||
} else {
|
||||
snprintf(size_str, sizeof(size_str), " (%.1f%s)", size, size_suffix);
|
||||
}
|
||||
label_text += size_str;
|
||||
}
|
||||
}
|
||||
|
||||
lv_obj_t* button = lv_list_add_button(list, symbol, label_text.c_str());
|
||||
lv_obj_add_event_cb(button, &onDirEntryPressedCallback, LV_EVENT_SHORT_CLICKED, this);
|
||||
lv_obj_add_event_cb(button, &onDirEntryLongPressedCallback, LV_EVENT_LONG_PRESSED, this);
|
||||
}
|
||||
@@ -212,6 +255,18 @@ void View::onDeletePressed() {
|
||||
alertdialog::start("Are you sure?", message, choices);
|
||||
}
|
||||
|
||||
void View::onNewFilePressed() {
|
||||
TT_LOG_I(TAG, "Creating new file");
|
||||
state->setPendingAction(State::ActionCreateFile);
|
||||
inputdialog::start("New File", "Enter filename:", "");
|
||||
}
|
||||
|
||||
void View::onNewFolderPressed() {
|
||||
TT_LOG_I(TAG, "Creating new folder");
|
||||
state->setPendingAction(State::ActionCreateFolder);
|
||||
inputdialog::start("New Folder", "Enter folder name:", "");
|
||||
}
|
||||
|
||||
void View::showActionsForDirectory() {
|
||||
lv_obj_clean(action_list);
|
||||
|
||||
@@ -262,6 +317,8 @@ void View::init(const AppContext& appContext, lv_obj_t* parent) {
|
||||
|
||||
auto* toolbar = lvgl::toolbar_create(parent, appContext);
|
||||
navigate_up_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressedCallback, this);
|
||||
new_file_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_FILE, &onNewFilePressedCallback, this);
|
||||
new_folder_button = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_DIRECTORY, &onNewFolderPressedCallback, this);
|
||||
|
||||
auto* wrapper = lv_obj_create(parent);
|
||||
lv_obj_set_width(wrapper, LV_PCT(100));
|
||||
@@ -354,6 +411,62 @@ void View::onResult(LaunchId launchId, Result result, std::unique_ptr<Bundle> bu
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::ActionCreateFile: {
|
||||
auto filename = inputdialog::getResult(*bundle);
|
||||
if (!filename.empty()) {
|
||||
std::string new_file_path = file::getChildPath(state->getCurrentPath(), filename);
|
||||
|
||||
auto lock = file::getLock(new_file_path);
|
||||
lock->lock();
|
||||
|
||||
struct stat st;
|
||||
if (stat(new_file_path.c_str(), &st) == 0) {
|
||||
TT_LOG_W(TAG, "File already exists: \"%s\"", new_file_path.c_str());
|
||||
lock->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
FILE* new_file = fopen(new_file_path.c_str(), "w");
|
||||
if (new_file) {
|
||||
fclose(new_file);
|
||||
TT_LOG_I(TAG, "Created file \"%s\"", new_file_path.c_str());
|
||||
} else {
|
||||
TT_LOG_E(TAG, "Failed to create file \"%s\"", new_file_path.c_str());
|
||||
}
|
||||
lock->unlock();
|
||||
|
||||
state->setEntriesForPath(state->getCurrentPath());
|
||||
update();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::ActionCreateFolder: {
|
||||
auto foldername = inputdialog::getResult(*bundle);
|
||||
if (!foldername.empty()) {
|
||||
std::string new_folder_path = file::getChildPath(state->getCurrentPath(), foldername);
|
||||
|
||||
auto lock = file::getLock(new_folder_path);
|
||||
lock->lock();
|
||||
|
||||
struct stat st;
|
||||
if (stat(new_folder_path.c_str(), &st) == 0) {
|
||||
TT_LOG_W(TAG, "Folder already exists: \"%s\"", new_folder_path.c_str());
|
||||
lock->unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
if (mkdir(new_folder_path.c_str(), 0755) == 0) {
|
||||
TT_LOG_I(TAG, "Created folder \"%s\"", new_folder_path.c_str());
|
||||
} else {
|
||||
TT_LOG_E(TAG, "Failed to create folder \"%s\"", new_folder_path.c_str());
|
||||
}
|
||||
lock->unlock();
|
||||
|
||||
state->setEntriesForPath(state->getCurrentPath());
|
||||
update();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user