Basic UI with commands
This commit is contained in:
@@ -217,7 +217,8 @@ asana_err user_task_list(char *task_list_gid, Project *task_list) {
|
|||||||
task_list->tasks = (Task *)asana_parse_array(task_list_resp->body, sizeof(Task), &(task_list->tasks_len));
|
task_list->tasks = (Task *)asana_parse_array(task_list_resp->body, sizeof(Task), &(task_list->tasks_len));
|
||||||
ret = task_list->tasks == NULL ? ASANA_ERR_PARSE : ASANA_ERR_OK;
|
ret = task_list->tasks == NULL ? ASANA_ERR_PARSE : ASANA_ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error fetching user_Task_list: %d\n", task_list_resp->status);
|
fprintf(stderr, "Error fetching user_task_list: %d\n",
|
||||||
|
task_list_resp->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
asana_free_response(task_list_resp);
|
asana_free_response(task_list_resp);
|
||||||
|
|||||||
87
ncac.c
87
ncac.c
@@ -1,39 +1,80 @@
|
|||||||
#include "ncac.h"
|
#include "ncac.h"
|
||||||
|
|
||||||
#include <curses.h>
|
#include <curses.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <term.h>
|
#include <term.h>
|
||||||
|
|
||||||
#include "asana/asana.h"
|
#include "asana/asana.h"
|
||||||
#include "asana/fetch.h"
|
#include "asana/fetch.h"
|
||||||
#include "ui/base.h"
|
#include "ui/base.h"
|
||||||
|
#include "ui/commands.h"
|
||||||
|
#include "ui/model.h"
|
||||||
|
|
||||||
|
void append_to_buffer(ui_state *state, char c) {
|
||||||
|
if (state->buffer_size < UI_INPUT_BUFFER_SIZE - 1) {
|
||||||
|
state->input_buffer[state->buffer_size++] = c;
|
||||||
|
state->input_buffer[state->buffer_size] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_command(ui_state *state) {
|
||||||
|
for (size_t i = 0; i < UI_NUM_COMMANDS; i++) {
|
||||||
|
if (strncmp(state->input_buffer, ui_commands[i].command,
|
||||||
|
UI_INPUT_BUFFER_SIZE) == 0) {
|
||||||
|
return ui_commands[i].handler(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state->curs_y = 0;
|
||||||
|
state->curs_x = 0;
|
||||||
|
|
||||||
|
draw_text("Unknown command. Type \":help\" for a list of commands", state);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int main(/*int argc, char **argv*/) {
|
int main(/*int argc, char **argv*/) {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
int curs_x = 0;
|
int input;
|
||||||
int curs_y = 0;
|
|
||||||
|
|
||||||
char input;
|
ui_state state;
|
||||||
|
state.mode = 0;
|
||||||
|
state.buffer_size = 0;
|
||||||
|
state.input_buffer[0] = '\0';
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
draw_status_line(&state);
|
||||||
|
|
||||||
while (1) {
|
|
||||||
switch (input = getch()) {
|
switch (input = getch()) {
|
||||||
case 'a':
|
case '\r':
|
||||||
draw_text("Hello, world!", &curs_x, &curs_y);
|
if (state.mode == COMMAND) {
|
||||||
break;
|
state.mode = NORMAL;
|
||||||
case 'b':
|
if (handle_command(&state)) {
|
||||||
draw_text("Goodbye, world!", &curs_x, &curs_y);
|
finish(SIGTERM);
|
||||||
break;
|
}
|
||||||
case 'j':
|
} else if (state.mode == NORMAL) {
|
||||||
get_me(&curs_x, &curs_y);
|
state.curs_y++;
|
||||||
break;
|
}
|
||||||
case 'm':
|
break;
|
||||||
get_my_tasks(&curs_x, &curs_y);
|
case KEY_EXIT:
|
||||||
break;
|
state.mode = NORMAL;
|
||||||
case 'q':
|
break;
|
||||||
finish(SIGTERM);
|
case ':':
|
||||||
break;
|
if (state.mode == NORMAL) {
|
||||||
|
state.mode = COMMAND;
|
||||||
|
state.buffer_size = 0;
|
||||||
|
state.input_buffer[0] = '\0';
|
||||||
|
} else {
|
||||||
|
append_to_buffer(&state, input);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
append_to_buffer(&state, input);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -71,6 +112,8 @@ static void setup() {
|
|||||||
}
|
}
|
||||||
noecho();
|
noecho();
|
||||||
nonl();
|
nonl();
|
||||||
|
intrflush(stdscr, FALSE);
|
||||||
|
keypad(stdscr, TRUE);
|
||||||
|
|
||||||
// install handlers
|
// install handlers
|
||||||
signal(SIGINT, &finish);
|
signal(SIGINT, &finish);
|
||||||
@@ -95,7 +138,7 @@ void get_me(int *curs_x, int *curs_y) {
|
|||||||
|
|
||||||
*curs_x = 0;
|
*curs_x = 0;
|
||||||
(*curs_y)++;
|
(*curs_y)++;
|
||||||
draw_text(gid, curs_x, curs_y);
|
// draw_text(gid, curs_x, curs_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_my_tasks(int *curs_x, int *curs_y) {
|
void get_my_tasks(int *curs_x, int *curs_y) {
|
||||||
@@ -124,12 +167,12 @@ void get_my_tasks(int *curs_x, int *curs_y) {
|
|||||||
*curs_x = 0;
|
*curs_x = 0;
|
||||||
*curs_y = 0;
|
*curs_y = 0;
|
||||||
|
|
||||||
draw_text("My Tasks", curs_x, curs_y);
|
// draw_text("My Tasks", curs_x, curs_y);
|
||||||
*curs_x = 0;
|
*curs_x = 0;
|
||||||
(*curs_y)+=2;
|
(*curs_y)+=2;
|
||||||
|
|
||||||
for (size_t i=0; i<my_tasks.tasks_len;i++) {
|
for (size_t i=0; i<my_tasks.tasks_len;i++) {
|
||||||
draw_text(my_tasks.tasks[i].name, curs_x, curs_y);
|
// draw_text(my_tasks.tasks[i].name, curs_x, curs_y);
|
||||||
*curs_x = 0;
|
*curs_x = 0;
|
||||||
(*curs_y)++;
|
(*curs_y)++;
|
||||||
}
|
}
|
||||||
|
|||||||
29
ui/base.c
29
ui/base.c
@@ -1,17 +1,40 @@
|
|||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
#include <curses.h>
|
#include <curses.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void draw_text(char *text, int *x, int *y) {
|
#include "commands.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
void draw_status_line(ui_state *state) {
|
||||||
|
int old_x = state->curs_x;
|
||||||
|
int old_y = state->curs_y;
|
||||||
|
|
||||||
|
state->curs_y = LINES - 1;
|
||||||
|
state->curs_x = 0;
|
||||||
|
|
||||||
|
if (state->mode == NORMAL) {
|
||||||
|
draw_text("NORMAL", state);
|
||||||
|
} else {
|
||||||
|
draw_text(":", state);
|
||||||
|
draw_text(state->input_buffer, state);
|
||||||
|
}
|
||||||
|
clrtoeol();
|
||||||
|
|
||||||
|
state->curs_x = old_x;
|
||||||
|
state->curs_y = old_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_text(const char *text, ui_state *state) {
|
||||||
if (!text || strnlen(text, 1) == 0) return;
|
if (!text || strnlen(text, 1) == 0) return;
|
||||||
|
|
||||||
mvaddch(*y, *x, *text);
|
mvaddch(state->curs_y, state->curs_x, *text);
|
||||||
++text;
|
++text;
|
||||||
|
|
||||||
for (; *text != '\0'; ++text) {
|
for (; *text != '\0'; ++text) {
|
||||||
addch(*text);
|
addch(*text);
|
||||||
}
|
}
|
||||||
|
|
||||||
getyx(stdscr, *y, *x);
|
getyx(stdscr, state->curs_y, state->curs_x);
|
||||||
}
|
}
|
||||||
|
|||||||
11
ui/base.h
11
ui/base.h
@@ -1,10 +1,19 @@
|
|||||||
#ifndef UI_BASE_H_
|
#ifndef UI_BASE_H_
|
||||||
#define UI_BASE_H_
|
#define UI_BASE_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the string text starting at position *x, *y. x and y are updated to
|
* Prints the string text starting at position *x, *y. x and y are updated to
|
||||||
* the position after the last character
|
* the position after the last character
|
||||||
*/
|
*/
|
||||||
void draw_text(char *text, int *x, int *y);
|
void draw_text(const char *text, ui_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the input status bar
|
||||||
|
*/
|
||||||
|
void draw_status_line(ui_state *state);
|
||||||
|
|
||||||
#endif // UI_BASE_H_
|
#endif // UI_BASE_H_
|
||||||
|
|||||||
92
ui/commands.c
Normal file
92
ui/commands.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include "commands.h"
|
||||||
|
|
||||||
|
#include <curses.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "../asana/asana.h"
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
bool ui_quit(ui_state *state) { return true; }
|
||||||
|
|
||||||
|
bool ui_help(ui_state *state) {
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y = 0;
|
||||||
|
|
||||||
|
draw_text("Commands:", state);
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y += 2;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < UI_NUM_COMMANDS; i++) {
|
||||||
|
draw_text("\t", state);
|
||||||
|
draw_text(ui_commands[i].command, state);
|
||||||
|
draw_text("\t", state);
|
||||||
|
draw_text(ui_commands[i].help_text, state);
|
||||||
|
clrtoeol();
|
||||||
|
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ui_mytasks(ui_state *state) {
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y = 0;
|
||||||
|
draw_text("Fetching user...", state);
|
||||||
|
clrtoeol();
|
||||||
|
|
||||||
|
/*
|
||||||
|
User me;
|
||||||
|
user_info(&me);
|
||||||
|
|
||||||
|
if (me.workspaces == NULL || me.workspaces_len == 0) {
|
||||||
|
fprintf(stderr, "Unable to get workspaces.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y = 0;
|
||||||
|
draw_text("Fetching user task list ID...", state);
|
||||||
|
clrtoeol();
|
||||||
|
|
||||||
|
char gid[64];
|
||||||
|
gid[0] = '\0';
|
||||||
|
if (user_task_list_gid(
|
||||||
|
/*me.workspaces[me.workspaces_len-1].gid*/ "15793206719", gid) !=
|
||||||
|
ASANA_ERR_OK) {
|
||||||
|
fprintf(stderr, "Unable to get task list ID. %s\n", gid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y = 0;
|
||||||
|
draw_text("Fetching user task list", state);
|
||||||
|
clrtoeol();
|
||||||
|
|
||||||
|
Project my_tasks;
|
||||||
|
if (user_task_list(gid, &my_tasks) != ASANA_ERR_OK) {
|
||||||
|
fprintf(stderr, "Unable to get task list.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->curs_x = 0;
|
||||||
|
state->curs_y = 0;
|
||||||
|
draw_text("My Tasks", state);
|
||||||
|
clrtoeol();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < my_tasks.tasks_len; i++) {
|
||||||
|
state->curs_y++;
|
||||||
|
state->curs_x = 0;
|
||||||
|
draw_text(my_tasks.tasks[i].name, state);
|
||||||
|
clrtoeol();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_command ui_commands[UI_NUM_COMMANDS] = {
|
||||||
|
{"help", "print this help message", ui_help},
|
||||||
|
{"q", "quit the application", ui_quit},
|
||||||
|
{"mytasks", "fetch and display your task list", ui_mytasks}};
|
||||||
19
ui/commands.h
Normal file
19
ui/commands.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef UI_COMMANDS_H_
|
||||||
|
#define UI_COMMANDS_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
typedef struct ui_command {
|
||||||
|
const char *command;
|
||||||
|
const char *help_text;
|
||||||
|
bool (*handler)(ui_state *);
|
||||||
|
} ui_command;
|
||||||
|
|
||||||
|
#define UI_NUM_COMMANDS 3
|
||||||
|
extern ui_command ui_commands[];
|
||||||
|
|
||||||
|
bool handle_command(ui_state *state);
|
||||||
|
|
||||||
|
#endif // UI_COMMANDS_H_
|
||||||
1
ui/model.c
Normal file
1
ui/model.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "model.h"
|
||||||
21
ui/model.h
Normal file
21
ui/model.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef UI_MODEL_H_
|
||||||
|
#define UI_MODEL_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
enum UI_MODE {
|
||||||
|
NORMAL,
|
||||||
|
COMMAND,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UI_INPUT_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
typedef struct ui_state {
|
||||||
|
int curs_x;
|
||||||
|
int curs_y;
|
||||||
|
enum UI_MODE mode;
|
||||||
|
size_t buffer_size;
|
||||||
|
char input_buffer[UI_INPUT_BUFFER_SIZE];
|
||||||
|
} ui_state;
|
||||||
|
|
||||||
|
#endif // UI_MODEL_H_
|
||||||
Reference in New Issue
Block a user