Skip to content

Commit

Permalink
Bad UX? Curse it!
Browse files Browse the repository at this point in the history
Major changes for the terminal.
Overall improvements for input handling.
  • Loading branch information
cristianfrasineanu committed Nov 27, 2016
1 parent 1ba8dc8 commit 971c4a4
Show file tree
Hide file tree
Showing 15 changed files with 1,740 additions and 131 deletions.
13 changes: 6 additions & 7 deletions app/Bootstrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,34 @@ using namespace std;

void main()
{
Console::initTerminal();
try
{
View::loadViewsOptions();
Console console;
do
{
try
{
console.showPrompt();
console.setLastInput(_getch());
console.setLastInput(getch());
console.takeActionOrNext();
}
catch (const invalid_argument &e)
{
toast(e.what(), string("error"));
toast(string(e.what()), string("error"));

sleepAndClearBuffer(console.getDelay());
console.reloadView();
clearPreviousLines(0);
}
} while (!console.shouldExit());
}
catch (const invalid_argument &e)
{
toast(e.what(), string("error"));
toast(string(e.what()), string("error"));
}
catch (const system_error &e)
{
clearScreen();

toast(e.what(), string("error"));
toast(string(e.what()), string("error"));
}
}
108 changes: 78 additions & 30 deletions app/Console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,53 @@
string Console::initialView = "home.view";
string Console::viewsFolder = "..\\views";

// Prepare a standard screen that buffers all keys, doesn't echo input,
// waits for the input and isn't affected by interrupt characters.
void Console::initTerminal()
{
initscr();

cbreak();
keypad(stdscr, TRUE);
noecho();
nodelay(stdscr, FALSE);
resize_term(150, 150);

// Scroll to the bottom if the content overflows.
scrollok(stdscr, TRUE);

start_color();
use_default_colors();

// Define color pairs to be assign to stdscr.
init_pair(1, COLOR_WHITE, COLOR_BLACK);

wbkgd(stdscr, COLOR_PAIR(1) | A_BOLD);
refresh();
}

void Console::showPrompt()
{
printString(">> ");
}

void Console::loadActions()
{
// TODO: load actions via config file
vector<char> actions = { 'q', 'b', 'n', 'y' };

this->actions = actions;
}

Console::Console()
{
this->mode = new char[strlen("live") + 1];
this->lastInput = '\0';
strcpy(this->mode, "live");
this->exit = false;

View::loadViewsOptions();
map<char, string> availableOptions = View::getViewsOptions().find(Console::initialView)->second;
this->previousViews = {};

this->delay = 2000;
this->loadActions();
this->loadViews(Console::viewsFolder);

Expand All @@ -30,22 +66,20 @@ Console::Console()
else
{
string exceptionIntro = "Please specify an existing view (";
throw invalid_argument(exceptionIntro + this->currentView.getViewName() + ")");
throw invalid_argument(exceptionIntro + this->currentView.getViewName() + ")\n");
}
}

Console::Console(char *mode)
{
this->mode = new char[strlen("debug") + 1];
strcpy(this->mode, "debug");
this->lastInput = '\0';
this->exit = false;

string viewName = "debug.view";
map<char, string> availableOptions = View::getViewsOptions().find(Console::initialView)->second;
View::loadViewsOptions();
map<char, string> availableOptions = View::getViewsOptions().find(viewName)->second;
this->previousViews = {};

this->delay = 2000;
this->loadActions();
this->loadViews(Console::viewsFolder);

Expand All @@ -58,7 +92,7 @@ Console::Console(char *mode)
else
{
string exceptionIntro = "No debug view found: ";
throw invalid_argument(exceptionIntro + this->currentView.getViewName());
throw invalid_argument(exceptionIntro + this->currentView.getViewName() + ")\n");
}
}

Expand All @@ -74,12 +108,6 @@ void Console::setLastInput(char input)
}
}

void Console::showPrompt()
{
cout << endl
<< ">> ";
}

char Console::getLastInput()
{
return this->lastInput;
Expand Down Expand Up @@ -107,14 +135,6 @@ void Console::loadViews(const fs::path &viewsFolder)
}
}

void Console::loadActions()
{
// TODO: load actions via config file
vector<char> actions = { 'q', 'b', 'n', 'y' };

this->actions = actions;
}

void Console::handleView()
{
string content,
Expand All @@ -133,13 +153,13 @@ void Console::handleView()
if (!Controller::getErrorBag().empty())
{
toast(string("There were some issues:"), string("error"));
printString("\n");
printVector(Controller::getErrorBag());

sleepAndClearBuffer(3 * this->delay);
this->reloadView();
// Empty the bag and provide a retry step.
Controller::pushError(string(""));
this->provideRetry();
}
// TODO: provide an option to the users to cancel what they want to do.
// i.e. show the errors and ask if they want to try again or go back.

buffer.clear();
viewFile.close();
Expand Down Expand Up @@ -192,6 +212,25 @@ void Console::reloadView()
this->handleView();
}

void Console::provideRetry()
{
printString("\n");
toast(string("Would you like to retry or go back? (Y/b)\n"), string("notification"));
this->showPrompt();
do
{
this->lastInput = (char)tolower(getch());
if (this->lastInput == 'y')
{
this->reloadView();
}
else if (this->lastInput == 'b')
{
this->renderPreviousView();
}
} while (this->lastInput != 'y' && this->lastInput != 'b');
}

void Console::takeActionOrNext()
{
if (isInVector(this->actions, this->lastInput))
Expand All @@ -208,8 +247,8 @@ void Console::takeActionOrNext()
// TODO: implement pagination
break;
case 'y':
UserRepository::logOutUser();
// TODO: Decouple this somehow
UserRepository::logOutUser();
this->renderNextView(string(Console::initialView));
default:
break;
Expand Down Expand Up @@ -243,7 +282,16 @@ Console::~Console()
// Dump all the records...
UserModel::dumpFile();

// Revert to default terminal and display notice.
clearScreen();
cout << "Program exited the main console."
<< endl;
wbkgd(stdscr, COLOR_PAIR(1));
printString("Program exited the main console.\n");

// This or use the windows Sleep.
// Maybe better Sleep.
//timeout(this->delay);
getch();

endwin();
refresh();
}
9 changes: 6 additions & 3 deletions app/Console.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ class Console {
static string viewsFolder;

char *mode;
char lastInput;
unsigned delay;
bool exit;
unsigned delay = 2000;
char lastInput = '\0';
bool exit = false;

View currentView;
Controller theController;
Expand All @@ -37,6 +37,8 @@ class Console {
void renderPreviousView();
void handleView();
public:
static void initTerminal();

Console();
Console(char *);

Expand All @@ -50,6 +52,7 @@ class Console {
unsigned getDelay();

void reloadView();
void provideRetry();

~Console();
};
53 changes: 46 additions & 7 deletions app/Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ vector<string> Controller::errorBag = {};

void Controller::justShow()
{
cout << this->viewChunk
<< endl;
addstr(this->viewChunk.c_str());
printString("\n\n");
}

// Determine the order of the input/output from the user.
Expand Down Expand Up @@ -55,8 +55,7 @@ void Controller::prepareView()
// Show the rest.
if (copyChunk.size())
{
cout << copyChunk
<< endl;
addstr((copyChunk + "\n\n").c_str());
}

// Send the payload to the accessor model to be passed to the according repository.
Expand All @@ -71,9 +70,45 @@ void Controller::prepareViewInput(const string &subChunk, const string &inputAli
string userInput;
map<string, string> currentInput;

cout << subChunk << " ";
getline(cin, userInput);
cout << endl;
addstr((subChunk + " ").c_str());
refresh();

// Hide the input when typing any sensitive data.
if (inputAlias.find("password") != string::npos)
{
const char carriage_return = 10;
const char backspace = 8;

unsigned char ch = 0;

noecho();
while ((ch = getch()) != carriage_return)
{
if (ch == backspace && userInput.size())
{
printw("\b \b");
refresh();
userInput.resize(userInput.size() - 1);
}
else if (ch != backspace)
{
userInput += ch;
printw("*");
refresh();
}
}

// Re-enable input and render the previous carriage return.
echo();
printString("\n");
}
else
{
//getline(cin, userInput);
getString(userInput);
}

printString("\n");

this->userInputs[inputAlias] = userInput;
}
Expand Down Expand Up @@ -110,6 +145,8 @@ Controller::Controller(char *viewName, string &viewChunk, string &ViewExtension)
string controllerName = viewName;
controllerName.erase(controllerName.find(ViewExtension), ViewExtension.size()).append("Controller");

echo();

this->controllerName = new char[controllerName.size() + 1];
strcpy(this->controllerName, controllerName.c_str());

Expand Down Expand Up @@ -165,4 +202,6 @@ bool Controller::hasOutput(const string &raw)
Controller::~Controller()
{
delete[] this->controllerName;

noecho();
}
Loading

0 comments on commit 971c4a4

Please sign in to comment.