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