some login prototyping
This commit is contained in:
parent
70168f9ed2
commit
f8854de25c
File diff suppressed because it is too large
Load Diff
|
@ -264,12 +264,10 @@ where
|
||||||
last_ctrlc = Some(Instant::now());
|
last_ctrlc = Some(Instant::now());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Some(Event::Input(e))
|
|
||||||
} else {
|
|
||||||
Some(Event::Input(e))
|
|
||||||
}
|
}
|
||||||
|
Some(Event::Input(key.into()))
|
||||||
}
|
}
|
||||||
_ => Some(Event::Input(e)),
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -1,6 +1,54 @@
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Event<T> {
|
pub enum Event<T> {
|
||||||
Link(String),
|
Link(String),
|
||||||
Input(termion::event::Event),
|
Input(Key),
|
||||||
Message(T),
|
Message(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<termion::event::Key> for Key {
|
||||||
|
fn from(value: termion::event::Key) -> Self {
|
||||||
|
match value {
|
||||||
|
termion::event::Key::Backspace => Self::Backspace,
|
||||||
|
termion::event::Key::Left => Self::Left,
|
||||||
|
termion::event::Key::Right => Self::Right,
|
||||||
|
termion::event::Key::Up => Self::Up,
|
||||||
|
termion::event::Key::Down => Self::Down,
|
||||||
|
termion::event::Key::Home => Self::Home,
|
||||||
|
termion::event::Key::End => Self::End,
|
||||||
|
termion::event::Key::PageUp => Self::PgUp,
|
||||||
|
termion::event::Key::PageDown => Self::PgDown,
|
||||||
|
termion::event::Key::BackTab => Self::Backtab,
|
||||||
|
termion::event::Key::Delete => Self::Delete,
|
||||||
|
termion::event::Key::Insert => Self::Insert,
|
||||||
|
termion::event::Key::F(f) => Self::F(f),
|
||||||
|
termion::event::Key::Char(c) => Self::Char(c),
|
||||||
|
termion::event::Key::Alt(c) => Self::Alt(c),
|
||||||
|
termion::event::Key::Ctrl(c) => Self::Ctrl(c),
|
||||||
|
termion::event::Key::Null => Self::Null,
|
||||||
|
termion::event::Key::Esc => Self::Esc,
|
||||||
|
_ => Self::Null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Key {
|
||||||
|
Backspace,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Home,
|
||||||
|
End,
|
||||||
|
PgUp,
|
||||||
|
PgDown,
|
||||||
|
Backtab,
|
||||||
|
Delete,
|
||||||
|
Insert,
|
||||||
|
F(u8),
|
||||||
|
Char(char),
|
||||||
|
Alt(char),
|
||||||
|
Ctrl(char),
|
||||||
|
Null,
|
||||||
|
Esc,
|
||||||
|
}
|
||||||
|
|
|
@ -12,3 +12,7 @@ kkdisp = { version = "0.1.0", path = "../kkdisp" }
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
version = "1.24.2"
|
version = "1.24.2"
|
||||||
features = ["full"]
|
features = ["full"]
|
||||||
|
|
||||||
|
[dependencies.misskey]
|
||||||
|
version = "*"
|
||||||
|
features = ["websocket-client"]
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
use kkdisp::{
|
||||||
|
component::{Plan, Widget},
|
||||||
|
theme::Color,
|
||||||
|
token::Token,
|
||||||
|
view::{Event, Key},
|
||||||
|
Action,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::Message;
|
||||||
|
pub enum LoginFocus {
|
||||||
|
Hostname,
|
||||||
|
Token,
|
||||||
|
OK,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginFocus {
|
||||||
|
fn ok(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
LoginFocus::OK => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoginPrompt {
|
||||||
|
hostname: String,
|
||||||
|
token: String,
|
||||||
|
error: Option<String>,
|
||||||
|
focus: LoginFocus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&LoginPrompt> for Plan {
|
||||||
|
fn from(value: &LoginPrompt) -> Self {
|
||||||
|
Plan::start()
|
||||||
|
.fill(vec![])
|
||||||
|
.fixed(8, vec![Widget::new(100, value.tokens())])
|
||||||
|
.fill(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoginPrompt {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
hostname: String::new(),
|
||||||
|
token: String::new(),
|
||||||
|
error: None,
|
||||||
|
focus: LoginFocus::Hostname,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backspace(&mut self) {
|
||||||
|
match self.focus {
|
||||||
|
LoginFocus::Hostname => {
|
||||||
|
self.hostname.pop();
|
||||||
|
}
|
||||||
|
LoginFocus::Token => {
|
||||||
|
self.token.pop();
|
||||||
|
}
|
||||||
|
LoginFocus::OK => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attempt(&self) -> Result<(), anyhow::Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
event: Event<Message>,
|
||||||
|
) -> Result<Action, anyhow::Error> {
|
||||||
|
match event {
|
||||||
|
Event::Link(lnk) => {
|
||||||
|
if lnk == "ok" {
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
Ok(Action::Nothing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Input(input) => {
|
||||||
|
match input {
|
||||||
|
Key::Backspace => self.backspace(),
|
||||||
|
Key::Up => {
|
||||||
|
self.focus = match self.focus {
|
||||||
|
LoginFocus::Hostname => LoginFocus::OK,
|
||||||
|
LoginFocus::Token => LoginFocus::Hostname,
|
||||||
|
LoginFocus::OK => LoginFocus::Token,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Key::Down => {
|
||||||
|
self.focus = match self.focus {
|
||||||
|
LoginFocus::Hostname => LoginFocus::Token,
|
||||||
|
LoginFocus::Token => LoginFocus::OK,
|
||||||
|
LoginFocus::OK => LoginFocus::Hostname,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Key::Char(c) => {
|
||||||
|
if c == '\n' {
|
||||||
|
if self.focus.ok() {
|
||||||
|
self.attempt()?;
|
||||||
|
}
|
||||||
|
} else if c == '\t' {
|
||||||
|
} else {
|
||||||
|
match self.focus {
|
||||||
|
LoginFocus::Hostname => {
|
||||||
|
self.hostname.push(c)
|
||||||
|
}
|
||||||
|
LoginFocus::Token => {
|
||||||
|
self.token.push(c)
|
||||||
|
}
|
||||||
|
LoginFocus::OK => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Key::Ctrl(c) => {
|
||||||
|
if c == 'u' || c == 'U' {
|
||||||
|
match self.focus {
|
||||||
|
LoginFocus::Hostname => {
|
||||||
|
self.hostname = String::new();
|
||||||
|
}
|
||||||
|
LoginFocus::Token => {
|
||||||
|
self.token = String::new()
|
||||||
|
}
|
||||||
|
LoginFocus::OK => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Key::Esc => {
|
||||||
|
self.focus = LoginFocus::OK;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Ok(Action::Nothing);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Action::ReplaceAll(vec![(&*self).into()]))
|
||||||
|
}
|
||||||
|
Event::Message(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tokens(&self) -> Vec<Token> {
|
||||||
|
let mut hostname =
|
||||||
|
Token::text(self.hostname.clone()).padded(10);
|
||||||
|
let mut token = Token::text(self.token.clone()).padded(10);
|
||||||
|
let mut ok = Token::text("[ok]");
|
||||||
|
match self.focus {
|
||||||
|
LoginFocus::Hostname => {
|
||||||
|
hostname = hostname.bg(Color::BLUE)
|
||||||
|
}
|
||||||
|
LoginFocus::Token => token = token.bg(Color::BLUE),
|
||||||
|
LoginFocus::OK => ok = ok.bg(Color::BLUE),
|
||||||
|
};
|
||||||
|
vec![
|
||||||
|
Token::text("kkx cfg")
|
||||||
|
.bg(Color::BLUE)
|
||||||
|
.fg(Color::WHITE)
|
||||||
|
.centered(),
|
||||||
|
Token::End,
|
||||||
|
match &self.error {
|
||||||
|
Some(e) => Token::text(e).fg(Color::RED),
|
||||||
|
None => Token::End,
|
||||||
|
},
|
||||||
|
hostname.string("hostname: ").centered(),
|
||||||
|
token.string("token: ").centered(),
|
||||||
|
ok.link("ok").centered(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
109
kkx/src/main.rs
109
kkx/src/main.rs
|
@ -5,98 +5,69 @@ use kkdisp::{
|
||||||
theme::Color,
|
theme::Color,
|
||||||
token::Token,
|
token::Token,
|
||||||
view::Event,
|
view::Event,
|
||||||
Action, View,
|
Action, PlanLayers, View,
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc::{self, Receiver};
|
use login::LoginPrompt;
|
||||||
|
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||||
|
mod login;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
kkdisp::run(App::default()).await.unwrap();
|
kkdisp::run(AppView::default()).await.unwrap();
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub enum Page {
|
||||||
states: Vec<Plan>,
|
Login(LoginPrompt),
|
||||||
index: usize,
|
|
||||||
recv: Receiver<Token>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for App {
|
impl Page {
|
||||||
fn default() -> Self {
|
fn init(&self) -> Result<PlanLayers, anyhow::Error> {
|
||||||
let (snd, recv) = mpsc::channel(256);
|
match self {
|
||||||
tokio::spawn(async move {
|
Page::Login(log) => Ok(vec![log.into()]),
|
||||||
std::thread::sleep(Duration::from_secs(10));
|
|
||||||
snd.send(Token::text("this is an event").centered())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
});
|
|
||||||
Self {
|
|
||||||
recv,
|
|
||||||
index: 0,
|
|
||||||
states: vec![
|
|
||||||
Plan::start().fill(vec![]).fixed(
|
|
||||||
4,
|
|
||||||
vec![Widget::new(
|
|
||||||
100,
|
|
||||||
vec![
|
|
||||||
Token::End,
|
|
||||||
Token::text("click me")
|
|
||||||
.bg(Color::BLUE)
|
|
||||||
.link("click"),
|
|
||||||
],
|
|
||||||
)],
|
|
||||||
),
|
|
||||||
Plan::start()
|
|
||||||
.fixed(4, vec![])
|
|
||||||
.fill(vec![Widget::scrolling(
|
|
||||||
100,
|
|
||||||
(1..=100)
|
|
||||||
.into_iter()
|
|
||||||
.map(|num| {
|
|
||||||
Token::text(format!(
|
|
||||||
"this is {}",
|
|
||||||
num
|
|
||||||
))
|
|
||||||
.padded(30)
|
|
||||||
.bg("#330033".try_into().unwrap())
|
|
||||||
.link(format!("num{}", num))
|
|
||||||
.centered()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)])
|
|
||||||
.fixed(4, vec![]),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for App {
|
pub struct AppView {
|
||||||
type Message = Token;
|
recv: Receiver<Message>,
|
||||||
|
page: Page,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AppView {
|
||||||
|
fn default() -> Self {
|
||||||
|
let (snd, recv) = mpsc::channel(256);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
// std::thread::sleep(Duration::from_secs(10));
|
||||||
|
// snd.send(Token::text("this is an event").centered())
|
||||||
|
// .await
|
||||||
|
// .unwrap();
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
recv,
|
||||||
|
page: Page::Login(LoginPrompt::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Message {}
|
||||||
|
|
||||||
|
impl View for AppView {
|
||||||
|
type Message = Message;
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> {
|
) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> {
|
||||||
tokio::spawn(async { loop {} });
|
self.page.init()
|
||||||
Ok(vec![self.states[self.index].clone()])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: Event<Self::Message>,
|
event: Event<Self::Message>,
|
||||||
) -> std::result::Result<Action, anyhow::Error> {
|
) -> std::result::Result<Action, anyhow::Error> {
|
||||||
match event {
|
let page = &mut self.page;
|
||||||
Event::Link(lnk) => {
|
match page {
|
||||||
eprintln!("recieved link: {}", lnk);
|
Page::Login(login) => login.update(event),
|
||||||
self.index ^= 1;
|
|
||||||
Ok(Action::ReplaceAll(vec![
|
|
||||||
self.states[self.index].clone()
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
Event::Message(tok) => {
|
|
||||||
Ok(Action::ReplaceAll(vec![Plan::start()
|
|
||||||
.fixed(3, vec![Widget::new(100, vec![tok])])]))
|
|
||||||
}
|
|
||||||
_ => Ok(Action::Nothing),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue