Cause: any answer other than y was treated as no, so your t discarded the changes. Fix: the prompt now only accepts y (save), n (discard) or c (cancel the exit). Anything else asks again, so a typo can't lose data. In my test, t, an empty line, then y saved correctly. Also: I changed the db restore confirmation to y/n only, with no cancel option. Closing stdin still saves automatically. Wait without a time tsk restat <task> wait: works with no time while the task's account is still waiting, and the task just follows that wait. tsk add <task> <acc> wait works the same way. Time required: otherwise it asks for one, with a message saying why. That covers an account that isn't waiting, an account whose wait is already over (Limit reset), and a task with no account. acc wait: it still requires a time. A plain acc wait would have nothing to do, since the account already has a wait. Account panel: there's a new RESET column showing when the account's wait ends. It shows 16:30 for today, tomorrow 06:40 for the next day, or a full date like 2020-01-01 10:00 (which is how an old, already-reset wait appears). Accounts with no wait show -. Since the time is in its own column now, an account with a wait but no task showing it lists just (wait) or (limit reset) in the TASKS column.
59 lines
2.4 KiB
C++
59 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <ctime>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Prompt: free to accept prompts.
|
|
// LimitReset: computed - a Wait whose time has passed (can also be set by hand).
|
|
enum class StatusKind { Prompt, LimitReset, Testing, Wait, Uploading, Frozen, Done };
|
|
|
|
struct Status {
|
|
StatusKind kind = StatusKind::Prompt;
|
|
std::time_t waitUntil = 0; // when the wait ends; set for Wait, and kept on the computed LimitReset
|
|
};
|
|
|
|
namespace StatusUtil {
|
|
|
|
Status make(StatusKind kind);
|
|
|
|
// User input such as "testing" or "wait 16:30". A wait time that has already
|
|
// passed today is taken to mean tomorrow.
|
|
std::optional<Status> parse(const std::string& text, std::time_t now);
|
|
|
|
// Database representation, e.g. "testing" or "wait 2026-10-17T16:30".
|
|
std::string serialize(const Status& status);
|
|
std::optional<Status> deserialize(const std::string& text);
|
|
|
|
// Prompt and Testing tasks follow their account's wait; Uploading, Frozen and
|
|
// Done tasks do not.
|
|
bool followsAccountWait(StatusKind kind);
|
|
|
|
// The status to show for a task. If its account has a wait, the tasks that
|
|
// follow it show Wait until then and Limit reset after; otherwise the stored
|
|
// status is used (see effective).
|
|
Status resolve(const Status& stored, const std::optional<std::time_t>& accountWait, std::time_t now);
|
|
|
|
// The status shown to the user: an expired wait becomes LimitReset.
|
|
Status effective(const Status& status, std::time_t now);
|
|
|
|
// Times kept outside a Status (an account's cooldown): "2026-10-17T16:30".
|
|
std::string timeToText(std::time_t value);
|
|
std::optional<std::time_t> timeFromText(const std::string& text);
|
|
std::string clockLabel(std::time_t value); // "16:30"
|
|
// "16:30" for today, "tomorrow 06:40" for the next day, otherwise "2026-10-26 16:30".
|
|
std::string resetLabel(std::time_t value, std::time_t now);
|
|
|
|
std::string label(const Status& status); // "Prompt", "Limit reset", "Wait 16:30", ...
|
|
std::string kindName(StatusKind kind); // lowercase token: "prompt", "limit-reset", ...
|
|
std::vector<StatusKind> allKinds();
|
|
// Accepts "limit-reset", "limit_reset", "limitreset", "reset"; "available" is an
|
|
// old name for "prompt".
|
|
std::optional<StatusKind> kindFromName(const std::string& name);
|
|
int rank(StatusKind kind); // task sort priority, lowest first
|
|
bool isBusy(StatusKind kind); // keeps its account Busy: Testing, Limit reset, Wait
|
|
bool isTaken(StatusKind kind); // keeps its account Taken: Prompt
|
|
|
|
} // namespace StatusUtil
|