aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2022-09-03 16:53:43 +0000
committerdam <dam@gudinoff>2022-09-03 16:53:43 +0000
commitcd2247bf832a1f210192afa3dc68cd226ae3aa02 (patch)
treec89ceac11b5c1f916049e85546173d2124b2ffff
parentd8920087a81ef9490037028863d998e9b53989d4 (diff)
downloadtask-time-tracker-cd2247bf832a1f210192afa3dc68cd226ae3aa02.tar.zst
task-time-tracker-cd2247bf832a1f210192afa3dc68cd226ae3aa02.zip
Keep track of time for active task.
-rw-r--r--main.c213
1 files changed, 139 insertions, 74 deletions
diff --git a/main.c b/main.c
index 6181d7a..11768fa 100644
--- a/main.c
+++ b/main.c
@@ -27,12 +27,12 @@
#define DB_MAX_CAP ((PTRDIFF_MAX >> 1) + 1)
typedef struct /*__attribute__((__packed__))*/ {
- uint32_t time[7];
+ uint32_t times[7];
char name[MAX_TASK_NAME];
} task_t;
typedef struct /*__attribute__((__packed__))*/ {
- uint64_t modified_on;
+ time_t modified_on;
size_t count;
size_t capacity;
task_t *tasks;
@@ -83,13 +83,13 @@ char *replace_char(char *string, char find, char replace) {
void print_task(const task_t *task) {
printf("name: '%s'\n", task->name);
- printf("t[0]: '%" PRIu32 "'\n", task->time[0]);
- printf("t[1]: '%" PRIu32 "'\n", task->time[1]);
- printf("t[2]: '%" PRIu32 "'\n", task->time[2]);
- printf("t[3]: '%" PRIu32 "'\n", task->time[3]);
- printf("t[4]: '%" PRIu32 "'\n", task->time[4]);
- printf("t[5]: '%" PRIu32 "'\n", task->time[5]);
- printf("t[6]: '%" PRIu32 "'\n", task->time[6]);
+ printf("t[0]: '%" PRIu32 "'\n", task->times[0]);
+ printf("t[1]: '%" PRIu32 "'\n", task->times[1]);
+ printf("t[2]: '%" PRIu32 "'\n", task->times[2]);
+ printf("t[3]: '%" PRIu32 "'\n", task->times[3]);
+ printf("t[4]: '%" PRIu32 "'\n", task->times[4]);
+ printf("t[5]: '%" PRIu32 "'\n", task->times[5]);
+ printf("t[6]: '%" PRIu32 "'\n", task->times[6]);
}
// Macro used to calculate index of task on a database.
@@ -272,13 +272,13 @@ bool export_to_csv(const database_t *db, const char *path_name) {
replace_char(name, ',', ' ');
fprintf(file, "%s,%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 "\n",
name,
- task->time[0],
- task->time[1],
- task->time[2],
- task->time[3],
- task->time[4],
- task->time[5],
- task->time[6]
+ task->times[0],
+ task->times[1],
+ task->times[2],
+ task->times[3],
+ task->times[4],
+ task->times[5],
+ task->times[6]
);
}
@@ -335,13 +335,13 @@ bool import_from_csv(database_t *db, const char *path_name) {
// Parse task times.
if(sscanf(name_delimiter+1,
"%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32,
- &task->time[0],
- &task->time[1],
- &task->time[2],
- &task->time[3],
- &task->time[4],
- &task->time[5],
- &task->time[6]
+ &task->times[0],
+ &task->times[1],
+ &task->times[2],
+ &task->times[3],
+ &task->times[4],
+ &task->times[5],
+ &task->times[6]
) != 7) {
replace_char(line_buffer, '\n', ' ');
fprintf(stderr, "Discarding invalid line '%s' and continuing.\n", line_buffer);
@@ -362,8 +362,8 @@ bool import_from_csv(database_t *db, const char *path_name) {
enum TEST {
T_NONE = 0x00,
- T_UTC = 0x01,
- T_DAY = 0x02,
+ T_TIME = 0x01,
+ T_XXXX = 0x02,
T_SBIN = 0x04,
T_LBIN = 0x08,
T_ECSV = 0x10,
@@ -377,21 +377,12 @@ void prototype(int level) {
const char *done = "# -- done -- -- -- /\n";
///////////////////////////////////////////////////////////////////////////
- // Get current UTC time.
- if (level & T_UTC) {
- fprintf(stderr, "# current UTC time --------------------------- \\\n");
- time_t x = time(NULL);
- printf("%s", ctime(&x));
- fprintf(stderr, done);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Get current day of the week.
- if (level & T_DAY) {
- fprintf(stderr, "# current day of the week --------------------- \\\n");
- time_t now_ut = time(NULL);
- uint8_t week_day = localtime(&now_ut)->tm_wday;
- fprintf(stderr, "%d\n", week_day);
+ // Get current time and day of week (UTC).
+ if (level & T_TIME) {
+ fprintf(stderr, "# UTC time and day of week -------------------- \\\n");
+ time_t now_utc = time(NULL); // Get current UTC time.
+ uint8_t week_day = localtime(&now_utc)->tm_wday; // Get current day of the week.
+ fprintf(stderr, "day of week: %d\ntime: %s", week_day, ctime(&now_utc));
fprintf(stderr, done);
}
@@ -401,15 +392,15 @@ void prototype(int level) {
task_t tmp[] = {
{
.name = "ALPHA-TASK",
- .time = { 0, 0, 0, 0, 0, 0, 0 },
+ .times = { 0, 0, 0, 0, 0, 0, 0 },
},
{
.name = "BETA-TASK",
- .time = { 1, 1, 1, 1, 1, 1, 1 },
+ .times = { 1, 1, 1, 1, 1, 1, 1 },
},
{
.name = "DELTA-TASK",
- .time = { 2, 2, 2, 2, 2, 2, 2 },
+ .times = { 2, 2, 2, 2, 2, 2, 2 },
}
};
@@ -485,11 +476,57 @@ void prototype(int level) {
size = sizeof(task_t);
fprintf(stderr, "sizeof(%s) = %zu bytes (%zu bits : %6.3f W64b)\n", name, size, size*8, ((double)size)*8.0/64.0);
+ name = "time_t";
+ size = sizeof(time_t);
+ fprintf(stderr, "sizeof(%s) = %zu bytes (%zu bits : %6.3f W64b)\n", name, size, size*8, ((double)size)*8.0/64.0);
+
+
fprintf(stderr, done);
}
}
+
+
+void update_timers(database_t *db) {
+
+ // Get current UTC time.
+ time_t stop_time = time(NULL);
+
+ // Get last modified on UTC time.
+ time_t start_time = db->modified_on;
+
+// time_t diff = (double)stop_time - start_time;
+// fprintf(stderr, "> diff: %zu seconds | %6.2f minutes | %6.2f hours\n", (time_t)diff, diff / 60.0, diff / (60.0*60.0));
+
+ if (db->active_task < 0) {
+ return;
+ }
+
+ task_t *active_task = db->tasks + db->active_task;
+ uint8_t start_week_day;
+ while (start_time < stop_time) {
+
+ start_week_day = localtime(&start_time)->tm_wday;
+
+ // Get next week of day.
+ time_t next_day = (start_time / 86400) * 86400 + 86400;
+ time_t next_start = next_day < stop_time ? next_day : stop_time;
+
+ active_task->times[start_week_day] += next_start - start_time;
+
+
+// fprintf(stderr, "Added '%zu' on %s\n", next_start - start_time, DAYS_OF_WEEK[start_week_day]);
+
+ start_time = next_start;
+ }
+
+ db->modified_on = stop_time;
+// fprintf(stderr, "> done\n");
+}
+
+
+
char *line_buffer;
int size_x, size_y, pos_x, pos_y;
uint8_t selected_layout = 0;
@@ -515,14 +552,14 @@ void initialize_layouts() {
layout->table_size = 8;
layout->table_headers_size = TABLE_HEADERS_SIZE;
// TODO Headers must be dynamic according to FIRST_DAY_OF_WEEK
- layout->table_headers[0] = " Task ";
- layout->table_headers[1] = " Mon ";
- layout->table_headers[2] = " Tue ";
- layout->table_headers[3] = " Wed ";
- layout->table_headers[4] = " Thu ";
- layout->table_headers[5] = " Fri ";
- layout->table_headers[6] = " Sat ";
- layout->table_headers[7] = " Sun ";
+ layout->table_headers[0] = " Task Time Tracker v1 ";
+ layout->table_headers[1] = " Sun ";
+ layout->table_headers[2] = " Mon ";
+ layout->table_headers[3] = " Tue ";
+ layout->table_headers[4] = " Wed ";
+ layout->table_headers[5] = " Thu ";
+ layout->table_headers[6] = " Fri ";
+ layout->table_headers[7] = " Sat ";
layout->table_headers[8] = " Total ";
// layout->table_headers = { " Task ", " Mon ", " Tue ", " Wed ", " Thu ", " Fri ", " Sat ", " Sun ", " Total " };
@@ -531,13 +568,13 @@ void initialize_layouts() {
layout->table_size = 6;
layout->table_headers_size = TABLE_HEADERS_SIZE;
// TODO Headers must be dynamic according to FIRST_DAY_OF_WEEK
- layout->table_headers[0] = " Task ";
- layout->table_headers[1] = " M ";
- layout->table_headers[2] = " T ";
- layout->table_headers[3] = " W ";
- layout->table_headers[4] = " T ";
- layout->table_headers[5] = " F ";
- layout->table_headers[6] = " S ";
+ layout->table_headers[0] = " TTT ";
+ layout->table_headers[1] = " S ";
+ layout->table_headers[2] = " M ";
+ layout->table_headers[3] = " T ";
+ layout->table_headers[4] = " W ";
+ layout->table_headers[5] = " T ";
+ layout->table_headers[6] = " F ";
layout->table_headers[7] = " S ";
layout->table_headers[8] = " # ";
// layout->table_headers = { " T ", " M ", " T ", " W ", " T ", " F ", " S ", " S ", " # " };
@@ -584,10 +621,30 @@ void draw_header() {
start_columns+(table_size*7),
};
+ time_t now = time(NULL);
+ uint8_t today = localtime(&now)->tm_wday + 1;
+
+ start_color();
+ init_pair(1, COLOR_BLUE, COLOR_BLACK);
+ init_pair(2, COLOR_BLACK, COLOR_CYAN);
+ init_pair(3, COLOR_WHITE, COLOR_BLUE);
+ int color_pair = 1;
+
+
+
mvaddstr(0, columns[0]+2, table_headers[0]);
- for (int idx = 1; idx < 9; idx++) {
+ for (int idx = 1; idx < 9; idx++) { // TODO When does the week start?
mvaddch(0, columns[idx], ACS_TTEE);
+
+ if (idx == today) {
+ attron(COLOR_PAIR(color_pair));
+ }
+
mvaddstr(0, columns[idx]+2, table_headers[idx]);
+
+ if (idx == today) {
+ attroff(COLOR_PAIR(color_pair));
+ }
}
}
@@ -646,10 +703,9 @@ void draw_table() {
if (task == active_task && task == selected_task) {
color_pair = 3;
}
- if (color_pair > 0) {
- attron(COLOR_PAIR(color_pair));
+ if (color_pair == 1 || color_pair == 3) {
+ attron(A_BOLD);
}
-
attron(COLOR_PAIR(color_pair));
// Clear line_buffer and add string termination.
@@ -662,7 +718,7 @@ void draw_table() {
size_t copy_length = task_name_length < max_column_length ? task_name_length : max_column_length;
memcpy(line_buffer+2, task->name, copy_length);
- uint32_t *time = task->time;
+ uint32_t *time = task->times;
sprintf(line_buffer + columns[1], "%8d", time[0]);
sprintf(line_buffer + columns[2], "%8d", time[1]);
sprintf(line_buffer + columns[3], "%8d", time[2]);
@@ -678,14 +734,13 @@ void draw_table() {
totals[idx] += time[idx];
}
totals[DAYS_ON_WEEK] += total;
- sprintf(line_buffer + columns[8], "%10" PRIu64, total);
+ sprintf(line_buffer + columns[8], "%10" PRIu64, total); // BUG This causes "corrupted size vs. prev_size because it is writing beyond line_buffer size.
addstr(line_buffer);
// Disable highlight color on selected entry.
- if (color_pair > 0) {
- attroff(COLOR_PAIR(color_pair));
- }
+ attroff(COLOR_PAIR(color_pair));
+ attroff(A_BOLD);
// Print columns separators.
pos_y = getcury(stdscr);
@@ -750,7 +805,6 @@ void draw_footer() {
addch(ACS_LRCORNER);
-
// TODO This code is now repeated accross the header, table and footer. Clean this up.
layout_t *layout = &layouts[selected_layout];
int table_size = layout->table_size;
@@ -782,7 +836,7 @@ int main(int argc, char *argv[]) {
// Make sure architecture uses 8bits per char.
assert(CHAR_BIT == 8);
-
+
// TODO Parse commands using: https://stackoverflow.com/questions/9642732/parsing-command-line-arguments-in-c
if (argc > 1) {
@@ -806,6 +860,13 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
+ action = "--t_time";
+ do_action = strncmp(argv[idx], action, strlen(action)) == 0;
+ if (do_action) {
+ prototype(T_TIME);
+ return EXIT_SUCCESS;
+ }
+
action = "--t_sos";
do_action = strncmp(argv[idx], action, strlen(action)) == 0;
if (do_action) {
@@ -869,6 +930,7 @@ int main(int argc, char *argv[]) {
cbreak(); // Line buffering disabled, Pass on everty thing to me.
keypad(stdscr, TRUE); // I need that nifty F1
curs_set(0); // Set cursor invisible.
+ timeout(1000); // Make getch() timeout after timeout(...) miliseconds.
height = 3;
width = 10;
@@ -878,13 +940,18 @@ int main(int argc, char *argv[]) {
refresh();
my_win = create_newwin(height, width, starty, startx);
+
ch = KEY_RESIZE;
do {
task_t *active_task = database.tasks + database.active_task;
task_t *selected_task = database.tasks + database.selected_task;
+ update_timers(&database);
switch(ch)
{
+ case ERR: // When getch() times out.
+ break;
+
case KEY_F(1):
{
task_t *new_task;
@@ -950,7 +1017,7 @@ int main(int argc, char *argv[]) {
task_t *next_task = selected_task;
if (active_task > 0) {
- // TODO Add remaining time to task.
+ update_timers(&database); // TODO Should I keep this even though it always does?
database.active_task = -1;
}
if (active_task != next_task) {
@@ -963,11 +1030,8 @@ int main(int argc, char *argv[]) {
case KEY_RESIZE:
erase();
- if (line_buffer != NULL) {
- free(line_buffer);
- }
getmaxyx(stdscr, size_y, size_x);
- line_buffer = malloc(size_x * sizeof(char));
+ line_buffer = realloc(line_buffer, size_x * sizeof(char));
break;
case KEY_LEFT:
@@ -1011,6 +1075,7 @@ int main(int argc, char *argv[]) {
} while((ch = getch()) != 'q');
+ update_timers(&database);
store_database(&database, DB_BIN_PATH_NAME);
free_memory();
endwin();