...
This commit is contained in:
parent
3cdf7c62d5
commit
71ac8d97fa
12 changed files with 445 additions and 445 deletions
|
|
@ -5,6 +5,9 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
iota-state = { path = "../iota-state" }
|
||||
iota-core = { path = "../iota-terms" }
|
||||
|
||||
|
||||
ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" }
|
||||
ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" }
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ pub mod screens {
|
|||
}
|
||||
pub mod util {
|
||||
pub mod borders;
|
||||
pub mod buttons;
|
||||
pub mod terms_focus;
|
||||
}
|
||||
pub mod app_state;
|
||||
pub mod input_handler;
|
||||
|
|
|
|||
175
iota-cli/src/util/buttons.rs
Normal file
175
iota-cli/src/util/buttons.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
use ratatui::{
|
||||
layout::{Alignment, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Line, Span},
|
||||
widgets::{Block, Borders, Paragraph},
|
||||
};
|
||||
|
||||
use crate::util::terms_focus::Focus;
|
||||
|
||||
#[allow(mismatched_lifetime_syntaxes)]
|
||||
pub fn checkbox(label: &str, checked: bool, active: bool, allowed: bool) -> Line {
|
||||
let box_char = if checked { "[x]" } else { "[ ]" };
|
||||
let (box_style, text_style) = if active {
|
||||
if allowed {
|
||||
(
|
||||
Style::default()
|
||||
.fg(Color::Yellow)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
Style::default()
|
||||
.fg(Color::Yellow)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Style::default().fg(Color::Gray),
|
||||
Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(Style::default(), Style::default())
|
||||
};
|
||||
Line::from(vec![
|
||||
Span::styled(box_char, box_style),
|
||||
Span::raw(" "),
|
||||
Span::styled(label, text_style),
|
||||
])
|
||||
}
|
||||
|
||||
pub fn draw_button(f: &mut ratatui::Frame, area: Rect, label: &str, style: Style) {
|
||||
let p = Paragraph::new(Span::styled(label, style))
|
||||
.alignment(Alignment::Center)
|
||||
.block(Block::default().borders(Borders::ALL));
|
||||
f.render_widget(p, area);
|
||||
}
|
||||
pub fn draw_buttons(
|
||||
f: &mut ratatui::Frame,
|
||||
area: Rect,
|
||||
current_focus: Focus,
|
||||
state: (bool, bool),
|
||||
update_needed: bool,
|
||||
downgrade_scenario: bool,
|
||||
tos_or_privacy: bool,
|
||||
) {
|
||||
let cancel_text = if update_needed {
|
||||
"[Q] Quit"
|
||||
} else {
|
||||
"[Q] Not now"
|
||||
};
|
||||
let continue_text = if downgrade_scenario {
|
||||
"Downgrade"
|
||||
} else {
|
||||
"Continue"
|
||||
};
|
||||
let mut buttons = vec![
|
||||
(cancel_text, Focus::Cancel),
|
||||
(continue_text, Focus::Continue),
|
||||
];
|
||||
if tos_or_privacy {
|
||||
buttons.push(("Continue with Tensamin Services", Focus::ContinueAll));
|
||||
}
|
||||
|
||||
let padding = 2;
|
||||
let min_widths: Vec<u16> = buttons
|
||||
.iter()
|
||||
.map(|(label, _)| label.len() as u16 + padding)
|
||||
.collect();
|
||||
|
||||
let widths = compute_widths(area.width, &min_widths);
|
||||
|
||||
let mut x = area.x;
|
||||
|
||||
for ((label, focus), width) in buttons.iter().zip(widths) {
|
||||
let chunk = Rect {
|
||||
x,
|
||||
y: area.y,
|
||||
width,
|
||||
height: area.height,
|
||||
};
|
||||
x += width;
|
||||
|
||||
let is_focused = current_focus == *focus;
|
||||
|
||||
let style = match focus {
|
||||
Focus::Cancel => {
|
||||
if is_focused {
|
||||
Style::default()
|
||||
.fg(Color::Black)
|
||||
.bg(Color::Red)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else {
|
||||
Style::default().fg(Color::Red)
|
||||
}
|
||||
}
|
||||
|
||||
Focus::Continue => {
|
||||
if is_focused && state.0 {
|
||||
Style::default()
|
||||
.fg(Color::Black)
|
||||
.bg(Color::Green)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else if state.0 {
|
||||
Style::default().fg(Color::Green)
|
||||
} else {
|
||||
Style::default().fg(Color::DarkGray)
|
||||
}
|
||||
}
|
||||
|
||||
Focus::ContinueAll => {
|
||||
if is_focused && state.1 {
|
||||
Style::default()
|
||||
.fg(Color::Black)
|
||||
.bg(Color::Green)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else if state.1 {
|
||||
Style::default().fg(Color::Green)
|
||||
} else {
|
||||
Style::default().fg(Color::DarkGray)
|
||||
}
|
||||
}
|
||||
|
||||
_ => Style::default().fg(Color::DarkGray),
|
||||
};
|
||||
|
||||
draw_button(f, chunk, label, style);
|
||||
}
|
||||
}
|
||||
pub fn compute_widths(area_width: u16, min_widths: &[u16]) -> Vec<u16> {
|
||||
let mut widths = vec![0; min_widths.len()];
|
||||
let mut remaining: Vec<usize> = (0..min_widths.len()).collect();
|
||||
|
||||
let mut remaining_width = area_width;
|
||||
|
||||
while !remaining.is_empty() {
|
||||
let count = remaining.len() as u16;
|
||||
let equal = remaining_width / count;
|
||||
|
||||
let mut clamped = Vec::new();
|
||||
|
||||
for &i in &remaining {
|
||||
if min_widths[i] > equal {
|
||||
widths[i] = min_widths[i];
|
||||
remaining_width -= min_widths[i];
|
||||
clamped.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
if clamped.is_empty() {
|
||||
let mut remainder = remaining_width % count;
|
||||
for &i in &remaining {
|
||||
widths[i] = equal
|
||||
+ if remainder > 0 {
|
||||
remainder -= 1;
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
remaining.retain(|i| !clamped.contains(i));
|
||||
}
|
||||
|
||||
widths
|
||||
}
|
||||
25
iota-cli/src/util/terms_focus.rs
Normal file
25
iota-cli/src/util/terms_focus.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Focus {
|
||||
Eula,
|
||||
Tos,
|
||||
Pp,
|
||||
Cancel,
|
||||
Continue,
|
||||
ContinueAll,
|
||||
}
|
||||
|
||||
impl Focus {
|
||||
pub fn next(&mut self, order: &[Focus]) {
|
||||
if let Some(pos) = order.iter().position(|&f| f == *self) {
|
||||
let next_pos = (pos + 1) % order.len();
|
||||
*self = order[next_pos];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev(&mut self, order: &[Focus]) {
|
||||
if let Some(pos) = order.iter().position(|&f| f == *self) {
|
||||
let prev_pos = if pos == 0 { order.len() - 1 } else { pos - 1 };
|
||||
*self = order[prev_pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue