diff --git a/.gitignore b/.gitignore index d4e463c..02b180e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ build/ *~ *.o *#* -adhd \ No newline at end of file +adhd +*.sqlite3 \ No newline at end of file diff --git a/Makefile b/Makefile index 5976374..61bf6e1 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC = cc CFLAGS = -g -Wall -Iinclude SOURCES = src/main.c src/window_state.c OBJECTS = src/main.o src/window_state.o -LDFLAGS = -lraylib -lm +LDFLAGS = -lraylib -lm -lsqlite3 HEADERS = \ include/raygui.h include/common.h include/window_state.h diff --git a/TODO.md b/TODO.md index 65bd3d4..2138274 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,13 @@ - [x] model window state with intention and simple overlay, window modes -- [ ] create 2d grid -- [ ] toggle win / loss and persist values +- [x] create 2d grid +- [x] usability: show week of the year / day of week, tooltips +- [x] toggle win / loss and persist values + +- [x] persist results in sqlite3 - [ ] reminder animation - [ ] install via homebrew -- [ ] create windows download -- [ ] launch on hackernews "for developers with adhd"...create an html page as well on flowylabs site +- [ ] launch on hackernews "for developers with adhd" diff --git a/src/main.c b/src/main.c index 09f6f28..d16482c 100644 --- a/src/main.c +++ b/src/main.c @@ -93,7 +93,6 @@ void draw_graph(int x, int y) { GuiSetStyle(BUTTON, BASE_COLOR_NORMAL, ColorToInt(BLANK)); } if (GuiButton((Rectangle) {cell_x + x, cell_y + y, CELL_SIZE, CELL_SIZE}, " ")) { - printf("clicked row %d | column %d\n", r, c); set_result(time, abs(result - 1)); } diff --git a/src/window_state.c b/src/window_state.c index 3f7ef7e..c436cd1 100644 --- a/src/window_state.c +++ b/src/window_state.c @@ -3,6 +3,7 @@ #include #include #include +#include struct state *s = NULL; @@ -21,6 +22,84 @@ struct state { size_t capacity_records; }; +static sqlite3 *db = NULL; + +static void db_open() { + int r = sqlite3_open("local.sqlite3", &db); + if (r == SQLITE_OK) { + } else { + fprintf(stderr, "Unable to prepare sqlite db\n"); + exit(-1); + } + + const char *sql = + "CREATE TABLE IF NOT EXISTS records (" + "key TEXT PRIMARY KEY," + "value INT" + ");" + ; + + char *err; + r = sqlite3_exec(db, sql, NULL, NULL, &err); + if (r != SQLITE_OK) { + fprintf(stderr, "SQL error during setup: %s\n", err); + sqlite3_free(err); + sqlite3_close(db); + exit(-1); + } +} + +static void db_close() { + if (db) { + sqlite3_close(db); + } +} + +static int db_get_record_callback(void *ctx, int argc, char *argv[], char **argv_col_name) { + Record *rec = calloc(1, sizeof(Record)); + + for (int i = 0; i < argc; i++) { + if (strcmp(argv_col_name[i], "key") == 0) { + rec->key = strdup(argv[i]); + } else if (strcmp(argv_col_name[i], "value") == 0) { + rec->value = (U32) atoi(argv[i]); + } + } + + if (s->size_records >= s->capacity_records) { + printf("MAX capacity"); + return 0; + } + + *(s->records + s->size_records) = rec; + s->size_records++; + + return 0; +} + +static void db_upsert_record(char *key, U32 value) { + sqlite3_stmt *stmt; + const char *sql = "INSERT INTO records (key, value) VALUES (?, ?) ON CONFLICT (key) DO UPDATE SET value = ?;"; + int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + assert(rc == SQLITE_OK); + sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC); + sqlite3_bind_int(stmt, 2, value); + sqlite3_bind_int(stmt, 3, value); + + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) { + printf("Failure in insert: %s\n", sqlite3_errmsg(db)); + } + + sqlite3_finalize(stmt); +} + +static void db_get_all_records() { + const char *sql = "SELECT key, value FROM records;"; + int rc = sqlite3_exec(db, sql, db_get_record_callback, NULL, NULL); + assert(rc == SQLITE_OK); +} + void init_window_state() { s = malloc(sizeof(struct state)); s->mode = WINDOW; @@ -30,12 +109,15 @@ void init_window_state() { s->size_records = 0; s->capacity_records = 1000; //TODO: make dynamic s->records = malloc(sizeof(Record *) * s->capacity_records); + + db_open(); + db_get_all_records(); } -static void add_record(char *key, U32 value) { +static Record *append_record(char *key, U32 value) { if (s->size_records >= s->capacity_records) { printf("MAX capacity"); - exit(-1); + return NULL; } char *cpy = strdup(key); @@ -46,6 +128,7 @@ static void add_record(char *key, U32 value) { *(s->records + s->size_records) = new_record; s->size_records++; + return new_record; } static void upsert_record(char *key, U32 value) { @@ -60,7 +143,7 @@ static void upsert_record(char *key, U32 value) { } if (!found) { - add_record(key, value); + append_record(key, value); } } @@ -99,6 +182,8 @@ void cleanup_window_state() { free(s); s = NULL; + + db_close(); } void set_intention(char *intention) { @@ -142,6 +227,5 @@ void set_result(struct tm *time, U32 result) { char key[10]; generate_key(time, key, sizeof(key)); upsert_record(key, result); - - print_records(); + db_upsert_record(key, result); }