M1 step 3: Log writing and Storage Clean-up

- lib/storage_model (host-tested): FAT-safe names, daily Log paths,
  dates from Log/Capture file names, CleanupPlan by category and age,
  byte formatting
- StorageService does all card I/O on its task: queued Log lines are
  written in batches each second (dropped while Logs are paused),
  plus file listing and deletion jobs
- Settings > Storage moves into StoragePage: usage, Clean up
  (category, age with size preview, confirmation), Erase SD card
- Clock: local date for Log names
- Serial: log <text>, sd list

Verified on the device: lines land in /irc/dev/#test/2026-10-02.log
with folders created as needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-02 14:56:06 +02:00
co-authored by Claude Opus 5.5
parent 1a0baf4ac7
commit d3948ccc3a
18 changed files with 785 additions and 74 deletions
+53
View File
@@ -0,0 +1,53 @@
#include "cleanup_plan.h"
#include <cstdio>
#include "storage_paths.h"
namespace roro {
namespace {
int maxAgeDays(CleanupAge age) {
switch (age) {
case CleanupAge::OneMonth: return 30;
case CleanupAge::ThreeMonths: return 91;
case CleanupAge::SixMonths: return 182;
case CleanupAge::OneYear: return 365;
default: return -1;
}
}
} // namespace
CleanupPlan CleanupPlan::make(const std::vector<StoredFile>& files, CleanupAge age, int todayDay) {
CleanupPlan plan;
for (auto& f : files) {
if (f.path.rfind("/notes", 0) == 0) continue; // Notes are never cleaned up
bool selected = age == CleanupAge::Everything;
if (!selected) {
size_t slash = f.path.find_last_of('/');
int day = storage::fileDay(slash == std::string::npos ? f.path : f.path.substr(slash + 1));
selected = day >= 0 && todayDay - day > maxAgeDays(age);
}
if (selected) {
plan.paths.push_back(f.path);
plan.bytes += f.bytes;
}
}
return plan;
}
std::string formatBytes(uint64_t bytes) {
const char* units[] = {"B", "KB", "MB", "GB"};
double v = static_cast<double>(bytes);
int u = 0;
while (v >= 1024 && u < 3) {
v /= 1024;
u++;
}
char buf[16];
if (u == 0 || v >= 10) std::snprintf(buf, sizeof(buf), "%.0f %s", v, units[u]);
else std::snprintf(buf, sizeof(buf), "%.1f %s", v, units[u]);
return buf;
}
} // namespace roro