diff options
| -rw-r--r-- | main.c | 64 | ||||
| -rw-r--r-- | readme.md | 21 |
2 files changed, 65 insertions, 20 deletions
@@ -82,6 +82,10 @@ char *string_buffer = NULL; size_t string_buffer_size = 0; int size_x, size_y, pos_x, pos_y; +void inline static clear_string_buffer() { + memset(string_buffer, 0, string_buffer_size); +} + // Checks if file is exists and is accessible. // Returns true when the file exists and is accessible. @@ -527,6 +531,33 @@ bool store_database(const database_st *db, const char *path) { return true; } +// Writes only the database core structure and the provided task if not null. +// Returns success. +bool store_database_partial(const database_st *db, const task_st *task, const char *path) { + assert(db != NULL); + assert(path != NULL); + + // Open file. + FILE *file = fopen(path, "r+b"); + if (file == NULL) { + fprintf(stderr, "Failed to open file '%s' while partially storing database: %s.\n", path, strerror(errno)); + return false; + } + + fseek(file, DB_FILE_SIGN_LENGTH, SEEK_SET); + fwrite(db, SIZEOF_DATABASE_ST, 1, file); + + if (task != NULL) { + assert(task >= db->tasks && task < &db->tasks[db->count]); + ptrdiff_t offset = task - db->tasks; + fseek(file, offset * SIZEOF_TASK_ST, SEEK_CUR); + fwrite(task, SIZEOF_TASK_ST, 1, file); + } + + fclose(file); + return true; +} + // Loads data from binary file into database. // Returns success. bool load_database(database_st *db, const char *path) { @@ -751,7 +782,7 @@ typedef struct { layout_st layouts[NUM_LAYOUTS]; int layout_tasks_rows; -bool is_valid_window = false; +bool is_terminal_too_small = true; void initialize_tui() { @@ -1151,7 +1182,7 @@ int main(int argc, char *argv[]) { static layout_st *layout = &layouts[L_COMPACT]; task_st *active_task = get_active_task(db); task_st *selected_task = get_selected_task(db); - int selected_task_row = is_valid_window ? (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS : 0; + int selected_task_row = is_terminal_too_small ? 0 : (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS; int selected_task_theme = selected_task == active_task ? THEME_E : THEME_D; timeout(INPUT_AWAIT_INF); @@ -1168,7 +1199,7 @@ int main(int argc, char *argv[]) { case KEY_RESIZE: { clear(); getmaxyx(stdscr, size_y, size_x); - is_valid_window = size_x >= 60 && size_y >= 3; + is_terminal_too_small = size_x < 60 || size_y < 3; size_t new_size = 2047 | MAX_TASK_NAME | (size_x + 1); if (string_buffer_size < new_size) { string_buffer_size = new_size; @@ -1193,10 +1224,13 @@ int main(int argc, char *argv[]) { struct tm *now_local = localtime(&now_utc); strftime(new_task->name, MAX_TASK_NAME, "%Y-%m-%d %H:%M:%S", now_local); - // Select new task. + // Select new task. TODO Maybe do this on the database? selected_task = new_task; db->selected_task = selected_task - db->tasks; - + + // TODO + store_database_partial(db, selected_task, db_file_path); + // Force rename action. flushinp(); ungetch(KEY_F(2)); @@ -1216,6 +1250,8 @@ int main(int argc, char *argv[]) { // Get new task name. echo(); curs_set(1); + clear_string_buffer(); +// memset(string_buffer, 0, string_buffer_size); TODO mvgetnstr(selected_task_row, 1, string_buffer, MAX_TASK_NAME-1); noecho(); curs_set(0); @@ -1233,7 +1269,7 @@ int main(int argc, char *argv[]) { break; } - case '0': { + case KEY_BACKSPACE: { if (selected_task == NULL) { break; } @@ -1361,6 +1397,7 @@ int main(int argc, char *argv[]) { // Adust time. set_task_time(db, selected_task, day, time); + store_database_partial(db, selected_task, db_file_path); break; } @@ -1592,20 +1629,25 @@ int main(int argc, char *argv[]) { } } - if (is_valid_window) { - draw_tui(db, layout); - } - else { - const char *INVALID_WINDOW_MESSAGE = "Please expand window."; + if (is_terminal_too_small) { + const char *INVALID_WINDOW_MESSAGE = "Terminal is too small: minimum 60x3."; const int INVALID_WINDOW_MESSAGE_LENGTH = strlen(INVALID_WINDOW_MESSAGE); mvaddstr(size_y / 2, (size_x - INVALID_WINDOW_MESSAGE_LENGTH) / 2, INVALID_WINDOW_MESSAGE); } + else { + draw_tui(db, layout); + } timeout(INPUT_TIMEOUT_MS); } update_times(&database); store_database(&database, db_file_path); +// task_st *active_task = get_active_task(&database); +// if (active_task != NULL) { +// update_times(&database); +// store_database_partial(&database, active_task, db_file_path); +// } if (db == &archive) { export_to_csv(&archive, ar_file_path); } @@ -5,6 +5,7 @@ Task Time Tracker - [ncurses colors](https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/color.html#COLORBASICS) - [pprintf](https://cplusplus.com/reference/cstdio/printf/) - [intmax_t](https://wiki.sei.cmu.edu/confluence/plugins/servlet/mobile?contentId=87152366#content/view/87152366) +- [hexed.it](https://hexed.it/) # to-do list - [x] Include check on number of char bits; @@ -51,18 +52,20 @@ Task Time Tracker - [x] Add/remove time using keys: `F3`; - [x] Add/remove time for any day of week; - [x] Total times may saturate, but before that the user will see the infinite symbol. Solution: Provide user with possibility to refresh totals. -- [ ] Improve the way we save the changes made to the database: +- [x] Decide on a INVALID_WINDOW_MESSAGE. +- [x] Use backspace to clear all timers for current task. +- [ ] Save more often using the `store_database_partial` and only save all when quitting: - When operating on the archive, will we keep the saves synchronous? - Maybe add a cooldown timer and save changes after it times out? - Maybe add a partial-save when (de)activating a task (just save the task and the database core? - - partial_store_task(db, task) - - partial_store_database(db) - - on (de)activate_task : partial_store_database partial_store_database - - on rename, changetimes : partial_store_task - - on new_task : partial_store_database partial_store_task - - on refresh : partial_store_database - - on exit if active : partial_store_database partial_store_task - - on move, delete, archive: FULL store_database + - on (de)activate_task : partial w/task + - on rename, changetimes : partial w/task + - on new_task : partial w/task + - on refresh : partial + - on exit : full + - on move, delete, archive: full +- [ ] Check if string_buffer needs to be cleared. We may be leaking info on the string_buffer. +- [ ] Maybe replace all `sprintf` by `snprintf`; - [ ] REVISE ALL CODE ptrdiff_t/size_t (signed/unsigned)! - [ ] Go over all `TODO` items; - [ ] Cleanup `draw_tui`: |
