diff options
-rw-r--r-- | v2/client.ts | 45 | ||||
-rw-r--r-- | v2/elements.ts | 51 | ||||
-rw-r--r-- | v2/screen.ts | 16 | ||||
-rw-r--r-- | v2/screen/home.ts | 21 | ||||
-rw-r--r-- | v2/screen/login.ts | 9 | ||||
-rw-r--r-- | v2/screenbuilder.ts | 19 |
6 files changed, 137 insertions, 24 deletions
diff --git a/v2/client.ts b/v2/client.ts index eedc578..0411425 100644 --- a/v2/client.ts +++ b/v2/client.ts @@ -1,7 +1,12 @@ import { Screen } from "./screen.ts"; +import type { Text } from "./elements.ts"; +import strftime from "./strftime.js"; export let token: string; export let account; +export const connection = new WebSocket("wss://api.meower.org/v0/cloudlink?v=1") + +export let home: any[] = []; let screen: Screen; @@ -10,6 +15,7 @@ export function setScreen(screenN: Screen) { } export async function login(username: string, password: string) { + screen.logs.push(`logging in as ${username}`) const authr = await (await fetch("https://api.meower.org/auth/login", { method: "post", headers: { @@ -20,12 +26,39 @@ export async function login(username: string, password: string) { password }) })).json(); - + screen.logs.push(`got auth response (${authr.error ? "error" : "not error"})`) token = authr.token; - account = authr.account + account = authr.account; + screen.logs.push(`Got token ${token}`); + connection.addEventListener("message", (ev) => { + const data = JSON.parse(ev.data.toString()); + screen.logs.push("INC: " + JSON.stringify(data)) + if(data.cmd != "post") return; + home.push(data.val) + const textHome: string[] = home.map(p => `[${strftime("%H:%M:%S")}] ${p.u}: ${p.p}`); + const homeElem: Text = screen.elements.get("home") as Text; + homeElem.text = textHome.join("\n")+"\n"; + screen.render() + }) } -export async function loadHome() { - const home = (await (await fetch("https://api.meower.org/home")).json()).autoget; - -} \ No newline at end of file +export async function loadHome(screen: Screen) { + home = (await (await fetch("https://api.meower.org/home")).json()).autoget.reverse(); + const textHome: string[] = home.map(p => `[${strftime("%H:%M:%S")}] ${p.u}: ${p.p}`); + const homeElem: Text = screen.elements.get("home") as Text; + homeElem.text = textHome.join("\n")+"\n"; + screen.render() +} + +export async function sendHome(post:string) { + fetch("https://api.meower.org/home", { + method: "POST", + headers: { + token, + "content-type": "application/json" + }, + body: JSON.stringify({ + content: post + }) + }).then(async r=>screen.logs.push(`Got send response (${r.status} ${r.statusText}) ${await r.text()}`)) +} diff --git a/v2/elements.ts b/v2/elements.ts index 56ef7da..8c3d58a 100644 --- a/v2/elements.ts +++ b/v2/elements.ts @@ -14,7 +14,8 @@ export abstract class Element { export class Text extends Element { text: string; - constructor(text: string) { + br: boolean; + constructor(text: string, br = false) { super(); this.text = text; } @@ -23,10 +24,33 @@ export class Text extends Element { } } +export class HR extends Element { + constructor() { + super() + } + render(): void { + console.log('-'.repeat(process.stdout.columns)) + } +} + +export class BR extends Element { + constructor() { + super() + } + render(): void { + console.log() + } +} + export class Input extends Element { focusable: boolean = true; value: string = ""; + height: number = 1; + heightOffser: number = 1; + grow: number = 1; + + textarea = false; br = false; isPassword: boolean = false; @@ -35,7 +59,7 @@ export class Input extends Element { let text = this.value if (this.isPassword) text = text.replace(/[^]/g, '*'); if (this.focused) text += "_" - console.log(text) + process.stdout.write(text) } onkeypres(key: Key): void { @@ -43,10 +67,14 @@ export class Input extends Element { if (key.meta || key.code || ["return", "backspace"].includes(key.name)) { switch (key.name) { case "return": + if(this.textarea) { + this.value += '\n' + break; + } this.focused = false; const focusableIDs = Object.keys(this.screen.getFocusable()); const focusedIndex = focusableIDs.indexOf(this.screen.focusedElementId); - this.screen.focus(focusableIDs[(focusedIndex - 1) % focusableIDs.length]); + this.screen.focus(focusableIDs[(focusedIndex + 1) % focusableIDs.length]); break; case "backspace": @@ -58,15 +86,24 @@ export class Input extends Element { this.screen.render() return; } - if (!key.sequence || key.sequence.length > 1 || key.name != key.sequence?.toLowerCase()) return; + // check if the character ism't typable + // checks: + // sequience length > 1 (eg ^[ ^[[A) + // key name != sequence (and if name exists) + //@ts-ignore + if (!key.sequence || key.sequence.length > 1 || key.name != key.sequence?.toLowerCase() && !["space"].includes(key.name) && key.name) return; this.value += key.sequence; this.screen.render() } - constructor(isPassword: boolean = false, br: boolean = false) { + constructor(isPassword: boolean = false, br: boolean = false, textarea: boolean = false, height: number = 1, heightOffset: boolean = false, grow: boolean = false) { super() this.br = br - this.isPassword = isPassword + this.isPassword = isPassword; + this.textarea = textarea; + this.height = height; + this.heightOffset = heightOffset; + this.grow = grow; } } @@ -78,7 +115,7 @@ export class Button extends Text { this.onclick = onclick } render(): void { - console.log(`(${(this.focused ? chalk.bgWhite : (a:string)=>a)(this.text)})`) + process.stdout.write(`(${(this.focused ? chalk.bgWhite : (a:string)=>a)(this.text)})`) } onkeypres(key: Key): void { diff --git a/v2/screen.ts b/v2/screen.ts index 2d90dde..4da6482 100644 --- a/v2/screen.ts +++ b/v2/screen.ts @@ -1,4 +1,4 @@ -import type { Element } from "./elements.ts" +import type { Element, Input, Text, Button } from "./elements.ts" import readline from 'node:readline'; readline.emitKeypressEvents(process.stdin); @@ -14,7 +14,7 @@ function onexit() { } export class Screen { - elements: Map<string, Element> = new Map<string, Element>(); + elements: Map<string, Element|Input|Text|Button> = new Map(); name: string; focusedElementId: string = ''; logs = logs @@ -23,6 +23,12 @@ export class Screen { this.name = name; } + call(function_name:string, ...args:any) { + for (const element of this.elements) { + element[1][function_name](...args) + } + } + handleKeypress(chunk: any, key: any, screen: Screen) { const focusableIDs = Object.keys(screen.getFocusable()); const focusedIndex = focusableIDs.indexOf(screen.focusedElementId); @@ -52,13 +58,15 @@ export class Screen { return (chunk: any, key: any) => this.handleKeypress(chunk,key, screen); } + keypressHandler = this.getKeypressHandler(this) + ready() { - process.stdin.on('keypress', this.getKeypressHandler(this)); + process.stdin.on('keypress', this.keypressHandler); this.render() } off() { - process.stdin.off('keypress', this.getKeypressHandler(this)) + process.stdin.off('keypress', this.keypressHandler) } addElement(name: string, element: Element) { diff --git a/v2/screen/home.ts b/v2/screen/home.ts index 6fb4f24..4c8a7cc 100644 --- a/v2/screen/home.ts +++ b/v2/screen/home.ts @@ -1,5 +1,6 @@ import { ElemType } from "../screenbuilder.ts"; import { Screen } from "../screen.ts"; +import type { Input } from "../elements.ts"; import * as client from "../client.ts" export default { @@ -7,21 +8,33 @@ export default { { type: ElemType.TextElem, id: 'home', - data: ["Username: \n"] + data: ["Loading home posts...\n"] + }, + { + type: ElemType.HR, + id: 'hr', + data: [] }, { type: ElemType.InputElem, id: 'msg-input', - data: [false, false] + data: [false, false, true] }, { type: ElemType.ButtonElem, id: 'done-btn', data: ["Send", async function (this: Screen) { - + const msgInput: Input = this.elements.get('msg-input') as Input + client.sendHome(msgInput.value); + msgInput.value = "" + this.render() }] } ], focus: "msg-input", - name: 'home' + name: 'home', + onload (screen: Screen) { + client.setScreen(screen) + client.loadHome(screen) + } } \ No newline at end of file diff --git a/v2/screen/login.ts b/v2/screen/login.ts index 525127b..bc39655 100644 --- a/v2/screen/login.ts +++ b/v2/screen/login.ts @@ -17,6 +17,10 @@ export default { data: [false] }, { + type: ElemType.BR, + id: 'naoiuou' + }, + { type: ElemType.TextElem, id: 'password-label', data: ["Password: \n"] @@ -27,9 +31,14 @@ export default { data: [true] }, { + type: ElemType.BR, + id: 'faij0ifsj' + }, + { type: ElemType.ButtonElem, id: 'done-btn', data: ["Done", async function (this: Screen) { + client.setScreen(this) this.off() this.logs.push(`clicked button`) console.clear() diff --git a/v2/screenbuilder.ts b/v2/screenbuilder.ts index dcf1af7..e8ce587 100644 --- a/v2/screenbuilder.ts +++ b/v2/screenbuilder.ts @@ -5,26 +5,39 @@ export enum ElemType { TextElem, InputElem, ButtonElem, + HR, + BR } const types = { 0: elements.Text, 1: elements.Input, - 2: elements.Button + 2: elements.Button, + 3: elements.HR, + 4: elements.BR } type BuilderElem = { type: ElemType, id: string, - data: any[] + data?: any[], } -export function build(data: {elements: BuilderElem[],focus?:string,name:string}) { +type Data = { + elements: BuilderElem[], + focus?: string, + name: string + onload?: (screen: Screen) => any +} + +export function build(data: Data) { const screen = new Screen(data.name); for (const element of data.elements) { + if (!element.data) element.data = [] //@ts-ignore screen.addElement(element.id, new types[element.type](...element.data)) } if (data.focus) screen.focus(data.focus); screen.ready() + if (data.onload) data.onload(screen) } \ No newline at end of file |