Implemented LaunchId and FileSelection, updated Notes (#281)
- Implemented `LaunchId` to keep track of the apps that are started - Implemented `FileSelection` app to select existing and/or new files. - Moved some re-usable file functionality to `tt::file::` - Renamed `Files` app to `FileBrowser` - Updated `Notes` app to use new `FileSelection` functionality, and cleaned it up a bit. - General code cleanliness improvements
This commit is contained in:
committed by
GitHub
parent
74eb830870
commit
2691dbb014
@@ -3,10 +3,34 @@
|
||||
#include "Tactility/TactilityCore.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
|
||||
namespace tt::file {
|
||||
|
||||
/** File types for `dirent`'s `d_type`. */
|
||||
enum {
|
||||
TT_DT_UNKNOWN = 0,
|
||||
#define TT_DT_UNKNOWN TT_DT_UNKNOWN // Unknown type
|
||||
TT_DT_FIFO = 1,
|
||||
#define TT_DT_FIFO TT_DT_FIFO // Named pipe or FIFO
|
||||
TT_DT_CHR = 2,
|
||||
#define TT_DT_CHR TT_DT_CHR // Character device
|
||||
TT_DT_DIR = 4,
|
||||
#define TT_DT_DIR TT_DT_DIR // Directory
|
||||
TT_DT_BLK = 6,
|
||||
#define TT_DT_BLK TT_DT_BLK // Block device
|
||||
TT_DT_REG = 8,
|
||||
#define TT_DT_REG TT_DT_REG // Regular file
|
||||
TT_DT_LNK = 10,
|
||||
#define TT_DT_LNK TT_DT_LNK // Symbolic link
|
||||
TT_DT_SOCK = 12,
|
||||
#define TT_DT_SOCK TT_DT_SOCK // Local-domain socket
|
||||
TT_DT_WHT = 14
|
||||
#define TT_DT_WHT TT_DT_WHT // Whiteout inodes
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr char SEPARATOR = '\\';
|
||||
#else
|
||||
@@ -36,6 +60,13 @@ std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSi
|
||||
*/
|
||||
std::unique_ptr<uint8_t[]> readString(const std::string& filepath);
|
||||
|
||||
/** Write text to a file
|
||||
* @param[in] path file path to write to
|
||||
* @param[in] content file content to write
|
||||
* @return true when operation is successful
|
||||
*/
|
||||
bool writeString(const std::string& filepath, const std::string& content);
|
||||
|
||||
/** Ensure a directory path exists.
|
||||
* @param[in] path the directory path to find, or to create recursively
|
||||
* @param[in] mode the mode to use when creating directories
|
||||
@@ -43,4 +74,41 @@ std::unique_ptr<uint8_t[]> readString(const std::string& filepath);
|
||||
*/
|
||||
bool findOrCreateDirectory(std::string path, mode_t mode);
|
||||
|
||||
/**
|
||||
* Concatenate a child path with a parent path, ensuring proper slash inbetween
|
||||
* @param basePath an absolute path with or without trailing "/"
|
||||
* @param childPath the name of the child path (e.g. subfolder or file)
|
||||
* @return the concatenated path
|
||||
*/
|
||||
std::string getChildPath(const std::string& basePath, const std::string& childPath);
|
||||
|
||||
typedef int (*ScandirFilter)(const dirent*);
|
||||
|
||||
typedef bool (*ScandirSort)(const dirent&, const dirent&);
|
||||
|
||||
/** Used for sorting by alphanumeric value and file type */
|
||||
bool direntSortAlphaAndType(const dirent& left, const dirent& right);
|
||||
|
||||
/** A filter for filtering out "." and ".." */
|
||||
int direntFilterDotEntries(const dirent* entry);
|
||||
|
||||
/**
|
||||
* A scandir()-like implementation that works on ESP32.
|
||||
* It does not return "." and ".." items but otherwise functions the same.
|
||||
* It returns an allocated output array with allocated dirent instances.
|
||||
* The caller is responsible for free-ing the memory of these.
|
||||
*
|
||||
* @param[in] path path the scan for files and directories
|
||||
* @param[out] outList a pointer to vector of dirent
|
||||
* @param[in] filter an optional filter to filter out specific items
|
||||
* @param[in] sort an optional sorting function
|
||||
* @return the amount of items that were stored in "output" or -1 when an error occurred
|
||||
*/
|
||||
int scandir(
|
||||
const std::string& path,
|
||||
std::vector<dirent>& outList,
|
||||
ScandirFilter _Nullable filter,
|
||||
ScandirSort _Nullable sort
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,66 @@
|
||||
#include "Tactility/file/File.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
namespace tt::file {
|
||||
|
||||
#define TAG "file"
|
||||
|
||||
std::string getChildPath(const std::string& basePath, const std::string& childPath) {
|
||||
// Postfix with "/" when the current path isn't "/"
|
||||
if (basePath.length() != 1) {
|
||||
return basePath + "/" + childPath;
|
||||
} else {
|
||||
return "/" + childPath;
|
||||
}
|
||||
}
|
||||
|
||||
int direntFilterDotEntries(const dirent* entry) {
|
||||
return (strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, ".") == 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
bool direntSortAlphaAndType(const dirent& left, const dirent& right) {
|
||||
bool left_is_dir = left.d_type == TT_DT_DIR || left.d_type == TT_DT_CHR;
|
||||
bool right_is_dir = right.d_type == TT_DT_DIR || right.d_type == TT_DT_CHR;
|
||||
if (left_is_dir == right_is_dir) {
|
||||
return strcmp(left.d_name, right.d_name) < 0;
|
||||
} else {
|
||||
return left_is_dir > right_is_dir;
|
||||
}
|
||||
}
|
||||
|
||||
int scandir(
|
||||
const std::string& path,
|
||||
std::vector<dirent>& outList,
|
||||
ScandirFilter _Nullable filterMethod,
|
||||
ScandirSort _Nullable sortMethod
|
||||
) {
|
||||
TT_LOG_I(TAG, "scandir start");
|
||||
DIR* dir = opendir(path.c_str());
|
||||
if (dir == nullptr) {
|
||||
TT_LOG_E(TAG, "Failed to open dir %s", path.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
dirent* current_entry;
|
||||
while ((current_entry = readdir(dir)) != nullptr) {
|
||||
if (filterMethod(current_entry) == 0) {
|
||||
outList.push_back(*current_entry);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (sortMethod != nullptr) {
|
||||
std::ranges::sort(outList, sortMethod);
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "scandir finish");
|
||||
return outList.size();
|
||||
}
|
||||
|
||||
|
||||
long getSize(FILE* file) {
|
||||
long original_offset = ftell(file);
|
||||
|
||||
@@ -80,12 +137,25 @@ std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSi
|
||||
std::unique_ptr<uint8_t[]> readString(const std::string& filepath) {
|
||||
size_t size = 0;
|
||||
auto data = readBinaryInternal(filepath, size, 1);
|
||||
if (data != nullptr) {
|
||||
data.get()[size] = 0; // Append null terminator
|
||||
return data;
|
||||
} else {
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data.get()[size] = 0; // Append null terminator
|
||||
return data;
|
||||
}
|
||||
|
||||
bool writeString(const std::string& filepath, const std::string& content) {
|
||||
std::ofstream fileStream(filepath);
|
||||
|
||||
if (!fileStream.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fileStream << content;
|
||||
fileStream.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool findOrCreateDirectoryInternal(std::string path, mode_t mode) {
|
||||
|
||||
Reference in New Issue
Block a user