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());
|
||||
continue;
|
||||
}
|
||||
Some(Event::Input(e))
|
||||
} else {
|
||||
Some(Event::Input(e))
|
||||
}
|
||||
Some(Event::Input(key.into()))
|
||||
}
|
||||
_ => Some(Event::Input(e)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
|
|
@ -1,6 +1,54 @@
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum Event<T> {
|
||||
Link(String),
|
||||
Input(termion::event::Event),
|
||||
Input(Key),
|
||||
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]
|
||||
version = "1.24.2"
|
||||
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,
|
||||
token::Token,
|
||||
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]
|
||||
async fn main() {
|
||||
kkdisp::run(App::default()).await.unwrap();
|
||||
kkdisp::run(AppView::default()).await.unwrap();
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
states: Vec<Plan>,
|
||||
index: usize,
|
||||
recv: Receiver<Token>,
|
||||
pub enum Page {
|
||||
Login(LoginPrompt),
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
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,
|
||||
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 Page {
|
||||
fn init(&self) -> Result<PlanLayers, anyhow::Error> {
|
||||
match self {
|
||||
Page::Login(log) => Ok(vec![log.into()]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl View for App {
|
||||
type Message = Token;
|
||||
pub struct AppView {
|
||||
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(
|
||||
&mut self,
|
||||
) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> {
|
||||
tokio::spawn(async { loop {} });
|
||||
Ok(vec![self.states[self.index].clone()])
|
||||
self.page.init()
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
event: Event<Self::Message>,
|
||||
) -> std::result::Result<Action, anyhow::Error> {
|
||||
match event {
|
||||
Event::Link(lnk) => {
|
||||
eprintln!("recieved link: {}", lnk);
|
||||
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),
|
||||
let page = &mut self.page;
|
||||
match page {
|
||||
Page::Login(login) => login.update(event),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue