201 lines
6.2 KiB
Rust
201 lines
6.2 KiB
Rust
use futures::stream::TryStreamExt;
|
|
use kkdisp::{
|
|
component::{Plan, Widget},
|
|
theme::Color,
|
|
token::Token,
|
|
view::{Event, Key},
|
|
Action,
|
|
};
|
|
use misskey::{StreamingClientExt, WebSocketClient};
|
|
use tokio::sync::mpsc::{self, Receiver, Sender};
|
|
|
|
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,
|
|
client: Option<WebSocketClient>,
|
|
}
|
|
|
|
impl LoginPrompt {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
hostname: String::new(),
|
|
token: String::new(),
|
|
error: None,
|
|
focus: LoginFocus::Hostname,
|
|
client: None,
|
|
}
|
|
}
|
|
|
|
pub fn plan(&self) -> Plan {
|
|
Plan::start()
|
|
.fill(vec![])
|
|
.fixed(8, vec![Widget::new(100, self.tokens())])
|
|
.fill(vec![])
|
|
}
|
|
|
|
fn backspace(&mut self) {
|
|
match self.focus {
|
|
LoginFocus::Hostname => {
|
|
self.hostname.pop();
|
|
}
|
|
LoginFocus::Token => {
|
|
self.token.pop();
|
|
}
|
|
LoginFocus::OK => {}
|
|
}
|
|
}
|
|
pub fn query(&mut self) -> Option<()> {
|
|
todo!()
|
|
}
|
|
|
|
pub fn attempt(&mut self) {
|
|
let hostname = self.hostname.clone();
|
|
if hostname.len() == 0 {
|
|
self.error = Some("empty hostname".into());
|
|
self.focus = LoginFocus::Hostname;
|
|
return;
|
|
}
|
|
let token = self.token.clone();
|
|
if token.len() == 0 {
|
|
self.error = Some("empty token".into());
|
|
self.focus = LoginFocus::Token;
|
|
return;
|
|
}
|
|
todo!();
|
|
}
|
|
|
|
pub fn update(
|
|
&mut self,
|
|
event: Event<Message>,
|
|
) -> Result<Action, anyhow::Error> {
|
|
match event {
|
|
Event::Link(lnk) => {
|
|
if lnk == "ok" {
|
|
self.attempt();
|
|
Ok(Action::ReplaceAll(vec![self.plan()]))
|
|
} else if lnk == "token" {
|
|
self.focus = LoginFocus::Token;
|
|
Ok(Action::ReplaceAll(vec![self.plan()]))
|
|
} else if lnk == "hostname" {
|
|
self.focus = LoginFocus::Hostname;
|
|
Ok(Action::ReplaceAll(vec![self.plan()]))
|
|
} else {
|
|
Ok(Action::Nothing)
|
|
}
|
|
}
|
|
Event::Input(input) => {
|
|
match input {
|
|
Key::Return => match self.focus {
|
|
LoginFocus::Hostname => {
|
|
self.focus = LoginFocus::Token;
|
|
}
|
|
LoginFocus::Token => {
|
|
self.focus = LoginFocus::OK;
|
|
}
|
|
LoginFocus::OK => self.attempt(),
|
|
},
|
|
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) => 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.plan()]))
|
|
}
|
|
Event::Message(_) => todo!(),
|
|
}
|
|
}
|
|
|
|
fn tokens(&self) -> Vec<Token> {
|
|
const HOSTNAME_PROMPT: &str = "hostname: ";
|
|
const TOKEN_PROMPT: &str = "token: ";
|
|
let mut hostname = Token::text(self.hostname.clone());
|
|
let mut token = Token::text(self.token.clone());
|
|
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)
|
|
.pad_percent(80)
|
|
.centered(),
|
|
None => Token::End,
|
|
},
|
|
hostname
|
|
.string(HOSTNAME_PROMPT)
|
|
.link("hostname")
|
|
.pad_percent(80)
|
|
.centered(),
|
|
token
|
|
.string(TOKEN_PROMPT)
|
|
.link("token")
|
|
.pad_percent(80)
|
|
.centered(),
|
|
ok.link("ok").centered(),
|
|
]
|
|
}
|
|
}
|