GabrielTofvesson 100f5a32be Major changes
Refactorings:
  * BinaryCollector -> BitWriter
  * BinaryDistributor -> BitReader

Additions:
  * Output class for making serverside output pretty and more readable
  * Better RSA keys (private keys withheld)

Changes:
  * Minor changes to all views and their rendering
  * Added corrective resizing to resize listener to prevent errant window sizes
  * Removed "default" language in favour of a purely priority-based system
  * NetContext now attempts to verify server identity before continuing to next context
  * Simplified common operations in Context
  * Minor updates to some layouts
  * Completed translations for english and swedish
  * Promise system now supports internal processing before notifying original caller
  * Bank interactor methods are now async
  * Added support for multiple accounts per user (separate repositories for money)
  * Removed test code from client program
  * Updated Database to support multiple accounts
  * Reimplemented RSA on the server side purely as an identity verification system on top of the networking layer (rather than part of the layer)
  * Added Account management endpoints
  * Added full support for System-sourced transactions
  * Added Account availability endpoint
  * Added verbose error responses
2018-04-26 00:24:58 +02:00

283 lines
13 KiB
C#

using Client.ConsoleForms.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tofvesson.Collections;
using Tofvesson.Crypto;
namespace Client.ConsoleForms.Graphics
{
public class InputView : TextView
{
public enum InputType
{
Any,
AlphaNumeric,
Integer,
Decimal,
Alphabet
}
public sealed class InputField
{
public const char hide_char = '*';
public string Label { get; private set; }
public int MaxLength { get; private set; }
public bool ShowText { get; set; }
public string Text { get; set; }
public int SelectIndex { get; set; }
public InputType Input { get; set; }
public ConsoleColor TextColor { get; set; }
public ConsoleColor BackgroundColor { get; set; }
public ConsoleColor SelectTextColor { get; set; }
public ConsoleColor SelectBackgroundColor { get; set; }
public string InputTypeString
{
get
{
switch (Input)
{
case InputType.Any:
return "Any";
case InputType.AlphaNumeric:
return "AlphaNumeric";
case InputType.Integer:
return "Integer";
case InputType.Decimal:
return "Decimal";
case InputType.Alphabet:
return "Alphabet";
}
throw new SystemException("Invalid system state detected");
}
set
{
switch (value.ToLower())
{
case "alphanumeric":
Input = InputType.AlphaNumeric;
break;
case "integer":
Input = InputType.Integer;
break;
case "decimal":
Input = InputType.Decimal;
break;
case "alphabet":
Input = InputType.Alphabet;
break;
default:
Input = InputType.Any;
break;
}
}
}
internal int RenderStart { get; set; }
public InputField(string label, int maxLength)
{
TextColor = ConsoleColor.Black;
BackgroundColor = ConsoleColor.DarkGray;
SelectTextColor = ConsoleColor.Black;
SelectBackgroundColor = ConsoleColor.Gray;
Input = InputType.Any;
Label = label;
MaxLength = maxLength;
Text = "";
}
public bool IsValidChar(char c) =>
(Input == InputType.Any) ||
(Input == InputType.AlphaNumeric && c.IsAlphaNumeric()) ||
(Input == InputType.Alphabet && c.IsAlphabetical()) ||
(Input == InputType.Integer && c.IsNumber()) ||
(Input == InputType.Decimal && c.IsDecimal());
}
public delegate void SubmissionListener(InputView view);
public delegate bool TextEnteredListener(InputView view, InputField change, ConsoleKeyInfo info);
public ConsoleColor DefaultBackgroundColor { get; set; }
public ConsoleColor DefaultTextColor { get; set; }
public ConsoleColor DefaultSelectBackgroundColor { get; set; }
public ConsoleColor DefaultSelectTextColor { get; set; }
public InputField[] Inputs { get; private set; }
private int selectedField;
public int SelectedField
{
get => selectedField;
set
{
selectedField = value;
Dirty = true;
}
}
private string[][] splitInputs;
public SubmissionListener SubmissionsListener { protected get; set; }
public TextEnteredListener InputListener { protected get; set; }
public InputView(ViewData parameters, LangManager lang) : base(parameters, lang)
{
int
sBC = parameters.AttribueAsInt("textfield_select_color", (int)ConsoleColor.Gray),
sTC = parameters.AttribueAsInt("text_select_color", (int)ConsoleColor.Black),
BC = parameters.AttribueAsInt("field_noselect_color", (int)ConsoleColor.DarkGray),
TC = parameters.AttribueAsInt("text_noselect_color", (int)ConsoleColor.Black);
DefaultBackgroundColor = (ConsoleColor)BC;
DefaultTextColor = (ConsoleColor)TC;
DefaultSelectBackgroundColor = (ConsoleColor)sBC;
DefaultSelectTextColor = (ConsoleColor)sTC;
List<InputField> fields = new List<InputField>();
foreach (var data in parameters.nestedData.GetFirst(d => d.Name.Equals("Fields")).nestedData)
if (!data.Name.Equals("Field")) continue;
else fields.Add(new InputField(data.InnerText, data.AttribueAsInt("max_length", -1))
{
ShowText = !data.AttribueAsBool("hide", false),
Text = data.GetAttribute("default"),
InputTypeString = data.GetAttribute("input_type"),
TextColor = (ConsoleColor)data.AttribueAsInt("color_text", TC),
BackgroundColor = (ConsoleColor)data.AttribueAsInt("color_background", BC),
SelectTextColor = (ConsoleColor)data.AttribueAsInt("color_text_select", sTC),
SelectBackgroundColor = (ConsoleColor)data.AttribueAsInt("color_background_select", sBC)
});
Inputs = fields.ToArray();
int computedSize = 0;
splitInputs = new string[Inputs.Length][];
for (int i = 0; i < Inputs.Length; ++i)
{
splitInputs[i] = ComputeTextDimensions(Inputs[i].Label.Split(' '));
computedSize += splitInputs[i].Length;
}
ContentHeight += computedSize + Inputs.Length * 2;
//++ContentWidth; // Idk, it works, though...
}
protected override void _Draw(int left, ref int top)
{
DrawEmptyPadding(left, ref top, padding.Top());
DrawContent(left, ref top);
DrawInputFields(left, ref top, 1);
DrawEmptyPadding(left, ref top, padding.Bottom());
}
protected void DrawInputFields(int left, ref int top, int spaceHeight)
{
int pl = padding.Left(), pr = padding.Right();
for (int j = 0; j < Inputs.Length; ++j)
{
DrawEmptyPadding(left, ref top, spaceHeight);
for (int i = 0; i < splitInputs[j].Length; ++i)
{
Console.SetCursorPosition(left, top++);
Console.BackgroundColor = BackgroundColor;
Console.Write(Filler(' ', pl) + splitInputs[j][i] + Filler(' ', MaxWidth - splitInputs[j][i].Length) + Filler(' ', pr));
}
Console.SetCursorPosition(left, top++);
// Draw padding
Console.BackgroundColor = BackgroundColor;
Console.Write(Filler(' ', pl));
// Draw field
Console.BackgroundColor = j == selectedField ? Inputs[j].SelectBackgroundColor : Inputs[j].BackgroundColor;
Console.ForegroundColor = j == selectedField ? Inputs[j].SelectTextColor : Inputs[j].TextColor;
Console.Write(Inputs[j].ShowText ? Inputs[j].Text.Substring(Inputs[j].RenderStart, Inputs[j].SelectIndex - Inputs[j].RenderStart) : Filler('*', Inputs[j].SelectIndex - Inputs[j].RenderStart));
if (j == selectedField) Console.BackgroundColor = ConsoleColor.DarkGray;
Console.Write(Inputs[j].SelectIndex < Inputs[j].Text.Length ? Inputs[j].ShowText ? Inputs[j].Text[Inputs[j].SelectIndex] : '*' : ' ');
if (j == selectedField) Console.BackgroundColor = Inputs[j].SelectBackgroundColor;
int drawn = 0;
if (Inputs[j].SelectIndex < Inputs[j].Text.Length)
Console.Write(
Inputs[j].ShowText ?
Inputs[j].Text.Substring(Inputs[j].SelectIndex + 1, drawn = Math.Min(maxWidth + Inputs[j].SelectIndex - Inputs[j].RenderStart - 1, Inputs[j].Text.Length - Inputs[j].SelectIndex - 1)) :
Filler('*', drawn = Math.Min(maxWidth + Inputs[j].SelectIndex - Inputs[j].RenderStart - 1, Inputs[j].Text.Length - Inputs[j].SelectIndex - 1))
);
Console.Write(Filler(' ', maxWidth - 1 - drawn - Inputs[j].SelectIndex + Inputs[j].RenderStart));
Console.ForegroundColor = ConsoleColor.Black;
// Draw padding
Console.BackgroundColor = BackgroundColor;
Console.Write(Filler(' ', pr));
}
}
public override bool HandleKeyEvent(ConsoleController.KeyEvent evt, bool inFocus)
{
bool changed = base.HandleKeyEvent(evt, inFocus);
ConsoleKeyInfo info = evt.Event;
if (!evt.ValidEvent || !inFocus || Inputs.Length == 0) return changed;
switch (info.Key)
{
case ConsoleKey.LeftArrow:
if (Inputs[selectedField].SelectIndex > 0)
{
if (Inputs[selectedField].RenderStart == Inputs[selectedField].SelectIndex--) --Inputs[selectedField].RenderStart;
}
else return changed;
break;
case ConsoleKey.RightArrow:
if (Inputs[selectedField].SelectIndex < Inputs[selectedField].Text.Length)
{
if (++Inputs[selectedField].SelectIndex - Inputs[selectedField].RenderStart == maxWidth) ++Inputs[selectedField].RenderStart;
}
else return changed;
break;
case ConsoleKey.Tab:
case ConsoleKey.DownArrow:
if (selectedField < Inputs.Length - 1) ++selectedField;
else return changed;
break;
case ConsoleKey.UpArrow:
if (selectedField > 0) --selectedField;
else return changed;
break;
case ConsoleKey.Backspace:
if (Inputs[selectedField].SelectIndex > 0)
{
if (InputListener?.Invoke(this, Inputs[selectedField], info) == false) break;
string text = Inputs[selectedField].Text;
Inputs[selectedField].Text = text.Substring(0, Inputs[selectedField].SelectIndex - 1);
if (Inputs[selectedField].SelectIndex < text.Length) Inputs[selectedField].Text += text.Substring(Inputs[selectedField].SelectIndex);
if (Inputs[selectedField].RenderStart == Inputs[selectedField].SelectIndex--) --Inputs[selectedField].RenderStart;
}
else return changed;
break;
case ConsoleKey.Delete:
if (Inputs[selectedField].SelectIndex < Inputs[selectedField].Text.Length)
{
if (InputListener?.Invoke(this, Inputs[selectedField], info) == false) break;
string text = Inputs[selectedField].Text;
Inputs[selectedField].Text = text.Substring(0, Inputs[selectedField].SelectIndex);
if (Inputs[selectedField].SelectIndex + 1 < text.Length) Inputs[selectedField].Text += text.Substring(Inputs[selectedField].SelectIndex + 1);
}
else return changed;
break;
case ConsoleKey.Enter:
SubmissionsListener?.Invoke(this);
return changed;
default:
if (info.KeyChar != 0 && info.KeyChar != '\b' && info.KeyChar != '\r' && (Inputs[selectedField].Text.Length < Inputs[selectedField].MaxLength || Inputs[selectedField].MaxLength < 0) && Inputs[selectedField].IsValidChar(info.KeyChar))
{
if (InputListener?.Invoke(this, Inputs[selectedField], info) == false) break;
Inputs[selectedField].Text = Inputs[selectedField].Text.Substring(0, Inputs[selectedField].SelectIndex) + info.KeyChar + Inputs[selectedField].Text.Substring(Inputs[selectedField].SelectIndex);
if (++Inputs[selectedField].SelectIndex - Inputs[selectedField].RenderStart == maxWidth) ++Inputs[selectedField].RenderStart;
}
else return changed;
break;
}
return true;
}
}
}