Most stuff should be complete.

This commit is contained in:
2026-06-24 17:44:17 +02:00
parent 76a04b7d3e
commit 212fa7ed44
4 changed files with 161 additions and 65 deletions
+125 -44
View File
@@ -14,25 +14,27 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use ratatui::widgets::Borders;
use ratatui::{Frame, Terminal, backend::TermionBackend, widgets::Paragraph};
use ratatui::{Frame, Terminal, backend::TermionBackend};
use ratatui::{
layout::{Constraint, Layout},
style::{Style, Stylize},
text::{Line},
widgets::{Block, List, ListState},
style::{Color, Style, Stylize},
text::Line,
widgets::{Block, Borders, List, ListState, Paragraph},
};
use ratatui_textarea::TextArea;
use std::io::{self, Read, stdout};
use std::process::ExitCode;
use std::thread;
use std::time::Duration;
use termion::event::{Event, Key};
use termion::event::{self, Event};
use termion::raw::IntoRawMode;
mod nyan_system;
use nyan_system::{ExecCommandError};
use nyan_system::ExecCommandError;
const BEE_CAT: &str = include_str!("bee_cat.txt");
@@ -71,17 +73,8 @@ enum NyanitState {
HandOff(String),
}
fn init_stage() -> Result<NyanitState, ExecCommandError> {
// mount sysfss
nyan_system::prepare_env()?;
// check if device is encrypted
if nyan_system::bzzpss_dev_encrypted(ROOT_DEV)? {
// if encrypted return EnterPassword so used get promted for pass
return Ok(NyanitState::EnterPassword);
}
// if unencrypted
/// Mounting bee-root and chiking if there any snapshots
fn mount_and_check_snaps() -> Result<NyanitState, ExecCommandError> {
// mount bee-root
nyan_system::mount_bee_root(TMP_ROOT, ROOT_DEV)?;
@@ -93,24 +86,40 @@ fn init_stage() -> Result<NyanitState, ExecCommandError> {
return Ok(NyanitState::WaitForF2(snaps_list));
}
// tell to finish boot
// else tell to finish boot
Ok(NyanitState::HandOff(TMP_ROOT.into()))
}
pub struct NyanitTUI {
fn init_stage() -> Result<NyanitState, ExecCommandError> {
// mount sysfss
nyan_system::prepare_env()?;
// check if device is encrypted
if nyan_system::bzzpss_dev_encrypted(ROOT_DEV)? {
// if encrypted return EnterPassword so used get promted for pass
return Ok(NyanitState::EnterPassword);
}
// if unencrypted
mount_and_check_snaps()
}
struct NyanitTUI<'a> {
exit: bool,
state: NyanitState,
list_state: ListState,
time_counter: u32,
textarea: Option<TextArea<'a>>,
}
impl NyanitTUI {
impl NyanitTUI<'_> {
pub fn new() -> io::Result<Self> {
Ok(Self {
exit: false,
state: NyanitState::Init,
list_state: ListState::default().with_selected(Some(0)),
time_counter: 0,
textarea: None,
})
}
@@ -127,19 +136,34 @@ impl NyanitTUI {
};
// if drive unencrypted and there is no root snapshots finish boot
if let NyanitState::HandOff(root_mnt) = &self.state {
if let Err(ex) = nyan_system::hand_off_control(root_mnt, SYS_INIT) {
self.state = NyanitState::Error(ex.to_string())
match &self.state {
// if drive unencrypted and there is no root snapshots finish boot
NyanitState::HandOff(root_mnt) => {
if let Err(ex) = nyan_system::hand_off_control(root_mnt, SYS_INIT) {
self.state = NyanitState::Error(ex.to_string())
}
}
// init password input
NyanitState::EnterPassword => {
let mut textarea: TextArea<'_> = TextArea::default();
textarea.set_cursor_line_style(Style::default());
textarea.set_mask_char('\u{1F41D}'); //U+2022 BULLET (•)
textarea.set_placeholder_text("Please enter your password");
textarea.set_style(Style::default().fg(Color::LightYellow));
textarea.set_block(Block::default().borders(Borders::ALL).title("Password"));
self.textarea = Some(textarea);
}
_ => (),
}
// Init terminal
// 1. Enable raw mode
let stdout = stdout().into_raw_mode()?;
// 2. Setup Terminal
let backend = TermionBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
// init tty input and start actually drawing things now!
// init tty async input and start actually drawing things now!
let mut tty_input_async = termion::async_stdin().bytes();
self.time_counter = 0;
@@ -207,37 +231,94 @@ impl NyanitTUI {
&mut self.list_state,
);
}
NyanitState::EnterPassword => {
frame.render_widget(self.textarea.as_ref().unwrap(), vertical_chunks[1]);
}
NyanitState::HandOff(_) => {
let ok_text = Paragraph::new("Booting\nKira Linux\n \u{1F41D} \u{1F41D} :3")
.block(Block::bordered().light_green())
.light_green();
frame.render_widget(ok_text, vertical_chunks[1]);
// just some time to look at message
thread::sleep(Duration::from_millis(1000))
}
_ => (),
};
}
fn handle_events(&mut self, tty_input: &mut io::Bytes<termion::AsyncReader>) -> io::Result<()> {
// cheking if there is any input to read
if let Some(item) = tty_input.next() {
let read_byte = item?;
let e = termion::event::parse_event(read_byte, tty_input)?;
let e = event::parse_event(read_byte, tty_input)?;
match &self.state {
NyanitState::WaitForF2(vol_list) => {
if e == Event::Key(Key::F(2)) {
self.state = NyanitState::ChooseSnapshot(vol_list.clone());
}
},
NyanitState::ChooseSnapshot(vol_list) => {
match e {
Event::Key(Key::Down) => self.list_state.select_next(),
Event::Key(Key::Up) => self.list_state.select_previous(),
Event::Key(Key::Char('\n')) => if let Some(idx) = self.list_state.selected() {
self.state = NyanitState::HandOff(vol_list[idx].clone());
},
_ => (),
// finishing boot
NyanitState::HandOff(root_mnt) => {
if let Err(ex) = nyan_system::hand_off_control(root_mnt, SYS_INIT) {
self.state = NyanitState::Error(ex.to_string())
}
}
NyanitState::WaitForF2(vol_list) => {
if e == Event::Key(event::Key::F(2)) {
self.state = NyanitState::ChooseSnapshot(vol_list.clone());
}
}
NyanitState::ChooseSnapshot(vol_list) => match e {
Event::Key(event::Key::Down) => self.list_state.select_next(),
Event::Key(event::Key::Up) => self.list_state.select_previous(),
Event::Key(event::Key::Char('\n')) => {
if let Some(idx) = self.list_state.selected() {
self.state = NyanitState::HandOff(vol_list[idx].clone());
}
}
_ => (),
},
_ => ()
NyanitState::EnterPassword => {
match e {
// try to unlock if enter pressed
Event::Key(event::Key::Char('\n')) => {
let password = self.textarea.as_ref().unwrap().lines()[0].clone();
match nyan_system::bcachefs_unlock(password, ROOT_DEV) {
Ok(unlocked) => {
if unlocked {
// need to check for subvolumes and stuff
self.state = match mount_and_check_snaps() {
Ok(st) => st,
Err(ex) => NyanitState::Error(ex.to_string()),
}
}
// ask to enter password again
else {
self.textarea
.as_mut()
.unwrap()
.set_placeholder_text("Wrong password, try again");
self.textarea
.as_mut()
.unwrap()
.set_style(Style::default().fg(Color::LightRed));
self.textarea.as_mut().unwrap().clear();
}
}
Err(ex) => {
self.state = NyanitState::Error(ex.to_string());
}
}
}
_ => {
self.textarea
.as_mut()
.unwrap()
.set_style(Style::default().fg(Color::LightYellow));
self.textarea.as_mut().unwrap().input(e);
}
}
}
_ => (),
}
}
else {
} else {
// Tick time
thread::sleep(Duration::from_millis(500));
self.time_counter = self.time_counter.wrapping_add(1u32);