rewrite askUserNameAndPassword() to use tim
This commit is contained in:
2
dependencies/tim
vendored
2
dependencies/tim
vendored
Submodule dependencies/tim updated: d417b5bbd5...3fb220ff54
@@ -18,11 +18,11 @@ static const str farewell_art = STR(
|
||||
"\\(_,J J L l`,)/\n"
|
||||
);
|
||||
|
||||
#define FPS 30
|
||||
|
||||
#define is_alias(LITERAL) str_equals(command, STR(LITERAL))
|
||||
|
||||
static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* password_out);
|
||||
Result(bool) start_screen(Array(char) username_buf, Array(char) password_buf,
|
||||
str* out_username, str* out_password);
|
||||
static Result(void) ClientCLI_openUserDB(ClientCLI* self);
|
||||
static Result(void) ClientCLI_execCommand(ClientCLI* self, str command, bool* stop);
|
||||
static Result(SavedServer*) ClientCLI_joinNewServer(ClientCLI* self);
|
||||
@@ -48,48 +48,29 @@ void ClientCLI_construct(ClientCLI* self){
|
||||
}
|
||||
|
||||
Result(void) ClientCLI_run(ClientCLI* self) {
|
||||
Deferral(FPS);
|
||||
Deferral(32);
|
||||
|
||||
TimEditState e;
|
||||
TimEditState_init(&e, 32, "Greetings!");
|
||||
bool edit_enabled = false;
|
||||
while(tim_run(30)){
|
||||
TimStyle c = { .brd = TimColor16_White, .bg = TimColor16_DarkBlue, .fg = TimColor16_White };
|
||||
tim_frame(0, 0, ~0, ~0, c);
|
||||
|
||||
tim_label(e.s, A, 2, A, A, c);
|
||||
|
||||
if(edit_enabled){
|
||||
TimKey key = tim_edit(&e, A, 5, tim->scopes[tim->scope].w - 4, c);
|
||||
|
||||
if(key == TimKey_Escape || key == TimKey_Enter)
|
||||
edit_enabled = false;
|
||||
}
|
||||
else {
|
||||
if(tim_button("[Enter] Edit text", A, 5, tim->scopes[tim->scope].w - 4, A, c) || tim_is_key_press(TimKey_Enter)){
|
||||
edit_enabled = true;
|
||||
tim->focus = &e;
|
||||
tim->event.type = TimEvent_Void; // consume key event
|
||||
}
|
||||
}
|
||||
|
||||
if(tim_button("[Q] Quit", A, ~1, 10, A, c) || tim_is_key_press('q'))
|
||||
exit(0);
|
||||
// ask username and password
|
||||
Array(char) username_buf = Array_char_alloc(USERNAME_SIZE_MAX + 1);
|
||||
Array(char) password_buf = Array_char_alloc(PASSWORD_SIZE_MAX + 1);
|
||||
Defer(
|
||||
Array_char_destroy(&username_buf);
|
||||
Array_char_destroy(&password_buf);
|
||||
);
|
||||
str username = str_null, password = str_null;
|
||||
try(bool start, i, start_screen(username_buf, password_buf, &username, &password));
|
||||
if(!start){
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
tim_reset_terminal();
|
||||
term_clear();
|
||||
printf(FMT_str"\n", greeting_art.len, greeting_art.data);
|
||||
|
||||
// create Client
|
||||
str username = str_null, password = str_null;
|
||||
try_void(ClientCLI_askUserNameAndPassword(&username, &password));
|
||||
Defer(
|
||||
str_destroy(username);
|
||||
str_destroy(password);
|
||||
);
|
||||
Client_free(self->client);
|
||||
// create client
|
||||
try(self->client, p, Client_create(username, password));
|
||||
memset(password.data, 0, password.len);
|
||||
// erase password from memory
|
||||
Array_char_memset(&password_buf, 0);
|
||||
|
||||
// init db
|
||||
try_void(ClientCLI_openUserDB(self));
|
||||
@@ -120,49 +101,6 @@ Result(void) ClientCLI_run(ClientCLI* self) {
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* password_out){
|
||||
Deferral(8);
|
||||
bool success = false;
|
||||
|
||||
// ask username
|
||||
Array(char) username_buf = Array_char_alloc(128);
|
||||
Defer(if(!success) Array_char_destroy(&username_buf));
|
||||
str username = str_null;
|
||||
while(true) {
|
||||
printf("username: ");
|
||||
try_void(term_readLine(username_buf.data, username_buf.len));
|
||||
username = str_from_cstr(username_buf.data);
|
||||
str_trim(&username, true);
|
||||
str name_error_str = validateUsername_str(username);
|
||||
if(name_error_str.data){
|
||||
printf("ERROR: "FMT_str"\n",
|
||||
name_error_str.len, name_error_str.data);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
// ask password
|
||||
Array(char) password_buf = Array_char_alloc(128);
|
||||
Defer(if(!success) Array_char_destroy(&password_buf));
|
||||
str password = str_null;
|
||||
while(true) {
|
||||
printf("password: ");
|
||||
// TODO: hide password
|
||||
try_void(term_readLineHidden(password_buf.data, password_buf.len));
|
||||
password = str_from_cstr(password_buf.data);
|
||||
str_trim(&password, true);
|
||||
if(password.len < PASSWORD_SIZE_MIN || password.len > PASSWORD_SIZE_MAX){
|
||||
printf("ERROR: password length (in bytes) must be >= %i and <= %i\n",
|
||||
PASSWORD_SIZE_MIN, PASSWORD_SIZE_MAX);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
*username_out = username;
|
||||
*password_out = password;
|
||||
success = true;
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) ClientCLI_openUserDB(ClientCLI* self){
|
||||
Deferral(8);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "tlibc/collections/List.h"
|
||||
#include "db/client_db.h"
|
||||
|
||||
#define FPS 30
|
||||
|
||||
typedef struct ClientCLI {
|
||||
Client* client;
|
||||
tsqlite_connection* db;
|
||||
|
||||
138
src/cli/ClientCLI/start_screen.c
Normal file
138
src/cli/ClientCLI/start_screen.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "ClientCLI.h"
|
||||
#include "network/tcp-chat-protocol/v1.h"
|
||||
#include "tim.h"
|
||||
|
||||
|
||||
typedef struct TextInputState {
|
||||
TimEditState edit;
|
||||
cstr label;
|
||||
TimStyle style_default;
|
||||
TimStyle style_focused;
|
||||
TimKey result_key;
|
||||
} TextInputState;
|
||||
|
||||
void draw_item_text_input(bool is_selected, TimRect place, void* data){
|
||||
TextInputState* ctx = data;
|
||||
TimStyle style = is_selected ? ctx->style_focused : ctx->style_default;
|
||||
ctx->result_key = tim_edit(&ctx->edit, place.x, place.y, place.w, style);
|
||||
tim_label(ctx->label, place.x + 3, place.y, A, 1, style);
|
||||
}
|
||||
|
||||
typedef struct StartScreenContext {
|
||||
TimStyle style_default;
|
||||
TimStyle style_focused;
|
||||
TimStyle style_error;
|
||||
TextInputState input_username;
|
||||
TextInputState input_password;
|
||||
bool exit;
|
||||
bool start;
|
||||
char* err_msg; // heap only
|
||||
} StartScreenContext;
|
||||
|
||||
void draw_start_screen_buttons(bool is_selected, TimRect place, void* data){
|
||||
StartScreenContext* ctx = data;
|
||||
TimStyle style = is_selected ? ctx->style_focused : ctx->style_default;
|
||||
i32 start_w = place.w / 2;
|
||||
i32 dist = 1;
|
||||
i32 quit_x = place.x + start_w + dist;
|
||||
i32 quit_w = place.w - start_w - dist;
|
||||
if(tim_button("[Enter] Start", place.x, place.y, start_w, A, style)
|
||||
|| tim_is_key_press(TimKey_Enter))
|
||||
{
|
||||
ctx->start = true;
|
||||
}
|
||||
else if(tim_button("[Esc/Q] Quit", quit_x, place.y, quit_w, A, ctx->style_default)
|
||||
|| tim_is_key_press('q'))
|
||||
{
|
||||
ctx->exit = true;
|
||||
}
|
||||
}
|
||||
|
||||
Result(bool) start_screen(Array(char) username_buf, Array(char) password_buf,
|
||||
str* out_username, str* out_password)
|
||||
{
|
||||
Deferral(16);
|
||||
|
||||
bool result = false;
|
||||
|
||||
StartScreenContext ctx = {
|
||||
.style_default = { .brd = TimColor16_Gray, .bg = TimColor16_DarkBlue, .fg = TimColor16_Gray },
|
||||
.style_focused = { .brd = TimColor16_White, .bg = TimColor16_DarkCyan, .fg = TimColor16_White },
|
||||
.style_error = { .brd = TimColor16_Gray, .bg = TimColor16_DarkRed, .fg = TimColor16_White },
|
||||
};
|
||||
|
||||
TimEditState_construct(&ctx.input_username.edit, username_buf.data, username_buf.len, NULL);
|
||||
ctx.input_username.label = "[username]";
|
||||
ctx.input_username.style_default = ctx.style_default;
|
||||
ctx.input_username.style_focused = ctx.style_focused;
|
||||
|
||||
TimEditState_construct(&ctx.input_password.edit, password_buf.data, password_buf.len, NULL);
|
||||
ctx.input_password.edit.masked = true;
|
||||
ctx.input_password.label = "[password]";
|
||||
ctx.input_password.style_default = ctx.style_default;
|
||||
ctx.input_password.style_focused = ctx.style_focused;
|
||||
|
||||
TimScrollItem items[] = {
|
||||
// username input
|
||||
{ .data = &ctx.input_username, .focus_target = &ctx.input_username.edit, .h = 3, .draw = draw_item_text_input },
|
||||
// password input
|
||||
{ .data = &ctx.input_password, .focus_target = &ctx.input_password.edit, .h = 3, .draw = draw_item_text_input },
|
||||
// buttons
|
||||
{ .data = &ctx, .focus_target = NULL, .h = 3, .draw = draw_start_screen_buttons },
|
||||
};
|
||||
|
||||
TimScrollState scroll_list = { .items = items, .len = ARRAY_LEN(items) };
|
||||
|
||||
while(tim_run(FPS)){
|
||||
tim_fill(tim_cell(" ", ctx.style_default.fg, ctx.style_default.bg), 0, 0, A, A);
|
||||
tim_scope(A, A, 40, 14) {
|
||||
tim_scroll(&scroll_list, 1, 1, ~1, ~1, ctx.style_default);
|
||||
}
|
||||
|
||||
if(ctx.err_msg){
|
||||
i32 below_scroll = tim->scopes[tim->scope].h/2 + 7;
|
||||
tim_label("ERROR: ", A, below_scroll, A, A, ctx.style_error);
|
||||
tim_label(ctx.err_msg, A, below_scroll + 1, A, A, ctx.style_error);
|
||||
}
|
||||
|
||||
if(ctx.exit
|
||||
|| ctx.input_username.result_key == TimKey_Escape
|
||||
|| ctx.input_password.result_key == TimKey_Escape)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
if(ctx.start){
|
||||
ctx.start = false;
|
||||
free(ctx.err_msg);
|
||||
ctx.err_msg = NULL;
|
||||
|
||||
// check username
|
||||
str username = str_from_cstr(username_buf.data);
|
||||
str_trim(&username, true);
|
||||
str name_error_str = validateUsername_str(username);
|
||||
if(name_error_str.data){
|
||||
ctx.err_msg = name_error_str.data;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check password
|
||||
str password = str_from_cstr(password_buf.data);
|
||||
str_trim(&password, true);
|
||||
if(password.len < PASSWORD_SIZE_MIN || password.len > PASSWORD_SIZE_MAX){
|
||||
ctx.err_msg = sprintf_malloc(
|
||||
"password length (in bytes) must be >= %i and <= %i",
|
||||
PASSWORD_SIZE_MIN, PASSWORD_SIZE_MAX
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
*out_username = username;
|
||||
*out_password = password;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Return RESULT_VALUE(i, result);
|
||||
}
|
||||
Reference in New Issue
Block a user